在bootstrap-table中使用滑动开关bootstrap-toggle

前言

最近对滑动开关有需求,由于当前的项目采用springboot+bootsrtap3架构,所以目标优先定位到基于bootstrap的滑动开关解决方案。先后尝试了bootstrap-swtich和bootstrap-toggle,期间踩坑无数,最后选择了bootstrap-toggle。在此详细记录一下整个过程。

需求在bootstrap-tables的某一列中显示滑动开关,操作本列对象是否启用。初始化时需要显示本列对象的初始状态(有的已经off,有的已经on)。

bootsrap-toggle的效果图:

toggle-on
toggle-off

简单说下bootstrap-switch

网上关于bootstrap-switch的资料是最多的,可见这个插件是相对流行的基于bootstrap的开关组件了。但是在使用过程中发现很多坑,首先这个组件的网页上的例子所有滑块竟然都没有渲染,全是原始的checkbox样式-_-;其次,渲染了之后发现也略丑,最小尺寸也很大;最后,解决一堆问题终于让开关渲染出来,状态切换事件也run起来之后,发现一个一直没有办法解决的问题:初始状态永远在off。由于本人前端水平是N手业余,所以stackoverflow查了半天没解决的前提下,选择了放弃。附bootstrap-switch的“官网”:https://www.bootcss.com/p/bootstrap-switch/

言归正传:bootstrap-toggle

这个插件在网上的资料极少极少,原因很简单——停更了...看js文件注释应该是2014年最后一次更新。然而这并不影响我们使用它(尽管那个年代还是面向bootstrap2,但在bootstrap3中亲测可用),因为滑动开关这种组件功能简单,就算实时更新也不会有太多花样。另外就是bootstrap-toggle的使用方法很简单,个人认为堪称优雅了。当然这里面也有个巨坑,好在已经排掉,后文详述。

bootstrap-toggle官网:http://www.bootstraptoggle.com/

bootstrap-toggle的用法在官网说的已经非常清楚了,在这里结合bootstrap-table一起总结一下。

常规用法

引入bootstrap-toggle,从官网下载代码解压后,css文件和js文件分别在根目录下的css和js文件夹中。

<link href="/bootstrap-toggle/css/bootstrap-toggle.css" rel="stylesheet">
<script src="/bootstrap-toggle/js/bootstrap-toggle.js"></script>

在页面里定义一个checkbox元素:

<input name='mycheck' type='checkbox' checked/>

然后在js中初渲染:

<input name="mycheck" checked type="checkbox">
<script>
  $(function() {
    $("[name='mycheck']").bootstrapToggle();
  })
</script>

这样就可以得到一个开关了:


开关基本样式

当然,这个开关只是展示了出来,还不具备数据传递功能。可以利用jquery的on方法绑定事件:

<input name="mycheck" checked type="checkbox">
<script>
  $(function() {
    $("[name='mycheck']").bootstrapToggle().on('change.status',function(){
      //do something 
    });
  })
</script>

结合bootstrap-table使用

首先在bootstrap-table对应列里动态生成开关:

   $('#yourTable').bootstrapTable({
        columns: [
            /**
            略去其他代码
            **/
            {
                field: 'available',
                title: "是否启用",
                align: 'left',
                valign: 'middle',
                formatter: function (value, row, index) {
                    var $switch;
                    if (value == true) {
                        $switch = "<input data-toggle='toggle' value=" + row.id + " name='avaCheck' type='checkbox' checked/>";
                    } else {
                        $switch = "<input data-toggle='toggle' value=" + row.id + " name='avaCheck' type='checkbox'/>";
                    }
                    return $switch;
                }
            }
        ],
        onLoadSuccess: function () {
            var changeHandler = function () {
                var id = $(this).val();
                var state = !$(this).prop('checked');
                updateStatus(id, state);
            };
            $("[name='avaCheck']").bootstrapToggle('destroy');
            return $("[name='avaCheck']").bootstrapToggle({
                on: '启用',//选中时显示文本
                off: '停用',//未选中时显示文本
                onstyle: 'success',//on样式:default,primary,success,info,warning,danger
                offstyle: 'default',//off样式:default,primary,success,info,warning,danger
                size: 'small',//控件大小:large,normal,small,mini
            }).off('change.status').on('change.status', changeHandler);
        }
    })

要点说明:

  • formatter中把本列的对象id绑定到checkbox的value中,可以透传到后续的状态变更事件。
  • 表格的onLoadSuccess事件保障表格载入完成后,对checkbox进行渲染,这步是无法在formatter中完成的。
  • changeHandler方法即是在开关状态变更的事件触发时执行,具体逻辑在updateStatus(id, state)中实现,其中id是前面透传过来的本行对象在系统中的id,state是开关当前的状态(on对应trueoff对应fasle)。
  • 这里调用bootstrapToggle方法时也对开关样式进行了部分定制。

还差最后一步

这样开关就搞定了。用法是不是很简洁?然后此时还没最终完工,此组件还有个大坑需要填上。按照这个方式启动程序后,首次载入表格,开关可以正常工作,点击开关会切换状态并且更新到后台。但是如果点击别的页面,再回到表格页面(表格会reload一次),再点击开关切换状态就会发生异常,具体表现:点击开关一次,后台会发送n次请求,n=表格load的总次数。
那么问题就可以总结为:表格每load一次,点击开关,开关就会自动多切一次。这个问题很难查,看似是change事件出问题了,最开始以为是每次表格reload后,都会叠加绑定一次change事件,所以在on方法前加了off方法,即绑事件前先卸载,保障事件只绑一次,然而问题并没有解决,甚至把绑事件的代码注释掉依然还是这样!这就说明,这个问题与事件绑定这个操作无关,是开关在初始化时出了一些问题。没办法,硬着头皮看bootstrap-toggle.js文件里的代码,幸好代码行数很少,很快发现问题所在,原来在初始化时,bootstrap-toggle会给自己绑定一个鼠标点击事件,源码176行:

    $(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function (e) {
        var $checkbox = $(this).find('input[type=checkbox]')
        $checkbox.bootstrapToggle('toggle')
        e.preventDefault()
    })

问题很明显了:绑定click事件只用了on,没有用off,所以每次都会叠加一个click事件,最后表现就是:初始化N次就绑定N次click,那么你点击一次它内部就会触发N次点击的效果。这是click事件问题,却很容易误导到往change事件的方向排查。简单修改一下代码,绑定前先增加off方法:

    $(document).off('click.bs.toggle').on('click.bs.toggle', 'div[data-toggle^=toggle]', function (e) {
        var $checkbox = $(this).find('input[type=checkbox]')
        $checkbox.bootstrapToggle('toggle')
        e.preventDefault()
    })

重新编译,运行,测试,问题解决!这样我们就可以真正优雅的使用这款滑动开关了。

默默的感谢一下作者,感谢互联网共享精神,让我在2019年用到了2014年就停更的来自NewYork的这款开关组件:

Copyright 2014 Min Hur, The New York Times Company
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342