HTML下拉框样式美化

        在网页中,下拉框的样式最难美化,默认样式巨丑,好在现在已经有各种框架实现了下拉框的样式美化,主要思路都是通过JS代码将下拉框元素用更容易设置样式的div进行替换,再将对应选项及事件进行关联。

        最近一项目需要修改很久以前的页面,用户需求又需要美化下拉框样式,又不能引入第三方的框架,只好自己动手写了一个JS插件,实现下拉框的样式美化。

1、插件效果

        页面包含两个下拉框,一个3个选项,一个多个选项,一个选项内容较短,一个较长,页面代码如下:

    <form>
        <div class="div-form">
            <div class="div-form-row">
                <span class="form-title">selected: </span>
                <div class="form-input">
                    <select name="s1" onchange="selectChange('1','2')">
                        <option value="1">1111</option>
                        <option value="2" selected>2222</option>
                        <option value="3">3333</option>
                    </select>
                </div>
            </div>

            <div class="div-form-row">
                <span class="form-title">select time zone: </span>
                <div class="form-input">
                    <select name="s2">
                        <option value="1">(GMT-12:00) International Date Line West</option>
                        <option value="2">(GMT-11:00) Midway Island, Samoa</option>
                        <option value="3">(GMT-10:00) Hawaii</option>
                        <option value="4">(GMT-09:00) Alaska</option>
                        <option value="5">(GMT-08:00) Pacific Time, Tijuana</option>
                        <option value="6">(GMT-07:00) Arizona, Mazatlan</option>
                        <option value="7">(GMT-07:00-1) Chihuahua, La Paz</option>
                        <option value="8">(GMT-07:00-2) Mountain Time</option>
                        <option value="9">(GMT-06:00) Central America</option>
                        <option value="10">(GMT-06:00-1) Central Time</option>
                        <option value="11" selected>(GMT-06:00-2) Guadalajara, Mexico City, Monterrey</option>
                        <option value="12">(GMT-06:00-3) Saskatchewan</option>
                        <option value="13">(GMT-05:00) Bogota, Lima, Quito</option>
                        <option value="14">(GMT-05:00-1) Eastern Time</option>
                        <option value="15">(GMT-05:00-2) Indiana</option>
                        <option value="16">(GMT-04:00) Atlantic Time</option>
                        <option value="17">(GMT-04:00-1) Caracas, La Paz</option>
                        <option value="18">(GMT-04:00-2) Santiago</option>
                        <option value="19">(GMT-03:30) Newfoundland</option>
                    </select>
                </div>
            </div>
        </div>
    </form>

        未引入插件时,页面效果如下图所示:

        引入插件js和样式:

 <script src="select.js"></script>
 <link rel="stylesheet" href="select.css">

        引入插件后,页面效果如下图:

        主要变化是整个下拉框使用边框包裹,下拉框展开和收起状态右侧箭头方向改变,选项列表设置了最高高度,超过高度出现滚动条,选中的选项自定背景色展示。

