上一篇《html自定义checkbox、radio、select —— checkbox、radio篇》介绍了咱们是怎么将 html 自带的 checkbox、radio 改为咱们自定义的UI的,如今来讲说怎么将 html 自带的 select 改为咱们自定义的UI(因为时间关系,咱们只完成了单选部分的转换,而多选部分的转换没作,后续会找个时间补上)。javascript
select 跟 checkbox、radio 方法大体相同。在 Bootstrap 中,有一个"按钮式下拉菜单"的组件,咱们是在这个基础上进行修改的。html
效果:java
结构大体是:chrome
<div>
<button>
<ul>
</div>
<select>bootstrap
其中,<div>包住的就是展现出来的UI,<button>是正常状况下显示的,<ul>是各个选项,<select>是隐藏的。app
首先,<button>使用 Bootstrap 中 "btn dropdown-toggle" 样式,并为其添加<span>、<i>标签用来显示文字和下拉的图标,咱们有对部分 ".dropdown-" 相关的样式作了扩展和改写。ide
var $button = $('<button>', { type: 'button', 'class': 'btn dropdown-toggle', 'data-toggle': 'dropdown' }) .append($('<span>', { 'class': 'text-left pull-left' })) .append($('<i>', { 'class': 'caret pull-right' })) .click(function () { $button.dropdown(); return $button; });
接着,将<select>中的各个选项加进<ul>中,使用<a>保存 value 和 text,并添加 click 事件。测试
var $selectALink; var _addOption = function ($option, inGroup) { var $aLink = $('<a>', { href: 'javascript:void(0)', 'data-value': $option.val(), html: $option.html() === '' ? ' ' : $option.html() }) .click(function () { if (!$aLink.data('disabled')) { _setSelectValue($wrapper, $aLink); $ul.scrollTop($aLink[0].offsetTop - 1); $select.trigger('change'); if ($.validator) $select.valid(); } return $aLink; }); inGroup && $aLink.addClass('groupopt'); $option.attr('disabled') && $aLink.addClass('disabled').data({ disabled: true }); $option.attr('selected') && ($selectALink = $aLink); $ul.append($('<li>').append($aLink)); } var $ul = $('<ul>', { 'class': 'dropdown-menu' }); $select .children() .each(function () { var $obj = $(this); if ($obj.is('optgroup')) { $ul.append( $('<li>').append( $('<label>', { 'class': 'optgroup', html: $obj.attr('label') }) ) ); $('option', $obj).each(function () { _addOption($(this), true); }); } else if ($obj.is('option')) { _addOption($obj); } });
而后将<button>、<ul>装进<div>中,隐藏<select>,设置初始值,再作一些调整,就能够看到这种效果了:this
对于咱们来讲,作麻烦的就是当使用 JQ 控制显示隐藏(hide()、show())的时候,修改的<select>也要跟着变化。说以咱们只能重写 JQ 的 hide()、show() 方法。spa
首先对 <select> 添加对应处理方法:
$select .addClass('hide') .data({ transformed: true }) .on({ hide: function () { $wrapper.hide(); _setSelectStatus($select); }, show: function () { $wrapper.show(); _setSelectStatus($select); }, transformReset: function () { $('option', $select).not(_$defaultSelected.attr({ selected: true })).attr({ selected: false }); $select.transformResetStatus(); } });
同 checkbox、radio,transformReset() 方法也是用于表单重置的。
接着,重写 JQ 的 hide()、show() 方法,而咱们的目的是新方法仅对 <select> 有效,而其余标签依旧使用旧方法,因此:
var _oldhide = $.fn.hide; var _oldshow = $.fn.show; $.fn.hide = function (speed, callback) { if (this.is('select') && this.data('transformed')) { this.trigger('hide'); } else { _oldhide.apply(this, arguments); } return this; }; $.fn.show = function (speed, callback) { if (this.is('select') && this.data('transformed')) { this.trigger('show'); } else { _oldshow.apply(this, arguments); } return this; };
至此,整个改造过程大致完成,测试也能经过。
可是后来又有问题了,就是用 JQ 改变 checkbox、radio、select 的值的时候,显示的东西不会随着变。
尝试了不少方法,想实现自动同步的效果,可是都失败了了。后来,咱们只能在代码里,手动同步了,即在修改后,再调用一个方法来同步:
$.fn.transformResetStatus = function () { return this.each(function () { var $obj = $(this); if ($obj.is('input')) { $obj.data('transformed') && _setInputStatus($obj); } else if ($obj.is('select')) { $obj.data('transformed') && _setSelectStatus($obj); } }); };
好了,3个标签的改造已经完成了。你们能够试试 Demo,在 IE八、九、chrome、ff 上测试经过,其余没测过。
demo 可能写得不够好,插件也可能存在一些问题我还没发现的,请发现任何问题都跟我说一下,谢谢各位!
另:要请教各位怎么把文件放在网盘上,而后直接 copy 出文件路径,今天试过11五、百度、腾讯的,都不能直接 copy,都是只能引到另外一个页面下载。