您现在的位置:首页 >> 前端 >> 内容

div模拟的下拉框

时间:2016/11/11 9:28:17 点击:

  核心提示:浏览中原生的下拉框太简陋,达不到设计效果是常有的事,所以做个模拟下拉框的模块是很有必要的。以后项目中可以拿来即用。网上是有很多各种功能的插件,但作为一个今后从事web前端工作的我来说,深入了解技术原理...

浏览中原生的下拉框太简陋,达不到设计效果是常有的事,所以做个模拟下拉框的模块是很有必要的。以后项目中可以拿来即用。

网上是有很多各种功能的插件,但作为一个今后从事web前端工作的我来说,深入了解技术原理是不变的战略问题。

网上有一篇《程序员为什么热衷造轮子》讲的是很有道理的。想要从小白上位到大神,没有捷径,少不了造轮搬砖。

我的轮子是7月份开始造的,而明天是双11了,一直再改进~先放个图

div模拟的下拉框

有如下接口(根据老板的要求,其实还有一个隐含的callback):代码即注释,有需要的兄弟自己理一下结构思路

1. hasText(str)、hasValue(str)
2. addItem(value, text)
3. selectByText(str)、selectByValue(str)
4. deleteByText(str)、deleteByValue(str)
5. getValue()、getText()
6. clearItems()

*依赖jQuery,仿jQuery源码写过一个库~只是不敢在项目中用~

一共一个html、jQuery.js、select.js、common.css、两张图片

html(这是今天之前的代码,今天修改了js,html里的input去掉了)如下:

<!DOCTYPE html>  
<html>  
<head>  
    <title>test</title>  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    <meta name="Author" content="阮家友">  
    <meta name="Keywords" content="HTML,model,test">  
    <meta name="Description" content="special effect">  
    <meta name="time" content="2016-11-4 11:07:25">  
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />  
    <link rel="stylesheet" href="css/common.css"/>  
    <script src="js/jquery.js"></script>  
    <script src="js/select.js"></script>  
    <style type="text/css">  
    #center { width: 80%; margin: 0 auto; }  
  
    </style>  
</head>  
<body>  
    <p id="center">  
        <p>基本</p>  
        <p class="select-box w120">  
            <p>请选择</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="">请选择</li>  
                <li data-id="1">请选择请选择请选择请选择请选择</li>  
                <li data-id="2">北京</li>  
                <li data-id="3">北京</li>  
                <li data-id="4">北京</li>  
                <li data-id="5">北京</li>  
                <li data-id="6">北京</li>  
                <li data-id="7">北京</li>  
                <li data-id="8">北京</li>  
                <li data-id="9">北京</li>  
                <li data-id="10">北京</li>  
                <li data-id="11">北京</li>  
                <li data-id="12">北京</li>  
                <li data-id="13">北京</li>  
                <li data-id="14">北京</li>  
                <li data-id="15">北京</li>  
                <li data-id="16">北京</li>  
                <li data-id="17">北京</li>  
            </ul>  
        </p>  
        <p>无input无id</p>  
        <p class="select-box ">  
            <p>请选择</p>  
            <ul>  
                <li>上海</li>  
                <li>北京</li>  
            </ul>  
        </p>  
        <p>API测试</p>  
        <p id="testHasText" class="select-box ">  
            <p>testHasText</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testHasValue" class="select-box ">  
            <p>testHasValue</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testAddItem" class="select-box ">  
            <p>testAddItem</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testDeleteByText" class="select-box ">  
            <p>testDeleteByText</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testDeleteByValue" class="select-box ">  
            <p>testDeleteByValue</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testSelectByText" class="select-box ">  
            <p>testSelectByText</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testSelectByValue" class="select-box ">  
            <p>testSelectByValue</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testGetText" class="select-box ">  
            <p>testGetText</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testGetValue" class="select-box ">  
            <p>testGetValue</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="testClearItems" class="select-box ">  
            <p>testClearItems</p>  
            <input type="hidden"/>  
            <ul>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
          
        <p>测试下拉框联动</p>  
        <p id="sheng" class="select-box">  
            <p>请选择省</p>  
            <ul>  
                <li data-id="">请选择省</li>  
                <li data-id="1">上海</li>  
                <li data-id="2">北京</li>  
            </ul>  
        </p>  
        <p id="shi" class="select-box">  
            <p>请选择市</p>  
            <ul>  
                <li>请选择市</li>  
                <li>武汉</li>  
                <li>咸宁</li>  
            </ul>  
        </p>  
        <p id="xian" class="select-box ">  
            <p>请选择县</p>  
            <ul>  
                <li>请选择县</li>  
                <li>通山</li>  
                <li>嘉鱼</li>  
            </ul>  
        </p>  
    </p>  