2、实现步骤

        首先在页面加载事件处理方法中添加方法进行下拉框的渲染动作:

    win.addListener(win, 'load', function () {
        renderSelects();
    });

        再来看 renderSelects()方法:

    win.renderSelects = function (className) {
        var selectList;
        if (typeof className != "string" || className.trim().length == 0) {
            selectList = document.querySelectorAll('select');
        } else {
            selectList = document.getElementsByClassName(className);
        }
        for (var i = 0; i < selectList.length; i++) {
            renderOneSelect(selectList[i]);
        }
    }

        此方法主要将页面中的下拉框通过选择器选取出来,再循坏调用单个的渲染方法进行渲染。此方法可以传入下拉框的样式类名,传入后选择器匹配的下拉框才会进行自定义样式渲染,未传入参数时页面内全部的下拉框都会进行渲染。

        再看单个下拉框的渲染 renderOneSelect(el),这里的el是单个的下拉框元素。先添加一个临时的段落元素pTemp,然后用此段落元素,与下拉框进行替换,占住下拉框原来的位子,等待div构造的下拉框结构拼接好后再将pTemp替换掉:

 renderOneSelect(el){
     var pTemp = document.createElement("p");
     el.replaceWith(pTemp);
     
     var divSelect = document.createElement("div"); //div构造的下拉框结构
     // ... 一系列构造过程
     
     pTemp.replaceWith(divSelect); //用构造好的div替换掉 pTemp
 } 

        用div构造的下拉框实际的元素结构如下图所示:

        整个下拉框用div.div-select包裹,原有下拉框select元素放到div.div-select内,其后添加div.div-options,div.div-options内部包含了两个div,第一个div.div-selected,用于展示下拉框当前选中的选项,第二个用于展示所有的下拉框选项,单个选项用div.div-option展示,当前选中的选项添加 option-selected 样式,与其他选项区别展示。选项的内容使用span元素包裹展示,用于控制长度,超过长度出现省略号,添加title,当鼠标悬停时展示完整的选项内容。

        div元素构造好之后就是给各元素添加事件处理了。

        div.div-select添加click事件处理,点击时进行选项列表的展开和收起操作:

   selectClick = function (el) {
        if (el.hasClass("select-open")) {
            el.removeClass("select-open")
        } else {
            el.addClass("select-open");
        }
    }

        div.div-select添加blur事件处理,失去焦点时收起选项列表:

    selectBlur = function (el) {
        if (el.hasClass("select-open")) {
            el.removeClass("select-open")
        }
    }

        div.div-option添加click事件处理,点击时选中该选项,同步设置原有select选项的选中状态,设置原有select的selectIndex,调用原有select的onchange方法:

 optionClick = function (el) {
        var _value = el.get("value");
        var select = el.parentElement.parentElement.parentElement.children[0];
        var originIndex = select.selectedIndex;
        var optionLength = select.children.length;
        for (var i = 0; i < optionLength; i++) {
            if (select.children[i].get("value") == _value) {
                select.children[i].set("selected", "");
            } else {
                select.children[i].remove("selected");
            }
        }
        var selected = el.parentElement.parentElement.children[0];
        selected.innerHTML = el.innerHTML;
        var newIndex = 0;
        for (var i = 0; i < el.parentElement.children.length; i++) {
            var tempEl = el.parentElement.children[i];
            tempEl.removeClass("option-selected");
            if (tempEl.get("value") == _value && tempEl.innerHTML == el.innerHTML) {
                newIndex = i;
            }
        }
        el.addClass("option-selected");

        //设置下拉框 selectedIndex 并触发onchange事件
        if (originIndex != newIndex) {
            select.selectedIndex = newIndex;
            eval(select.get("onchange"));
        }

3、其他问题

        实际项目中,个别页面个别select的选中状态是通过js设置selectedIndex指定的,渲染代码不能通过option的selected参数获取选中状态,就不能正确的渲染选中状态,此时需要在下拉框完成渲染后,调用一个根据selectedIndex渲染选中状态的方法:

   HTMLElement.prototype.renderSelected = function () {
        var ele = this;
        if (this.nodeName == "SELECT") {
            var index = ele.selectedIndex;
            var divOptions = ele.parentElement.children[1];
            if (!!divOptions && divOptions.nodeName == "DIV" && divOptions.hasClass("div-options") && index >= 0) {
                divOptions.children[0].innerHTML = divOptions.children[1].children[index].innerHTML;
                divOptions.children[1].children[index].addClass("option-selected");
            }
        }
    };

        还有的页面,下拉框的选项列表是通过异步方法动态获取的,在页面onload方法中执行渲染时,选项列表还是空的,渲染完成后可能选项列表才获取到,这种情况就只能手动的在异步方法完成后调用渲染方法。

        代码下载:https://download.csdn.net/download/evanyanglibo/87490754

猜你喜欢

转载自blog.csdn.net/evanyanglibo/article/details/129194656