zoukankan      html  css  js  c++  java
  • html自定义checkbox、radio、select —— select篇

    上一篇《html自定义checkbox、radio、select —— checkbox、radio篇》介绍了我们是怎么将 html 自带的 checkbox、radio 改成我们自定义的UI的,现在来说说怎么将 html 自带的 select 改成我们自定义的UI(由于时间关系,我们只完成了单选部分的转换,而多选部分的转换没做,后续会找个时间补上)。

    select 跟 checkbox、radio 方法大致相同。在 Bootstrap 中,有一个"按钮式下拉菜单"的组件,我们是在这个基础上进行修改的。

    效果:

            

    结构大致是:

    <div>
        <button>
        <ul>
    </div>
    <select>

    其中,<div>包住的就是展示出来的UI,<button>是正常情况下显示的,<ul>是各个选项,<select>是隐藏的。

    首先,<button>使用 Bootstrap 中 "btn dropdown-toggle" 样式,并为其添加<span>、<i>标签用来显示文字和下拉的图标,我们有对部分 ".dropdown-" 相关的样式做了扩展和改写。

    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() === '' ? '&nbsp;' : $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>,设置初始值,再做一些调整,就可以看到这种效果了:

    对于我们来说,做麻烦的就是当使用 JQ 控制显示隐藏(hide()、show())的时候,修改的<select>也要跟着变化。说以我们只能重写 JQ 的 hide()、show() 方法。

    首先对 <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,在 IE8、9、chrome、ff 上测试通过,其他没测过。

    demo 可能写得不够好,插件也可能存在一些问题我还没发现的,请发现任何问题都跟我说一下,谢谢各位!


    另:要请教各位怎么把文件放在网盘上,然后直接 copy 出文件路径,今天试过115、百度、腾讯的,都不能直接 copy,都是只能引到另一个页面下载。

  • 相关阅读:
    mac os x 查看网络端口情况
    mac 启动php-fpm报错 failed to open configuration file '/private/etc/php-fpm.conf': No such file or direc
    视频播放—— H5同层播放器接入规范
    [转]webpack中require和import的区别
    职场方法论系列—怎样做项目
    一幅图帮你搞懂订单的拆分与合并
    如何用数据去驱动决策?
    分库分表的 9种分布式主键ID 生成方案,挺全乎的
    快手基于 Apache Flink 的优化实践
    SQL数据库中临时表、临时变量和WITH AS关键词创建“临时表”的区别
  • 原文地址:https://www.cnblogs.com/SugarLSG/p/3198351.html
Copyright © 2011-2022 走看看