<script type="text/javascript">  
//2016-11-4 11:11:33  
/*测试内容:  
    兼容测试   
    压力测试 没有data-id  
    边界测试  
    功能测试 √  1. hasText(str)、hasValue(str)  
             √  2. addItem(value, text)  
             √  3. selectByText(str)、selectByValue(str)  
             √  4. deleteByText(str)、deleteByValue(str)  
             √  5. getValue()、getText()  
             √  6. clearItems()  
             √  联动  
*/  
//功能测试  
console.log("测试hasText('上海'):"+$.select("#testHasText").hasText("上海"));  
console.log("测试hasValue('2'):"+$.select("#testHasValue").hasValue("2"));  
console.log("测试AddItem:");  
    $.select("#testAddItem").addItem("3","武汉");  
console.log("测试deleteByText:");  
    $.select("#testDeleteByText").deleteByText("上海");  
console.log("测试deleteByValue:");  
    $.select("#testDeleteByValue").deleteByValue("1");  
console.log("测试selectByText:");  
    $.select("#testSelectByText").selectByText("上海");  
console.log("测试selectByValue:");  
    $.select("#testSelectByValue").selectByValue("2");  
console.log("测试getText:"+$.select("#testGetText").selectByValue("1").getText());  
console.log("测试getValue:"+$.select("#testGetValue").selectByValue("1").getValue());  
console.log("测试clearItems:");  
    $.select("#testClearItems").clearItems()  
  
//联动  
var sheng = document.getElementById("sheng");  
var shi = document.getElementById("shi");  
var xian = document.getElementById("xian");  
sheng.callback = function(o){  
    console.log(o);  
    if(o.value.trim() == "请选择省"){  
        shi.clearItems().addItem("", "请选择市");  
    }  
}//callback end  
  
</script>  
</body>  
</html>

select.js:

//IE7/8不支持trim()  
if (String.trim == undefined) String.prototype.trim = function () { return this.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }  
//获取变量类型 -m  
$.getType = function (o) {  
    var _t;  
    return ((_t = typeof (o)) == "object" ? o == null && "null" || Object.prototype.toString.call(o).slice(8, -1) : _t).toLowerCase();  
}  
  
