select 组件效果
这里不废话了直接上代码
HTML结构和select组件样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <style> *{ margin: 0; padding: 0; } .sel-plugin{ position: relative; display: inline-block; max-width: 280px; height: 42px; font-size: 14px; border: 1px solid rgb(221, 221, 221); vertical-align: middle; } .sel-plugin-focus{ border: solid 1px #3c95b7; } .sel-plugin__content{ height: 100%; padding-left: 10px; padding-right:35px; background: rgb(255, 255, 255); border-radius: 2px; font-family: MicrosoftYaHei; color: rgb(51, 51, 51); cursor: pointer; -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; user-select:none; overflow: hidden; text-overflow:ellipsis; white-space: nowrap; } .sel-plugin__arrow{ position: absolute; width: 20px; height: 20px; top:50%; right: 10px; transform: scale(0.8) translateY(-50%); cursor: pointer; } .sel-plugin__arrow::before{ content: ""; display: block; border-top:10px solid #2d0909; border-right:10px solid transparent; border-bottom:10px solid transparent; border-left:10px solid transparent; margin-top:2px; } .sel-plugin__items{ display: none; border: 1px solid #eee; position: absolute; width: 99%; max-height: 200px; overflow-y: auto; top: 102%; } .sel-plugin__items-show{ display: block; } .sel-plugin__ul{ list-style: none; } .sel-plugin__ul li{ height: 30px; line-height: 30px; padding-left: 10px; cursor: pointer; overflow: hidden; text-overflow:ellipsis; white-space: nowrap; } .sel-plugin__li-sel,.sel-plugin__ul li:hover{ background-color:#f5f7fa; } </style> <title>Document</title> </head> <body> 球队:<div class="js-sel-plugin"></div> <script type="module"> import SelPlugin from ‘./src/js/SelPlugin.js‘; // 使用 let sel = new SelPlugin({ el:".js-sel-plugin", // val:2, data:[//下拉框数据,默认数据,可覆盖 {val:1, txt:‘维拉人朴茨茅斯‘}, {val:2, txt:‘农夫农场主阿斯顿维拉‘}, {val:3, txt:‘军港西布罗姆维奇‘}, {val:4, txt:‘萝卜裤‘}, {val:5, txt:‘拖拉机手诺维‘}, {val:6, txt:‘蓝军桑德兰‘} ] }); </script> </body> </html>
javascript代码
class SelPlugin { constructor(option) { this.opt = Object.assign({ el: null,//挂载的元素,必须的,类型 string 选择器字符串 height: 30,//下拉框高度 onoff: false,//列表展示开关 focus_onoff: false,//下拉框是否获取焦点 val: 0,//设置默认选中的值,必须data包含的值 data: [//下拉框数据,默认数据,可覆盖 { val: 1, txt: ‘请选择‘ } ], changeCall: function (obj) {//数据当发生改变时回调 }, clickCall:function(obj){//点击选项卡回调 } }, option); this.init(); } //初始化 init() { if (!this.opt.el) throw ‘selPlugin el cannot be empty‘; if (!this.opt.data || this.opt.data.length == 0) { this.opt.data = [ { val: 1, txt: ‘请选择‘ } ]; } this.el = document.querySelector(this.opt.el); this.cur_val_txt = this.opt.val ? this.opt.data.find(item => item.val == this.opt.val) : this.opt.data[0]; if (!this.cur_val_txt) { this.cur_val_txt = this.opt.data[0]; } this.stop_ele = null;//下拉列表停留选项元素,默认为null this.render(); this.addEvent(); } //添加下拉框行为事件 addEvent() { let div_items = this.el.querySelector(".sel-plugin__items"); this.el.addEventListener("click", this.onOff.bind(this)); div_items.addEventListener("mousemove", this.mmove.bind(this)); div_items.addEventListener("mouseleave", this.mleave.bind(this)); document.addEventListener("click", this.watchDocClick.bind(this)); document.addEventListener(‘keydown‘, this.keydown.bind(this)); } //获取焦点时能通过键盘上下左右箭头进行选择下拉文本 keydown(e) { if (!this.opt.focus_onoff) return; let code = e.keyCode; let index = this.getIndex(); let length = this.opt.data.length - 1; switch (code) { case 37: if (index > 0) { this.updateVal(--index); } break; case 38: if (index > 0) { this.updateVal(--index); } break; case 39: if (index < length) { this.updateVal(++index); } break; case 40: if (index < length) { this.updateVal(++index); } break; case 13: this.selHide(); break; } } //通过下标更改值 updateVal(index) { this.cur_val_txt = this.opt.data[index]; let content = this.el.querySelector(‘.sel-plugin__content‘); content.innerHTML = this.cur_val_txt.txt; let lis = this.el.querySelectorAll("li"); [...lis].forEach((item, i) => { item.classList.remove("sel-plugin__li-sel") if (index == i) { item.classList.add(‘sel-plugin__li-sel‘); } }); this.opt.changeCall && this.opt.changeCall(this.cur_val_txt); } //移出下拉框行为事件 removeEvent() { let div_items = this.el.querySelector(".sel-plugin__items"); this.el.removeEventListener("click", this.onOff.bind(this)); div_items.removeEventListener("mousemove", this.mmove.bind(this)); div_items.removeEventListener("mouseleave", this.mleave.bind(this)); document.removeEventListener("click", this.watchDocClick.bind(this)); document.removeEventListener(‘keydown‘, this.keydown.bind(this)); } //监听document点击,如果当前点击的目标元素不是下拉框则然下拉框失去焦点 watchDocClick({ target }) { if (!this.isContain(target)) { this.selHide(); this.blur(); } } //获取下拉框焦点 focus() { this.opt.focus_onoff = true; this.el.classList.add("sel-plugin-focus"); } //下拉框失去焦点 blur() { this.opt.focus_onoff = false; this.el.classList.remove("sel-plugin-focus"); } //查找父辈或祖辈元素类名包含sel-plugin 如果有返回true isContain(tag) { while (tag && tag.classList.length && !tag.classList.contains("sel-plugin")) { tag = tag.parentNode; } return tag && tag.classList.length ? tag.classList.contains("sel-plugin") : false; } //下拉列表显示或隐藏 onOff(e) { this.opt.clickCall && this.opt.clickCall(); this.focus(); this.opt.onoff = !this.opt.onoff; let div_items = this.el.querySelector(".sel-plugin__items"); if (this.opt.onoff) { div_items.classList.add("sel-plugin__items-show"); } else { div_items.classList.remove("sel-plugin__items-show"); } if (e.target.tagName.toLowerCase() == "li") { let val = e.target.dataset.value; this.cur_val_txt = this.opt.data.find(item => item.val == val); this.el.querySelector(".sel-plugin__content").innerHTML = this.cur_val_txt.txt; this.opt.changeCall && this.opt.changeCall(this.cur_val_txt); } window.event ? window.event.cancelBubble = true : e.stopPropagation(); } //下拉隐藏 selHide() { let div_items = this.el.querySelector(".sel-plugin__items"); this.opt.onoff = false; div_items.classList.remove("sel-plugin__items-show"); } mmove({ target }) { let lis = this.el.querySelectorAll("li"); [...lis].forEach(item => item.classList.remove("sel-plugin__li-sel")); if (target.tagName.toLowerCase() == "li") { this.stop_ele = target; } } mleave(e) { this.stop_ele && this.stop_ele.classList.add("sel-plugin__li-sel") } //渲染下拉框 render() { let unit = "px"; this.el.classList.add(‘sel-plugin‘); this.el.style.width = this.opt.width + unit; this.el.style.height = this.opt.height + unit; this.opt.focus_onoff ? this.el.classList.add("sel-plugin-focus") : ‘‘; let div_content = document.createElement(‘div‘); div_content.className = ‘sel-plugin__content‘; div_content.innerHTML = this.cur_val_txt.txt; div_content.style.lineHeight = this.opt.height + unit; this.el.appendChild(div_content); let div_arrow = document.createElement(‘div‘); div_arrow.className = ‘sel-plugin__arrow‘; div_arrow.innerHTML = "<div></div>"; this.el.appendChild(div_arrow); let div_items = document.createElement(‘div‘); div_items.className = ‘sel-plugin__items‘; div_items.style.width = this.opt.width + unit; this.opt.onoff ? div_items.classList.add("sel-plugin__items-show") : ‘‘; this.el.appendChild(div_items); let ul = document.createElement(‘ul‘); ul.classList.add(‘sel-plugin__ul‘); div_items.appendChild(ul); let classstr = ""; let html = this.opt.data.map(item => { classstr = item.val == this.cur_val_txt.val ? "class=‘sel-plugin__li-sel‘" : ‘‘; return `<li ${classstr} data-value=‘${item.val}‘>${item.txt}</li>`; }).join(‘‘); ul.innerHTML = html; } //获取当前选项索引 getIndex() { let lis = this.el.querySelectorAll("li"); let index = 0; [...lis].forEach((item, i) => { if (item.classList.contains("sel-plugin__li-sel")) { index = i; } }); return index; } //获取值 getVal() { return this.cur_val_txt; } updateData(data, cur_item) { this.opt.data = data.length>0 ? data : [{ val: 1, txt: ‘请选择‘ }]; this.opt.cur_val_txt = cur_item ? cur_item : this.opt.data[0]; let div_content = this.el.querySelector(".sel-plugin__content"); let ul = this.el.querySelector(".sel-plugin__ul"); div_content.innerHTML = this.opt.cur_val_txt.txt; ul.innerHTML = ""; let classstr = ""; let html = this.opt.data.map(item => { classstr = item.val == this.cur_val_txt.val ? "class=‘sel-plugin__li-sel‘" : ‘‘; return `<li ${classstr} data-value=‘${item.val}‘>${item.txt}</li>`; }).join(‘‘); ul.innerHTML = html; } } export default SelPlugin;
代码复制到自己电脑,浏览页面必须安装本地服务器运行代码,否则或报错,因为我用的是es6 模块加载,必须是http协议的方式加载
原文地址:https://www.cnblogs.com/supermanGuo/p/11864858.html
时间: 2024-10-08 23:34:12