jQuery自定义下拉框

一、自定义原因

1.项目定制化需求,下拉框的样式包括滚动条都需要同现有客户端(QT qml开发)版本保持一致;
2.据有web前端经验开发人员告知,select滚动条样式不可以改变。后来google了之后发现是可以的,采用jquery-nicescroll.js插件,但我并没有尝试,原因有以下两点;
3.嵌入Qt的界面,下拉框滚动条只能鼠标滚动,单击滚动条不能滚动;
4.嵌入Qt的界面,在mainwindow出现滚动条的时候,打开下拉框的选择面板的时候,下拉框选择面板会错位;

二、解决方案

简而言之:采用input ul li标签实现自定义
如下图:


示例图

2.1)遇到的问题

No. 问题 解决方案 示例
1 监听事件对于动态加载的元素没有起效,即使使用jquery的on监听也无效 监听静态元素,通过on或者off的第二个选择器参数,指定到具体监听的元素 $('body').off('blur' , '.select-box .input-box input.ipt-select')
2 同一元素多次添加监听事件,执行的时候,事件中的方法会执行多次 监听事件前,先解绑该事件 $('body').off('blur' , '.select-box .input-box input.ipt-select').on('blur', '.select-box .input-box input.ipt-select', function () { $(this).parent().siblings('ul').addClass('hide'); })
3 下拉箭头click没有响应下拉框展示隐藏事件 因为下拉箭头同input响应click的事件相同,因此将箭头的css鼠标事件透传 .select-box .input-box span{pointer-events: none;}

2.2)具体代码

2.2.1)css代码
/* css变量定义 */
:root{
    --g-Width-input: 229px; /*输入框、搜索框宽度*/
    --g-height-input: 22px; /*输入框、搜索框高度*/
    --g-color-bg-input_nor: #2d2e30; /*控件公用颜色--输入框、搜索框、背景--nor状态--背景色*/
    --g-color-bg-input_hov: #232426; 
    --g-color-border_dow: 1px solid #1690f5; /*控件公用颜色--边框--dow状态--颜色*/
    --g-radius-input: 2px; /*输入框、搜索框圆角半径*/
    --g-color-border_nor: 1px solid #424447;  /*控件公用颜色--边框--nor状态--颜色*/

    --g-color-border_dow: 1px solid #1690f5; 
    --g-color-bg_hov:#1690f5;/*控件公用颜色--控件背景--hor状态--底色*/
     --g-color-b-text:#b5b5b5; 
    --g-color-w-border_modal:#fff;   
}
input[type="number"],
input[type="text"],
input[type="password"],
textarea.form-control {
    font-size: 12px;
    background-color: var(--g-color-bg-input_nor);
    color: var(--g-color-b-text);
    width: var(--g-Width-input);
    height: var(--g-height-input);
    line-height: 28px;
    padding: 0px 6px;
    border: var(--g-color-border_nor);
    /* border-radius: 0px; */
    border-radius: var(--g-radius-input);
}
input[type="number"]:hover,
input[type="text"]:hover,
input[type="text"]:hover +.search-icon,
textarea.form-control:hover{
    background-color: var(--g-color-bg-input_hov);
}
input[type="number"]:focus,
input[type="text"]:focus{
    background-color: var(--g-color-bg-input_hov);
    border: var(--g-color-border_dow);
}
input:focus {
    outline: none;
}
input[type="number"][disabled],
input[type="text"][disabled],
.form-control[disabled],
input[type="text"].disabled {
    background-color: transparent;
    color: var(--g-color-b-text);
    border: var( --g-color-border_nor);
    cursor: default;
}
input:-webkit-autofill {
    -webkit-box-shadow: 0 0 0px 1000px var(--g-color-bg-input_nor) inset !important;
    -webkit-text-fill-color: var(--g-color-b-text);
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
    margin: 0;
}

/* select框自定义样式 */
.select-box {
    position: relative;
    width: var(--g-Width-input);
    display: inline-block;
}
.select-box .input-box{
    position: relative;
    width: 100%;
}
.select-box .input-box .icon-box{
    position: relative;
    right: 18px;
}
.select-box .input-box input.ipt-select{
    width: 100%;
}
.select-box .input-box input.ipt-select:focus{
    background-color: var(--g-color-bg-input_hov);
    border: var(--g-color-border_dow);
}
.select-box .input-box span{
    pointer-events: none;
}
.select-box .input-box .icon-box{
    position: absolute;
    right: 5px;
    top: 1px;
}
.select-box .input-box .icon-box i{
    font-size: 14px;
    font-weight: 1000;
    transform: scale(0.65);
    -webkit-transform: scale(0.75);
    display: inline-block;
}
.select-box ul.select{
    position: absolute;
    background-color: var(--g-color-bg-input_hov);
    border: var(--g-color-border_dow);
    height: auto;
    width: 100%;
    max-height: 274px;
    min-width: 152px;
    top: 22px;
    left: 0px;
    z-index: 99;
}
.select-box ul.select > li{
    font-size: 12px;
    height: 22px;
    line-height: 22px;
    padding: 0px 6px 1px;
    text-align: left;
}
.select-box ul.select > li.selected,
.select-box ul.select > li[selected]{
    background-color: var(--g-color-bg_hov);
    color: var(--g-color-w-border_modal);
}
.select-box ul.select > li:hover{
    background-color: var(--g-color-bg_hov);
    color: var(--g-color-w-border_modal);
}
 .vertical-auto.select::-webkit-scrollbar { /*select滚动条对应的宽度 */
    width: 5px;
}
2.2.2)html代码

  • 苹果
  • 香蕉
  • 橘子
  • 苹果
  • 香蕉
  • 橘子