//创建Node节点  
function NewObject(tag, attrs, txt) {  
    var res = document.createElement(tag);  
    if ($.getType(attrs)==="object")  
        for (var k in attrs) {  
            if(k=="className"){ res.className = attrs[k]; continue; }  
            if (typeof attrs[k] == "object" && k == "style") $(res).css(attrs[k]);  
            else $(res).attr(k, attrs[k]);  
        };  
    if ($.getType(txt)==="string") res.appendChild(document.createTextNode(txt));  
    return res;  
}  
//2.下拉框组件 sclosed 保存下拉框的开闭状态 页面input缓存的值 通过 autocomplete = off 解决  
$.select = function (pBox, callback) {  
    var oBox = null;  
    if (typeof pBox == "string") oBox = $(pBox)[0];else oBox = pBox;  
    if ($.getType(callback) === "function") oBox.callback = callback;  
    //2.节点只被唯一绑定一次,再次绑定直接返回  
    if ($.getType(oBox.inited) !== "boolean") oBox.inited = true; else return oBox;  
    oBox.sclosed = true;  
    var label = $(oBox).children("p");    //用于界面上显示  
    var itemList = $(oBox).children("ul");  //li是下拉框的选项,ul用于代理事件  
    if(oBox.value == undefined) oBox.value = "";  
    //下拉框的打开和关闭(自动切换状态)  
    label.click(function (e) {  
        var o = e ? e.target : window.event.srcElement;  
        if (o.nodeName.toLowerCase() == "p") {  
            oBox.sclosed = false;  
            if (itemList.css("display") == "none") {  
                itemList.slideDown("fast", function () { oBox.sclosed = true; });  
            }  
            else itemList.slideUp("fast");  
        }  
        $(document).click(function (e) {  
            if (oBox.sclosed == true) {  
                itemList.css("display", "none");  
                $(this).unbind("click",arguments.callee);  
            }  
        });  
        if (window != window.parent) {  
            $(window.parent.document).click(function () {  
                if (oBox.sclosed == true) {  
                    itemList.hide();  
                    $(this).unbind("click",arguments.callee);  
                }  
            });  
        }  
    });  
    itemList.click(function (e) {//选中事件  
        var o = e ? e.target : window.event.srcElement;  
        if (o.nodeName.toLowerCase() != "li") return;  
        var id = o.getAttribute("data-id");  
        var value = o.innerHTML.trim();  
        if(id==undefined) id="";  
        label.html(value);  
        oBox.setAttribute("value",id);  
        if (oBox.callback != null) {  
            oBox.callback({ "id": id, "value": value });  
        }  
    });  
    oBox.hasText = function(str) {  
        var ocs = itemList.children("li");  
        for(var i=0;i<ocs.length;i++) if(str=== ocs[i].innerHTML.trim()) return true;  
        return false;  
    }  
    oBox.hasValue = function(str){  
        var ocs = itemList.children("li");  
        for(var i=0;i<ocs.length;i++) if(str=== ocs[i].getAttribute("data-id")) return true;  
        return false;  
    }  
    oBox.addItem = function (value, text) {  
        if(!this.hasValue(value)){  
            itemList[0].appendChild(NewObject("li",{"data-id":value},text));  
        }  
        return this;  
    }  
    oBox.selectByValue = function(str){  
        if(this.hasValue(str)){  
            var ocs = itemList.children("li");  
            for(var i=0;i<ocs.length;i++){  
                var id = ocs[i].getAttribute("data-id");  
                if(id==undefined) id = "";  
                else id = id.trim();  
                if(str==id && id!=""){  
                    label.html(ocs[i].innerHTML.trim());  
                    this.value = str;  
                    break;  
                }  
            }  
        }  
        return this;  
    }  
    oBox.selectByText = function(str){  
        if(this.hasText(str)){  
            var ocs = itemList.children("li");  
            for(var i=0;i<ocs.length;i++){  
                if(str===ocs[i].innerHTML.trim()){  
                    label.html(str);  
                    var id = ocs[i].getAttribute("data-id");  
                    if(id==undefined) id="";  
                    else id = id.trim();  
                    this.value = str;  
                    break;  
                }  
            }  
        }  
        return;  
    }  
    oBox.deleteByText = function(str){  
        itemList.children("li").each(function(){  
            if(str===this.innerHTML.trim()) this.parentNode.removeChild(this);  
        });  
        return this;  
    }  
    oBox.deleteByValue = function(str){  
        itemList.children("li").each(function(){  
            if(this.getAttribute("data-id")===str) this.parentNode.removeChild(this);  
        });  
        return this;  
    }  
    oBox.getText = function(){  
        return label.html().trim();  
    }  
    oBox.getValue = function(){  
        return this.value;  
    }  
    oBox.clearItems = function(){  
        this.value = "";  
        itemList.html("");  
        label.html("请选择");  
        return this;  
    }  
    return oBox;  
};  
//初始化全部下拉框 如果有实时性必要,可以跟在节点后面提前初始化 不影响  
$(function () {  
    $(".select-box").each(function () {  
        $.select(this);  
    });  
});

