想记录下自己在开发这个下拉框插件之后的心得,修修改改,最终决定,将以后我可能用得到的一条条来写,这样看起来也比较清晰。
1、写jquery插件需要的一个结构
// 定义jQuery私有作用域
(function ($) {
// 插件默认属性
var defaults = {
name1: "value1",
name2: "value1",
... ...
}
// 插件名
$.fn.easySlider = function (options) {
// 将默认属性和用户传入得属性合并
var options = $.extend(defaults, options);
// this.each(function() {}) 循环对象,支持jQuery选择器
// return 循环后的对象,支持链式调用
return this.each(function () {
});
}
})(jQuery) // 传入jQuery 对象
第一次写 jQuery 插件,有看了别人写的一些博客,分享一个写的很好的,自己也是从中受益。https://www.cnblogs.com/xcj26/p/3345556.html
2、写之前先把要实现的的功能理清楚
我觉得是这样的,要知道自己想要的功能,实现起来就比边想边做好,也不容易乱或者遗漏。就以下面这个为例:
- 单选下拉框
- 最基本的点击下拉框,弹出下拉选项列表
- 点击下拉选项,切换选中的内容,同时隐藏下拉选项列表
- 点击其他区域,隐藏下拉选项列表
- 多选下拉框(在单选下拉框的基础上)
- 可以点击多个选项,或者选项上的复选框图标,选择多个选项,当然这时点击选项就不能隐藏下拉选项列表了
3、尽可能让用的人使用起来方便
第一次写,想的没那么周到,按照自己想要的结构就写了,以下是我最开始写的,贴出来不怕人笑话,还有一个多选的就不贴了。
<div style="z-index: 200" class="singleSelect select hideOptions">
<div class="selecter">
<span>请选择</span>
</div>
<ul class="optionBox hide">
<li data-value="1" class="option">value1</li>
<li data-value="2" class="option">value2</li>
<li data-value="3" class="option">value3</li>
<li data-value="4" class="option">value4</li>
<li data-value="5" class="option">value5</li>
</ul>
</div>
样式什么的都写了,点击事件啥的也差不多了,啊哈哈哈,我也写了一个插件,开心啊!但是别人在用的时候,问题就来了,总不能我每次需要一个下拉框的时候,都要写这么一堆标签吧?而且他们需要通过 <form> 提交表单,按这样来写肯定是获取不到值的,虽然说我专门提供了获取值的方法,但是也满足不了需求。后面也看了别人写的下拉框插件,都有隐藏的原生的下拉框 <select>。
其实是这样的,用的人只需要像原来那样使用原生的 <select>(<select>在页面上不显示出来),需要什么功能直接往属性上加,其他的都放 js 中控制。页面上显示的是我们自定义的下拉框(newSelect),也就是上面那一堆标签,在操作 newSelect 的值的同时操作 <select>,保证他们当前选中的值是一样的,这样通过 <form> 提交表单就能获取到 <select> 的值了。
<select id="select2" class="customSelect" onchange="testChange(this)">
<option value="1">1</option>
<option value="2">2</option>
<option value="3" selected data-selected="selected">3</option>
<option value="4">4</option>
</select>
之后标签像这样写就可以了。
4、先把想要的html结构在html页面中写出来
就比如说我自定义的下拉框结构像下面这样,如果我先在 html 页面中把想要的结构、功能都实现了,再按这个结构移到 js 中写,这样就很清晰了,不会存在直接在 js 中写字符串模板,写到一半,然后不知道接着该是什么标签来着这样的问题。当然直接在 js 中写也行,就怕出错,所以觉得明确的先把自己想要的东西写出来,这样会比较好一些。
<div style="z-index: 200" class="singleSelect select hideOptions">
<div class="selecter">
<span>请选择</span>
</div>
<ul class="optionBox hide">
<li data-value="1" class="option">value1</li>
<li data-value="2" class="option">value2</li>
<li data-value="3" class="option">value3</li>
<li data-value="4" class="option">value4</li>
<li data-value="5" class="option">value5</li>
</ul>
</div>
5、如果原生已有的功能,尽可能在原生的基础上进行改造
这点在第3点也有提到,在没有这个插件的时候,用的肯定是原生的 <select>,如果能实现使用起来原生差不多,主要是结构不能太复杂,这样使用起来就比较方便。
6、onchange事件,通过js改变select的值,是不会触发的,需要通过 trigger("change") 来手动触发
onChange 事件要在失去焦点(blur)后执行,所以通过 js 改变值是不会触发 onChange 事件的,自己试一下就知道了。
$("#select").trigger("change");
7、事件绑定只需要调用一次,不用每次循环的时候都去调用
可能有的人会像我这样,好像只要能给元素绑定事件就行,没注意那么多,在看别人的代码的时候,才会注意到自己代码的问题。
下面的代码中,绑定事件是写在循环当中的,每次都要去绑定一次,这样就做了很多多余的操作。
// 插件名
$.fn.select = function(options) {
// 下拉框对象循环
$(this).each(function(i, select) {
var defaultOptions = {
checkboxImg: {
defaut: "../imgs/checkbox-default.png",
selected: "../imgs/checkbox-selected.png"
},
prompt: "请选择",
showTitle: true
};
$.extend(true, allOptions, defaultOptions, options || {});
// 建立新的下拉框
$(select).newSelect();
// dom标签生成之后,绑定事件
$(document).on("mousedown", ".selecter", function() {
});
$(document).on("mousedown", function() {
});
$(document).on("mousedown", ".option", function(event) {
});
});
}
像下面这样,控制一下,绑定一次就行。这是一种思路,要避免冗余的操作。
$.fn.select = function(options) {
$(this).each(function(i, select) {
var defaultOptions = {
checkboxImg: {
defaut: "../imgs/checkbox-default.png",
selected: "../imgs/checkbox-selected.png"
},
prompt: "请选择",
showTitle: true
};
$.extend(true, allOptions, defaultOptions, options || {});
// 建立新的下拉框
$(select).newSelect();
// 这边做一个控制,执行一次就行
if(!initOnce.fired) {
// 该方法的内容就是 为元素绑定事件
initOnce.fire();
initOnce.fired = true;
}
});
}
8、每个能提取出来的功能点都写成一个方法,比较清楚
这样以后改造起来会简单清晰一些。比如要为下拉框设置值,步骤应该是先获取当前点击的值,将值的结果处理成自己想要的结构,再设置值。获取并处理值结构可以写成一个方法,设置值写成一个方法,当然,你也可以按自己的需求来分,就是尽量拆分开来,不然一堆的代码写在一起,确实不好看。
9、使用 for(var i=0, len=arr.length; i < len; i++),而不是 for(var i=0; i < arr.length; i++),这样每次都要去获取数组的长度
这个其实跟第7点有点像,就是这种思路。
10、下拉选项框要放到<body>下,确保能显示出来
<div style="z-index: 200" class="singleSelect select hideOptions">
<div class="selecter">
<span>请选择</span>
</div>
<ul class="optionBox hide"> /* 这个下拉选项框相对于 .select 定位*/
<li data-value="1" class="option">value1</li>
<li data-value="2" class="option">value2</li>
<li data-value="3" class="option">value3</li>
<li data-value="4" class="option">value4</li>
<li data-value="5" class="option">value5</li>
</ul>
</div>
这个问题我遇到了,但是没有很明白。假如说 .select 的外层容器是 .wraper,不知道 .wraper 到底是怎么了,可能是 .wraper 的层级比较高 ?导致 .select 内层的定位元素被 .wraper 的高度限制,从而显示不出来。如果有看得懂我写的,能明白我说的朋友,帮忙说下是什么原因。
我猜可能是层级的问题,我也看了别人的插件定位元素是直接写在 <body> 下面,所以就把下拉选项框 <ul> 放到 <body> 下,这样就能保证能显示出来。
11、生成的下拉框与原<select>的唯一性属性要不同,不然在获取元素时会存在问题(id,name)
这个在开发中遇到的问题,开发人员通过 name 属性获取元素,结果不唯一,就导致了问题。这也不是什么难题,字符串拼接下就好了,只是需要注意一下。
12、鼠标事件顺序,mousedown -> focus -> mouseup -> click -> blur
基本用的都是 click 事件,很少用其他的,导致对鼠标事件顺序不了解。
mousedown 鼠标点下
focus 输入框获得焦点
mouseup 鼠标松开
click 鼠标点下、松开
blur 输入框失去焦点
我的插件中,为元素绑定的是 mousedown 事件,为什么呢?
有一个现象,假如我绑定的是 click 事件,然后在下拉选项框弹出之后,去拖动滚动条,这时下拉选项框是不会隐藏的,因为鼠标还没松开,所以绑定 mousedown 事件就可以很好的解决这个问题,只要点下去的时候就会隐藏下拉选项框了。
这是我写的简陋的下拉框:https://github.com/KumikoYYC/jQuery-select
写的比较 low,多多包涵,多多指点!
来源:oschina
链接:https://my.oschina.net/u/4257408/blog/3662475