jQuery自定義下拉框

一尤筐、自定義原因

1.項目定制化需求您朽,下拉框的樣式包括滾動條都需要同現(xiàn)有客戶端(QT qml開發(fā))版本保持一致黑界;
2.據(jù)有web前端經(jīng)驗開發(fā)人員告知劳澄,select滾動條樣式不可以改變稍走。后來google了之后發(fā)現(xiàn)是可以的袁翁,采用jquery-nicescroll.js插件,但我并沒有嘗試婿脸,原因有以下兩點粱胜;
3.嵌入Qt的界面,下拉框滾動條只能鼠標滾動狐树,單擊滾動條不能滾動焙压;
4.嵌入Qt的界面,在mainwindow出現(xiàn)滾動條的時候抑钟,打開下拉框的選擇面板的時候涯曲,下拉框選擇面板會錯位;

二味赃、解決方案

簡而言之:采用input ul li標簽實現(xiàn)自定義
如下圖:


示例圖

2.1)遇到的問題

No. 問題 解決方案 示例
1 監(jiān)聽事件對于動態(tài)加載的元素沒有起效掀抹,即使使用jquery的on監(jiān)聽也無效 監(jiān)聽靜態(tài)元素,通過on或者off的第二個選擇器參數(shù)心俗,指定到具體監(jiān)聽的元素 $('body').off('blur' , '.select-box .input-box input.ipt-select')
2 同一元素多次添加監(jiān)聽事件傲武,執(zhí)行的時候,事件中的方法會執(zhí)行多次 監(jiān)聽事件前城榛,先解綁該事件 $('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沒有響應(yīng)下拉框展示隱藏事件 因為下拉箭頭同input響應(yīng)click的事件相同揪利,因此將箭頭的css鼠標事件透傳 .select-box .input-box span{pointer-events: none;}

2.2)具體代碼

2.2.1)css代碼
/* css變量定義 */
:root{
    --g-Width-input: 229px; /*輸入框、搜索框?qū)挾?/
    --g-height-input: 22px; /*輸入框狠持、搜索框高度*/
    --g-color-bg-input_nor: #2d2e30; /*控件公用顏色--輸入框疟位、搜索框、背景--nor狀態(tài)--背景色*/
    --g-color-bg-input_hov: #232426; 
    --g-color-border_dow: 1px solid #1690f5; /*控件公用顏色--邊框--dow狀態(tài)--顏色*/
    --g-radius-input: 2px; /*輸入框喘垂、搜索框圓角半徑*/
    --g-color-border_nor: 1px solid #424447;  /*控件公用顏色--邊框--nor狀態(tài)--顏色*/

    --g-color-border_dow: 1px solid #1690f5; 
    --g-color-bg_hov:#1690f5;/*控件公用顏色--控件背景--hor狀態(tài)--底色*/
     --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滾動條對應(yīng)的寬度 */
    width: 5px;
}
2.2.2)html代碼
<!--使能的下拉框-->
<div class="select-box">
    <ul class="select hide vertical-auto">
        <li value="0">蘋果</li>
        <li value="1">香蕉</li>
        <li value="2">橘子</li>
        <li value="3">梨</li>
    </ul>
</div>
<!--不使能的下拉框-->
<div class="select-box" disabled>
    <ul class="select hide vertical-auto">
        <li value="0">蘋果</li>
        <li value="1">香蕉</li>
        <li value="2">橘子</li>
        <li value="3">梨</li>
    </ul>
</div>
2.2.2)js代碼
/**
 * @description: 下拉框賦默認值,document ready的時候甜刻,需要調(diào)用該方法初始化
 * @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(
                    `<div class="input-box">
                        <input type="text" class="ipt-select" readonly="readonly" disabled>
                        <span class="icon-box"><i class="icon iconfont icon-arrow-down"></i></span>
                    </div>`
                );
            } else {
                // 添加使能的input
                $select.prepend(
                    `<div class="input-box">
                        <input type="text" class="ipt-select" readonly="readonly">
                        <span class="icon-box"><i class="icon iconfont icon-arrow-down"></i></span>
                    </div>`
                );
            }
        } else {
            // select已經(jīng)有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)想要監(jiān)聽動態(tài)生成元素的事件正勒,可以綁定靜態(tài)元素得院,再在on或者off中添加需要監(jiān)聽元素的選擇器即可
 * 2)如果初始化多次走到boundEventFun事件,會導(dǎo)致該元素監(jiān)聽多次章贞,
 *    即監(jiān)聽事件中的方法會走多次祥绞,防止這種事情發(fā)生,應(yīng)該在綁定監(jiān)聽事件前,先解綁一下蜕径。
 */
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');
        }
    });
    
    // 觸發(fā)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');
    });
    
    // 監(jiān)聽鼠標滑動在下拉菜單的事件兜喻,清除選中樣式以及屬性
    $('body').off('mousemove', '.select-box ul.select')
             .on('mousemove', '.select-box ul.select', function () {
        $(this).children().removeClass('selected');
        $(this).children().removeAttr('selected');
    });
    
    // 監(jiān)聽鼠標選中某個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狀態(tài)發(fā)生變化梦染,需要改變input值
 * @param {*} $this li
 *            needTriggerChange: 是否需要觸發(fā)change信號
 */
function selectLiChange($this, needTriggerChange = false) {
    // 下拉框賦值
    let $select = $this.parent().parent('.select-box');
    $select.attr('value', $this.attr('value'));
    $select.val($this.attr('value'));
    // 設(shè)置下拉框的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");
}

三、教訓(xùn)總結(jié)

1.因為此次項目中【一虹统、自定義原因】中的問題弓坞,都是在完全開發(fā)完成之后才發(fā)現(xiàn),無論如何想到共通化的修改车荔,帶來的改動量以及風(fēng)險都是很大的。
2.因此戚扳,如果界面定制化極強的開發(fā)忧便,下拉框慎重考慮,采用自定義的不要采用html自帶標簽select帽借。就目前而言是這樣珠增,將來某天標簽發(fā)生變化了另說。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砍艾,一起剝皮案震驚了整個濱河市蒂教,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脆荷,老刑警劉巖凝垛,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜓谋,居然都是意外死亡梦皮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門桃焕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剑肯,“玉大人,你說我怎么就攤上這事观堂∪猛” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵师痕,是天一觀的道長溃睹。 經(jīng)常有香客問我,道長七兜,這世上最難降的妖魔是什么丸凭? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上惜犀,老公的妹妹穿的比我還像新娘铛碑。我一直安慰自己,他們只是感情好虽界,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布汽烦。 她就那樣靜靜地躺著,像睡著了一般莉御。 火紅的嫁衣襯著肌膚如雪撇吞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天礁叔,我揣著相機與錄音牍颈,去河邊找鬼。 笑死琅关,一個胖子當(dāng)著我的面吹牛煮岁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涣易,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼画机,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了新症?” 一聲冷哼從身側(cè)響起步氏,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎徒爹,沒想到半個月后荚醒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡瀑焦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年腌且,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榛瓮。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡铺董,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出禀晓,到底是詐尸還是另有隱情精续,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布粹懒,位于F島的核電站重付,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凫乖。R本人自食惡果不足惜确垫,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一弓颈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧删掀,春花似錦翔冀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至款票,卻和暖如春控硼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艾少。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工卡乾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姆钉。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓说订,卻偏偏與公主長得像,于是被迫代替她去往敵國和親潮瓶。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355