今天还在改,因为模拟的下拉框不好进行验证,于是我就将内部隐藏的input去掉,将value放到p.select-box上了,这中间有坑:Node.value与Node.getAttribute("value")看起来一样,但Node如果是p节点就有问题

工作记录里的一段:

2016-11-10 11:05:42  
    textarea的value和innerHTML的区别:js修改后innerHTML不会变 value会  
2016-11-10 11:58:23  
    真正解决了p的value问题 p初始标签里有value是属于attribute里的只能用getAttribute取,直接node.value是不行的 没有则node.value是undefined node.getAttribute("value")是null  
    jQuery获取的节点 [0].value是undefined val()是空字符串 [0].getAttribute("value")和attr("value")是一样的  
    select初始化时 来句 oBox.value = oBox.getAttribute("value");就没问题了  
    意外观察到   
    console.log(item[0].value);  
    console.log(item.val());  
    console.log(item[0].getAttribute("value"));  
    console.log(item.attr("value"));  
    有网址的input第三个为null 其他的正常  
    对全部的input遍历 基本都为null node.value 和 node.attribute.value是真不一样
//今天改了之后是这样写的  
<p id="unit" class="select-box" value="1">  
    <p>测试身份证</p>  
    <ul>  
       <li data-id="1">Kg</li>  
       <li data-id="2">吨</li>  
     </ul>  
</p>  

两张小图片:

div模拟的下拉框
div模拟的下拉框

最后是我在项目中用的重置样式的css:

/* 1.重置所有浏览器的初始样式 */  
html, body { margin: 0; font-family: "Microsoft YaHei"; font-size: 12px; }  
/* l-v-h-a原则 */  
a:link, a:visited { color: #333; }  
a:hover, a:active { color: #c00; }  
a:focus { outline: 0 none; }  
img, iframe, fieldset { border: 0 none; } /* frameborder="0"设置边框是不否为3维(0=否,1=是) 要在标签内写 为了对付IE */  
iframe { width: 100%; height: 100%; overflow-y: auto; }  
img { vertical-align: middle;/* -ms-interpolation-mode: bicubic;*/ } /* IE7中缩放采用高质量双线性图片采样 */  
ul { margin-top: 0; margin-bottom: 0; padding-left: 0; }  
ul > li { list-style-type: none; }  
input { border: 1px solid #ccc; padding: 4px 0 4px 8px; }  
input[type="text"]:focus { border-color: rgb(82, 168, 236); box-shadow:; }  
/*input[type="text"]:focus { border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236, 0.6); }*/  
p { margin: 5px 0; line-height: 1.5; word-wrap: break-word; } /* 允许长单词换到下一行 可继承:normal (默认在可以断开的点断开) break-word 断开*/  
textarea { resize: none; }/*  不允许用户通过右下角的三角形调整 IE不支持resize?*/  
table { table-layout: fixed; width: 100%; border-spacing: 0; border-collapse: collapse; word-break: break-all; } /* 合并表格的边框线*/  
button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; }  
article, aside, dialog, footer, header, section, footer, nav, figure, menu{ display: block; } /* H5标签兼容低版本IE,页面中需要用条件注释对每个H5标签用document.createElement。 例如:document.createElement("header");*/  
/* 渐进增强效果:设置页面文字等在拖动鼠标选中情况下的背景色与文字颜色 */   
::selection {color: #fff; background-color: #f99a41; }  
::-moz-selection {color: #fff;background-color: #f99a41; }   
::-webkit-selection {color: #fff;background-color: #f99a41; }

Tags:DI IV V模 模拟 
作者:网络 来源:ruanjiayou