您的当前位置:首页正文

原生JS实现自定义下拉单选选择框功能

2020-11-27 来源:汇智旅游网

浏览器自带的原生下拉框不太美观,而且各个浏览器表现也不一致,UI一般给的下拉框也是和原生的下拉框差别比较大的,这就需要自己写一个基本功能的下拉菜单/下拉选择框了。最近,把项目中用到的下拉框组件重新封装了一下,以构造函数的方式进行封装,主要方法和事件定义在原型上,下面是主要的实现代码并添加了比较详细的注释,分享出来供大家参考。代码用了ES6部分写法如需兼容低版本浏览器请把相关代码转成es5写法,或者直接bable转下。

先放个预览图吧,后面有最终的动态效果图:(样式和交互参考了阿里和Iview UI库)

下面是主要的HTML代码(包含部分js调用代码):

<!DOCTYPE html>
<html>
<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">
 <title>Diy Select</title>
 <link rel="stylesheet" href="index.css" rel="external nofollow" >
</head>
<body>
 <div id="main" class="main"></div>

 <script src="index.js"></script>
 <script>
 document.addEventListener("DOMContentLoaded",function(){
 const select1 = new $Selector({
 eleSelector:"#main",
 options:[
 {name:"选项1",value:"0"},
 {name:"选项2",value:"1"},
 {name:"选项3",value:"2"}
 ],
 defaultText:"选项2"
 });
 })
 </script>
</body>
</html>

页面中定义了id为main的div,即为选择框所要添加到的元素。传入参数即可。

接着就是样式CSS部分了,没啥说的了,手动滑稽:

* {
 padding: 0;
 margin: 0;
 box-sizing: border-box;
}

.main {
 padding: 40px;
}

.my-select {
 display: inline-block;
 width: auto;
 min-width: 80px;
 box-sizing: border-box;
 vertical-align: middle;
 color: #515a6e;
 font-size: 14px;
 line-height: normal;
 position: relative;
}

.select-selection {
 display: block;
 box-sizing: border-box;
 outline: 0;
 -webkit-user-select: none;
 -moz-user-select: none;
 -ms-user-select: none;
 user-select: none;
 cursor: pointer;
 position: relative;
 background-color: #fff;
 border-radius: 4px;
 border: 1px solid #dcdee2;
 transition: all .2s ease-in-out;
}

.select-selection:hover,
.select-selection.select-focus {
 border-color: #57a3f3;
 box-shadow: 0 0 0 2px rgba(45, 140, 240, .2);
}

.select-selected-value {
 display: block;
 height: 28px;
 line-height: 28px;
 font-size: 12px;
 overflow: hidden;
 text-overflow: ellipsis;
 white-space: nowrap;
 padding-left: 8px;
 padding-right: 24px;
}

.icon-select-arrow {
 position: absolute;
 top: 50%;
 right: 8px;
 line-height: 1;
 margin-top: -7px;
 font-size: 14px;
 color: #808695;
 transition: all .2s ease-in-out;
 display: inline-block;
 font-style: normal;
 font-weight: 400;
 font-variant: normal;
 text-transform: none;
 text-rendering: auto;
 line-height: 1;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 vertical-align: middle;
}

.icon-select-arrow::before {
 content: "";
 display: block;
 width: 6px;
 height: 6px;
 background-color: transparent;
 border-left: 1.5px solid #808695;
 border-bottom: 1.5px solid #808695;
 transform: rotate(-45deg);
}

.select-dropdown {
 width: auto;
 min-width: 80px;
 max-height: 200px;
 overflow: auto;
 margin: 5px 0;
 padding: 5px 0;
 background-color: #fff;
 box-sizing: border-box;
 border-radius: 4px;
 box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
 position: absolute;
 z-index: 2;
 transform-origin: center top 0px;
 transition: all 0.3s;
 will-change: top, left;
 top: 30px;
 left: 0;
 transform: scale(1, 0);
 opacity: 0;
}

.select-item {
 line-height: normal;
 padding: 7px 16px;
 clear: both;
 color: #515a6e;
 font-size: 12px !important;
 white-space: nowrap;
 list-style: none;
 cursor: pointer;
 transition: background .2s ease-in-out;
}

.select-item.select-item-selected,
.select-item:hover {
 color: #2d8cf0;
 background-color: #f3f3f3;
}

样式部分就不做什么解释了,下面放入压轴的JS,同样也无需过多解释,注释写的很详细了,上代码:

/* jshint esversion: 6 */
(function (window, document) {
 let Selector = function (option) {
 //执行初始化方法,
 this._init(option);
 };

 Selector.prototype = {
 //初始化传入参数并定义初始化的相关变量
 _init({
 eleSelector = "", //传入的选择器 id,class,tag等,用于将选择框渲染到此选择器所在的元素
 options = [{
 name: "请选择",
 value: "0",
 }], //传入的下拉框对象,name为选择的文字,value为值
 defaultText = "请选择" //提供的默认选择的值
 }) {
 
 //将传入的数据绑定到this上
 this.parentEle = document.querySelector(eleSelector) || document.body; //要邦定的dom 
 this.options = options; //选择值数组对象
 this.defaultText = defaultText; //默认值

 this.dropboxShow = false; //定义存储下拉框的显示隐藏状态
 this.defaultValue = ""; //定义村赤默认选中的值
 this._creatElement(); //初始化后执行创建元素方法
 },

 //创建下拉选择框dom
 _creatElement() {
 //选择框最外层的包裹元素
 let wrapEle = document.createElement("div");
 wrapEle.className = "my-select";

 //根据传入的值获取选择框默认的值和内容
 this.options.forEach(item => {
 if (item.name === "this.defaultText") {
 this.defaultValue = item.value;
 }
 });

 let selectWarpBox = document.createElement("div"); //选择框包裹元素
 selectWarpBox.className = "select-selection";

 let inputHideBox = document.createElement("input"); //隐藏保存选择值得元素
 inputHideBox.type = "hidden";
 inputHideBox.value = this.defaultValue;

 let selectShowBox = document.createElement("div"); //选择框默认展示框
 let selectNameBox = document.createElement("span"); //选择框展现的值ele
 selectNameBox.className = "select-selected-value";
 selectNameBox.id = "select-option";
 selectNameBox.innerText = this.defaultText; //将传入的默认值赋值
 let selectIcon = document.createElement("i"); //图标ele
 selectIcon.className = "arrow-down icon-select-arrow";
 //将span和角标添加到外层div
 selectShowBox.appendChild(selectNameBox);
 selectShowBox.appendChild(selectIcon);

 selectWarpBox.appendChild(inputHideBox);
 selectWarpBox.appendChild(selectShowBox);

 //下拉框
 let dropbox = document.createElement("div"),
 ulbox = document.createElement("ul");

 dropbox.id = "select-drop";
 dropbox.className = "select-dropdown";
 ulbox.className = "select-dropdown-list";
 //遍历传入的选项数组对象,生成下拉菜单的li元素并赋值
 this.options.forEach((item) => {
 let itemLi = document.createElement("li");
 if (this.defaultText === item.name) {
 itemLi.className = "select-item select-item-selected";
 } else {
 itemLi.className = "select-item";
 }

 itemLi.setAttribute("data-value", item.value);
 itemLi.innerText = item.name;
 ulbox.appendChild(itemLi);

 });
 //将下拉框ul推入到包裹元素
 dropbox.appendChild(ulbox);

 wrapEle.appendChild(selectWarpBox);
 wrapEle.appendChild(dropbox);

 this.parentEle.appendChild(wrapEle); //将生成的下拉框添加到所选元素中

 //把需要操作的dom挂载到当前实例
 //this.wrapEle = wrapEle; //最外层包裹元素
 this.eleSelect = selectWarpBox; //选择框
 this.eleDrop = dropbox; //下拉框
 this.eleSpan = selectNameBox; //显示文字的span节点

 //绑定事件处理函数
 this._bind(this.parentEle);
 },

 //点击下拉框事件处理函数
 _selectHandleClick() {
 if (this.dropboxShow) {
 this._selectDropup();
 } else {
 this._selectDropdown();
 }
 },

 //收起下拉选项
 _selectDropup() {
 this.eleDrop.style.transform = "scale(1,0)";
 this.eleDrop.style.opacity = "0";
 this.eleSelect.className = "select-selection";
 this.dropboxShow = false;
 },

 //展示下拉选项
 _selectDropdown() {
 this.eleDrop.style.transform = "scale(1,1)";
 this.eleDrop.style.opacity = "1";
 this.eleSelect.className = "select-selection select-focus";
 this.dropboxShow = true;
 },

 //点击下拉选项进行赋值
 _dropItemClick(ele) {
 this.defaultValue = ele.getAttribute("data-value");
 //document.querySelector("#select-value").value = ele.getAttribute("data-value");
 this.eleSpan.innerText = ele.innerText;
 ele.className = "select-item select-item-selected";
 //对点击选中的其他所有兄弟元素修改class去除选中样式
 this._siblingsDo(ele, function (ele) {
 if (ele) {
 ele.className = "select-item";
 }
 });
 this._selectDropup();
 },

 //node遍历是否是子元素包裹元素
 _getTargetNode(ele, target) {
 //ele是内部元素,target是你想找到的包裹元素
 if (!ele || ele === document) return false;
 return ele === target ? true : this._getTargetNode(ele.parentNode, target);
 },

 //兄弟元素遍历处理函数
 _siblingsDo(ele, fn) {

 (function (ele) {
 fn(ele);
 if (ele && ele.previousSibling) {
 arguments.callee(ele.previousSibling);
 }
 })(ele.previousSibling);

 (function (ele) {
 fn(ele);
 if (ele && ele.nextSibling) {
 arguments.callee(ele.nextSibling);
 }
 })(ele.nextSibling);

 },

 //绑定下拉框事件处理函数
 _bind(parentEle) {
 let _this = this;
 //事件委托到最外层包裹元素进行绑定处理
 parentEle.addEventListener("click", function (e) {
 const ele = e.target;
 
 //遍历当前点击的元素,如果是选中框内的元素执行
 if (_this._getTargetNode(ele, _this.eleSelect)) {
 if (_this.dropboxShow) {
 _this._selectDropup();
 } else {
 _this._selectDropdown();
 }
 } else if (ele.className === "select-item") { //如果是点击的下拉框的选项执行
 _this._dropItemClick(ele);
 } else { //点击其他地方隐藏下拉框
 _this._selectDropup();
 }

 });

 }

 };
 //将构造函数挂载到全局window
 window.$Selector = Selector;
})(window, document);

到此,一个自定义下拉菜单就出炉了,下面是动态效果:

至此,从css自定义的表单元素到下拉框元素都已经自定义完毕,使用bootstrap的同学把这些加进去就能基本保持各浏览器效果一致性和美观性了,就到这吧先。

推荐:

感兴趣的朋友可以关注小编的微信公众号【码农那点事儿】,更多网页制作特效源码及学习干货哦!!!

总结

以上所述是小编给大家介绍的原生js实现一个自定义下拉单选选择框功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

显示全文