浏览器自带的原生下拉框不太美观,而且各个浏览器表现也不一致,UI一般给的下拉框也是
浏览器自带的原生下拉框不太美观,而且各个浏览器表现也不一致,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实现一个自定义下拉单选选择框功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
js 单选 js自定义下拉选择框