2.2.2)js代码
/**
 * @description: 下拉框赋默认值,document ready的时候,需要调用该方法初始化
 * @param {*} dom $(document.documentElement)
 */
function initOptionSelect($dom){
    // 添加input框
    let selects = $dom.find('.select-box');
    for(let i = 0; i < selects.length; i++) {
        let $select = $(selects[i]);
        if($select.children('.input-box').length === 0) {
            // 添加不使能的input
            if($select.attr('disabled')) {
                $select.prepend(
                    `
` ); } else { // 添加使能的input $select.prepend( `
` ); } } else { // select已经有input了,不需要再添加 } } boundEventFun(); // 默认选中第一条记录 let uls = $dom.find('.select-box ul.select'); for(let i = 0; i < uls.length; i++) { selectLiChange($(uls[i]).find('li:first')); } } /** * @description: 绑定自定义下拉框事件 * 1)想要监听动态生成元素的事件,可以绑定静态元素,再在on或者off中添加需要监听元素的选择器即可 * 2)如果初始化多次走到boundEventFun事件,会导致该元素监听多次, * 即监听事件中的方法会走多次,防止这种事情发生,应该在绑定监听事件前,先解绑一下。 */ function boundEventFun(){ // input框失焦,需要隐藏下拉框 $('body').off('blur' , '.select-box .input-box input.ipt-select') .on('blur', '.select-box .input-box input.ipt-select', function () { $(this).parent().siblings('ul').addClass('hide'); }) // 下拉框中的input框点击的时候,需要控制下拉菜单的显隐 $('body').off('click', '.select-box .input-box input.ipt-select') .on('click', '.select-box .input-box input.ipt-select', function () { if ($(this).parent().siblings('ul').hasClass('hide')) { $(this).parent().siblings('ul').removeClass('hide'); } else { $(this).parent().siblings('ul').addClass('hide'); } }); // 触发change事件 $('body').off('change', '.select-box .input-box input.ipt-select') .on('change', '.select-box .input-box input.ipt-select', function () { $(this).parent().parent().trigger('change'); }); // 监听鼠标滑动在下拉菜单的事件,清除选中样式以及属性 $('body').off('mousemove', '.select-box ul.select') .on('mousemove', '.select-box ul.select', function () { $(this).children().removeClass('selected'); $(this).children().removeAttr('selected'); }); // 监听鼠标选中某个li的事件 $('body').off('mousedown', '.select-box ul.select > li') .on('mousedown', '.select-box ul.select > li', function () { selectLiChange($(this), true); }) } /** * @description: 下拉框赋指定值 * @param {*} dom 下拉框DOM元素 jquery对象 * @param {*} value 默认值 */ function setSelDefValue($dom, value) { if (value !== null && value !== '' && value !== undefined) { // 选中下拉框指定的一项 selectLiChange($dom.find(`li[value=${value}]`), true); } else { // 默认选中下拉框第一项 selectLiChange($dom.find("li:first")); } } /** * @description: li select状态发生变化,需要改变input值 * @param {*} $this li * needTriggerChange: 是否需要触发change信号 */ function selectLiChange($this, needTriggerChange = false) { // 下拉框赋值 let $select = $this.parent().parent('.select-box'); $select.attr('value', $this.attr('value')); $select.val($this.attr('value')); // 设置下拉框的selectedIndex let lis = $select.find('li'); let selectedIndex = 0; for(let i = 0; i < lis.length; i++) { let li = lis[i]; if($(li).attr('value') === $this.attr('value')) { selectedIndex = i; break; } } $select.prop('selectedIndex', selectedIndex); // option添加select类 $this.siblings().removeClass('selected'); $this.siblings().removeAttr('selected'); $this.addClass('selected'); $this.attr('selected', 'selected'); // input框赋值 let $input = $this.parent('.select').siblings('.input-box').find('input'); if($input.val() + '' !== $this.attr('value') + '') { if(needTriggerChange) { $select.trigger('change'); } } $input.val($this.text()); // 隐藏下拉框 $this.parent('.select').addClass("hide"); }

三、教训总结

1.因为此次项目中【一、自定义原因】中的问题,都是在完全开发完成之后才发现,无论如何想到共通化的修改,带来的改动量以及风险都是很大的。
2.因此,如果界面定制化极强的开发,下拉框慎重考虑,采用自定义的不要采用html自带标签select。就目前而言是这样,将来某天标签发生变化了另说。

你可能感兴趣的:(jQuery自定义下拉框)