• js插件---JS表格组件BootstrapTable行内编辑解决方案x-editable


    js插件---JS表格组件BootstrapTable行内编辑解决方案x-editable

    一、总结

    一句话总结:bootstrap能够做为最火的框架,绝对不仅仅只有我看到的位置,它应该还有很多位置可以极大的方便开发,可能是插件这一块,也可能是别的。

    1、创建可编辑弹出框的插件叫什么?

    x-editable组件

    2、bootstrap Table的优势是什么?

    在开发经历中,也使用Jqgrid、EasyUI等表格组件。相比而言,bootstrap Table有自己的优势:

    1、界面采用扁平化的风格,用户体验比较好,更好兼容各种客户端。这点也是最重要的。

    2、开源、免费。国人最喜欢的就是免费了。呵呵。

    3、相对Jqgrid、easyUI而言,比较轻量级。功能不能说最全面,但基本够用。

    二、JS表格组件BootstrapTable行内编辑解决方案x-editable

    前言:之前介绍bootstrapTable组件的时候有提到它的行内编辑功能,只不过为了展示功能,将此一笔带过了,罪过罪过!最近项目里面还是打算将行内编辑用起来,于是再次研究了下x-editable组件,遇到过一些坑,再此做个采坑记录吧!想要了解bootstrapTable的朋友可以移步JS组件系列——表格组件神器:bootstrap table。 

    一、x-editable组件介绍 

    x-editable组件是一个用于创建可编辑弹出框的插件,它支持三种风格的样式:bootstrap、Jquery UI、Jquery。大致效果如下图: 

    根据博主一贯的风格,这里肯定是选用第一种喽。首先还是给出开源地址吧。 
    x-editable开源地址:https://github.com/vitalets/x-editable 
    x-editable文档地址:http://vitalets.github.io/x-editable/docs.html 
    x-editable在线Demo:http://vitalets.github.io/x-editable/demo-bs3.html 

     1、x-editable初体验 

    首先下载基于bootstrap的源码到本地。引用相关文件。 

    1
    2
    3
    4
    5
    6
    <link href="/Content/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <link href="~/Content/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet" />
      
    <script src="/Scripts/jquery-1.9.1.min.js"></script>
    <script src="/Content/bootstrap/js/bootstrap.min.js"></script>
    <script src="~/Content/bootstrap3-editable/js/bootstrap-editable.js"></script>

     页面元素

    复制代码 代码如下:
    <a href="#" id="username" data-type="text" data-title="用户名">用户名</a>

    js初始化

    1
    2
    3
    $(function () {
     $('#username').editable();
    });

    效果展示

     

    上面是通过html的data属性去设置x-editable的参数,当然,我也可以在初始化的时候去设置参数,比如,我仅仅给一个空的a标签:<a href="#" id="username">用户名</a>

    js初始化 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $(function () {
     $('#username').editable({
      type: "text",    //编辑框的类型。支持text|textarea|select|date|checklist等
      title: "用户名",    //编辑框的标题
      disabled: false,    //是否禁用编辑
      emptytext: "空文本",   //空值的默认文本
      mode: "inline",    //编辑框的模式:支持popup和inline两种模式,默认是popup
      validate: function (value) { //字段验证
       if (!$.trim(value)) {
        return '不能为空';
       }
      }
     });
     
    });

    查看效果

     

    再来个稍微复杂一点的
     <a href="#" id="department">选择部门</a>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $(function () {
     $('#department').editable({
      type: "select",    //编辑框的类型。支持text|textarea|select|date|checklist等
      source: [{ value: 1, text: "开发部" }, { value: 2, text: "销售部" }, {value:3,text:"行政部"}],
      title: "选择部门",   //编辑框的标题
      disabled: false,   //是否禁用编辑
      emptytext: "空文本"//空值的默认文本
      mode: "popup",   //编辑框的模式:支持popup和inline两种模式,默认是popup
      validate: function (value) { //字段验证
       if (!$.trim(value)) {
        return '不能为空';
       }
      }
     });
     
    });

    查看效果

     

    上文只是给出了一些常用字段,当然x-editable组件还有很多其他的功能参数,有兴趣可以看看文档,官方文档对每个参数都有详细的说明。 

    二、bootstrapTable行内编辑初始方案 

    说了这么半天,上面的只是铺垫,我们最终是希望在bootstrapTable里面实现行内编辑。根据上面的规则,我们想要使用x-editable实现行内编辑,表格的单元格里面必须要有一个a标签,然后对a标签做x-editable的初始化。有了这个想法,我们按照这种思路先试试。 

    引用相关文件 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <link href="/Content/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <link href="~/Content/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet" />
    <link href="/Content/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
      
    <script src="/Scripts/jquery-1.9.1.min.js"></script>
    <script src="/Content/bootstrap/js/bootstrap.min.js"></script>
    <script src="~/Content/bootstrap3-editable/js/bootstrap-editable.js"></script>
    <script src="~/Content/bootstrap-table/bootstrap-table.js"></script>
    <script src="/Content/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>

    bootstrapTable的相关初始化 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    <script type="text/javascript">
     var curRow = {};
     $(function () {
      $("#tb_user").bootstrapTable({
       toolbar: "#toolbar",
       idField: "Id",
       pagination: true,
       showRefresh: true,
       search: true,
       clickToSelect: true,
       queryParams: function (param) {
        return {};
       },
       url: "/Editable/GetUsers",
       columns: [{
        checkbox: true
       }, {
        field: "UserName",
        title: "用户名",
        formatter: function (value, row, index) {
         return "<a href="#" name="UserName" data-type="text" data-pk=""+row.Id+"" data-title="用户名">" + value + "</a>";
        }
       }, {
        field: "Age",
        title: "年龄",
       }, {
        field: "Birthday",
        title: "生日",
        formatter: function (value, row, index) {
         var date = eval('new ' + eval(value).source)
         return date.format("yyyy年MM月dd日");
        }
       },
       {
        field: "DeptName",
        title: "部门"
       }, {
        field: "Hodd",
        title: "爱好"
       }],
       onClickRow: function (row, $element) {
        curRow = row;
       },
       onLoadSuccess: function (aa, bb, cc) {
        $("#tb_user a").editable({
         url: function (params) {
          var sName = $(this).attr("name");
          curRow[sName] = params.value;
          $.ajax({
           type: 'POST',
           url: "/Editable/Edit",
           data: curRow,
           dataType: 'JSON',
           success: function (data, textStatus, jqXHR) {
            alert('保存成功!');
           },
           error: function () { alert("error");}
          });
         },
         type: 'text'
        });
       },
      });
     });</script>

    后台方法 

    后台测试方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public JsonResult GetUsers()
      {
       var lstRes = new List<User>();
       lstRes.Add(new User() { Id = "1", UserName = "张三", Age = 22, Birthday = Convert.ToDateTime("1994-12-21"), DeptId = "1", DeptName = "研发部" });
       lstRes.Add(new User() { Id = "2", UserName = "李四", Age = 28, Birthday = Convert.ToDateTime("1988-09-09"), DeptId = "2", DeptName = "销售部" });
       lstRes.Add(new User() { Id = "3", UserName = "风衣大叔", Age = 40, Birthday = Convert.ToDateTime("1976-09-01"), DeptId = "2", DeptName = "销售部" });
       lstRes.Add(new User() { Id = "4", UserName = "闪电大虾", Age = 37, Birthday = Convert.ToDateTime("1979-03-12"), DeptId = "4", DeptName = "创意部" });
       lstRes.Add(new User() { Id = "5", UserName = "韩梅梅", Age = 29, Birthday = Convert.ToDateTime("1987-05-01"), DeptId = "5", DeptName = "事业部" });
      
       return Json(lstRes, JsonRequestBehavior.AllowGet);
      }
      
      public JsonResult Edit(User user)
      {
       //反序列化之后更新
      
       return Json(new { }, JsonRequestBehavior.AllowGet);
      }

    这样确实是可以实现想要的效果,貌似也能行内编辑了,可是如果没个列都需要行内编辑,并且列的个数很多,那么是不是每个列都得这样去formmater?并且这种写法狠显然很死板,博主着实难以接受。于是又找了找例子,发现在bootstrapTable的扩展里面存在bootstrap-table-editable.js这个js。 

    三、bootstrapTable行内编辑最终方案 

    好吧,博主承认,上面还是铺垫,因为博主觉得这可能是解决问题的一般思路,所以将这些铺垫的篇幅可能有点多。首先来看看bootstrap-table-editable.js这个文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    /**
     * @author zhixin wen <wenzhixin2010@gmail.com>
     */
      
    !function ($) {
      
     'use strict';
      
     $.extend($.fn.bootstrapTable.defaults, {
      editable: true,
      onEditableInit: function () {
       return false;
      },
      onEditableSave: function (field, row, oldValue, $el) {
       return false;
      },
      onEditableShown: function (field, row, $el, editable) {
       return false;
      },
      onEditableHidden: function (field, row, $el, reason) {
       return false;
      }
     });
      
     $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
      'editable-init.bs.table': 'onEditableInit',
      'editable-save.bs.table': 'onEditableSave',
      'editable-shown.bs.table': 'onEditableShown',
      'editable-hidden.bs.table': 'onEditableHidden'
     });
      
     var BootstrapTable = $.fn.bootstrapTable.Constructor,
      _initTable = BootstrapTable.prototype.initTable,
      _initBody = BootstrapTable.prototype.initBody;
      
     BootstrapTable.prototype.initTable = function () {
      var that = this;
      _initTable.apply(this, Array.prototype.slice.apply(arguments));
      
      if (!this.options.editable) {
       return;
      }
      
      $.each(this.columns, function (i, column) {
       if (!column.editable) {
        return;
       }
      
       var _formatter = column.formatter;
       column.formatter = function (value, row, index) {
        var result = _formatter ? _formatter(value, row, index) : value;
      
        return ['<a href="javascript:void(0)"',
         ' data-name="' + column.field + '"',
         ' data-pk="' + row[that.options.idField] + '"',
         ' data-value="' + result + '"',
         '>' + '</a>'
        ].join('');
       };
      });
     };
      
     BootstrapTable.prototype.initBody = function () {
      var that = this;
      _initBody.apply(this, Array.prototype.slice.apply(arguments));
      
      if (!this.options.editable) {
       return;
      }
      
      $.each(this.columns, function (i, column) {
       if (!column.editable) {
        return;
       }
      
       that.$body.find('a[data-name="' + column.field + '"]').editable(column.editable)
        .off('save').on('save', function (e, params) {
         var data = that.getData(),
          index = $(this).parents('tr[data-index]').data('index'),
          row = data[index],
          oldValue = row[column.field];
      
         row[column.field] = params.submitValue;
         that.trigger('editable-save', column.field, row, oldValue, $(this));
        });
       that.$body.find('a[data-name="' + column.field + '"]').editable(column.editable)
        .off('shown').on('shown', function (e, editable) {
         var data = that.getData(),
          index = $(this).parents('tr[data-index]').data('index'),
          row = data[index];
           
         that.trigger('editable-shown', column.field, row, $(this), editable);
        });
       that.$body.find('a[data-name="' + column.field + '"]').editable(column.editable)
        .off('hidden').on('hidden', function (e, reason) {
         var data = that.getData(),
          index = $(this).parents('tr[data-index]').data('index'),
          row = data[index];
           
         that.trigger('editable-hidden', column.field, row, $(this), reason);
        });
      });
      this.trigger('editable-init');
     };
      
    }(jQuery);

    这个js其实是对x-editable做了一个简单的封装,增加了列的editable属性以及编辑保存后的一些事件。有了这个作为基础,于是我们行内编辑的代码变成了这样。

    需要引用的文件如下: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <link href="/Content/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <link href="~/Content/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet" />
    <link href="/Content/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
      
    <script src="/Scripts/jquery-1.9.1.min.js"></script>
    <script src="/Content/bootstrap/js/bootstrap.min.js"></script>
    <script src="~/Content/bootstrap3-editable/js/bootstrap-editable.js"></script>
    <script src="~/Content/bootstrap-table/bootstrap-table.js"></script>
    <script src="/Content/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
    <script src="~/Content/bootstrap-table/extensions/editable/bootstrap-table-editable.js"></script>

    1、文本框 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
      $(function () {
      $("#tb_user").bootstrapTable({
       toolbar: "#toolbar",
       idField: "Id",
       pagination: true,
       showRefresh: true,
       search: true,
       clickToSelect: true,
       queryParams: function (param) {
        return {};
       },
       url: "/Editable/GetUsers",
       columns: [{
        checkbox: true
       }, {
        field: "UserName",
        title: "用户名",
        editable: {
         type: 'text',
         title: '用户名',
         validate: function (v) {
          if (!v) return '用户名不能为空';
      
         }
        }
       }, {
        field: "Age",
        title: "年龄",
       }, {
        field: "Birthday",
        title: "生日",
        formatter: function (value, row, index) {
         var date = eval('new ' + eval(value).source)
         return date.format("yyyy-MM-dd");
        }
       },
       {
        field: "DeptName",
        title: "部门"
       }, {
        field: "Hobby",
        title: "爱好"    
       }],
       onEditableSave: function (field, row, oldValue, $el) {
        $.ajax({
         type: "post",
         url: "/Editable/Edit",
         data: row,
         dataType: 'JSON',
         success: function (data, status) {
          if (status == "success") {
           alert('提交数据成功');
          }
         },
         error: function () {
          alert('编辑失败');
         },
         complete: function () {
      
         }
      
        });
       }
      });
     });

    后台对应的更新方法

    1
    2
    3
    4
    5
    6
    public JsonResult Edit(User user)
    {
     //更新实体
     
     return Json(new { }, JsonRequestBehavior.AllowGet);
    }

    经过测试,用户名这一列基本可以自由编辑。同样,年龄这一列也可改成这样 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
           {
        field: "Age",
        title: "年龄",
        editable: {
         type: 'text',
         title: '年龄',
         validate: function (v) {
          if (isNaN(v)) return '年龄必须是数字';
          var age = parseInt(v);
          if (age <= 0) return '年龄必须是正整数';
         }
        }
       }

    其他基本不用做任何修改。
     代码释疑:上文在初始化的columns属性里面通过editable属性来配置可编辑的参数,注意这里每个列的editable属性对应的Json对象即为x-editable里面的初始化的Json对象,也就是说我们初始化x-editable的时候可以配置哪些属性,在列的editable属性里面也可以同样配置,这样用起来就爽多了吧。编辑后的提交方法统一放到onEditableSave事件里面统一处理。

    2、时间选择框

    有了上面的知识作为基础,我们来初始化生日这一列: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
     field: "Birthday",
     title: "生日",
     formatter: function (value, row, index) {
      var date = eval('new ' + eval(value).source)
      return date.format("yyyy-MM-dd");
     },
     editable: {
      type: 'date',
      title: '生日'
     }
    }

    其他地方不用做任何修改,得到效果: 

    这是x-editable的默认样式,如果你看着不爽,可以自行配置,x-editable提供了许多配置日期框的参数,如下: 

    当然,如果精确到时分秒,可以使用datetime类型的编辑框。如下是官方给出的时间框编辑效果,看着还不错。

     

    3、下拉框 

    表单编辑里面还有一个重要的标签就是select了。上文我们知道x-editable为我们提供了下拉框的编辑模式,比如我们的部门这一列的编辑可以写成这样: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
           {
        field: "DeptId",
        title: "部门",
        editable: {
         type: 'select',
         title: '部门',
         source:[{value:"1",text:"研发部"},{value:"2",text:"销售部"},{value:"3",text:"行政部"}]
        }
       }

    得到效果

     

    当然,这种本地设置数据源的方法肯定是不能满足我们需求的,因为很多情况下拉框里面的选项是从数据库远程得到的。当然x-editable也为我们考虑到了,比如我们可以这样写: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    {
        field: "DeptId",
        title: "部门",
        editable: {
         type: 'select',
         title: '部门',
         source: function () {
          var result = [];
          $.ajax({
           url: '/Editable/GetDepartments',
           async: false,
           type: "get",
           data: {},
           success: function (data, status) {
            $.each(data, function (key, value) {
             result.push({ value: value.ID, text: value.Name });
            });
           }
          });
          return result;
         }
        }
       }

    后台我们配置一个方法 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public JsonResult GetDepartments()
    {
     var lstRes = new List<Department>();
     lstRes.Add(new Department() { ID = "1", Name = "研发部" });
     lstRes.Add(new Department() { ID = "2", Name = "销售部" });
     lstRes.Add(new Department() { ID = "3", Name = "行政部" });
     lstRes.Add(new Department() { ID = "4", Name = "创意部" });
     lstRes.Add(new Department() { ID = "5", Name = "事业部" });
     return Json(lstRes, JsonRequestBehavior.AllowGet);
    }

    同样能达到我们想要的结果。 

    代码释疑:这里有一点需要说明一下,细心的园友可能发现了,我们这里的 field: "DeptId" ,为什么这里要配置DeptId而不是DeptName呢?很简单,因为我们需要和数据源里面的value值对应。 

    4、复选框

    除了上述几种常见的编辑框,x-editable还为我们提供了复选框组的编辑。比如: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
        field: "Hobby",
        title: "爱好",
        editable: {
         type: "checklist",
         separator:",",
         source: [{ value: 'bsb', text: '篮球' },
           { value: 'ftb', text: '足球' },
           { value: 'wsm', text: '游泳' }],
        }
       }

    得到效果:

     

    当然,如果远程数据,也可以使用类似上文的方法去取。 

    5、“阴魂不散”的select2 

    说到上文的复选框,博主不由自主又想到了Multiselect这些个东西,于是查找x-editable的文档,结果发现它不支持Multiselect,但是支持select2,也不知道这是不是一个好消息。根据博主自己的使用经历,也包括技术交流群里面的聊天经历,发现很多人在使用select2的时候都遇到过各种各样的样式问题,并且不太好解决。 

    既然x-editable支持select2,那我们就用用试试呗,反正官方demo说得挺好的,下面是官方demo的使用示例:

     

    怀着忐忑的心情,博主自己尝试了一把。 

    引用select2文件

    1
    2
    3
    <link href="~/Content/select2-bootstrap.css" rel="stylesheet" />
    <link href="~/Content/select2-master/dist/css/select2.min.css" rel="stylesheet" />
    <script src="~/Content/select2-master/dist/js/select2.full.min.js"></script>

    代码尝试 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {
        field: "Hobby",
        title: "爱好",
        editable: {
         type: 'select2',
         title: '爱好',
         name: 'Hobby',
         placement: 'top',
         success: function (response, newValue) {
          debugger;
         },
         error: function(response, newValue) {
          debugger;
         },
         url: function(params) {
          debugger;
         },
         source: [{ id: 'bsb', text: '篮球' },
            { id: 'ftb', text: '足球' },
            { id: 'wsm', text: '游泳' }],
         inputclass: 'input-large',
         select2: {
          allowClear: true,
          multiple: true,
         
        }
       }

    得到结果:

    结果发现select2的选中值不能正常传递到后台。反正博主试过各种参数,按照官方demo的写法也试过,均以失败告终。也不知道官方的demo如何成功的。这个问题先抛出来,如果有使用的园友欢迎指正与解答。后续如果博主解决了这个问题,也会在此更新。  

    四、总结 

    还有一个问题就是在编辑完成提交之后,博主在项目中遇到这样一个问题:如果提交之后的文本内容过多,表格的thead里面th的宽度和tbody里面td的宽度不对其的问题,看着相当恶心。但是在写demo的时候又没有遇到这个问题。在此还是将解决方案给出来。

     

    就这么一句话解决你的困扰!

    参考:JS表格组件BootstrapTable行内编辑解决方案x-editable_javascript技巧_脚本之家
    https://www.jb51.net/article/91708.htm

     
  • 相关阅读:
    <<SQL Server 2005 高级程序设计>> 学习笔记(4)
    ASP.NET发布网站的二个小问题总结
    Android AlertDialog 实例
    SQL2005 导入其它服务器数据
    Android sysout.exit(0) 和finish()区别
    <<SQL Server 2005 高级程序设计>> 学习笔记(3)
    ASP.NET上传多个文件
    <<SQL Server 2005 高级程序设计>> 学习笔记(1)
    SurfaceView 间取得焦点
    图像处理类
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/9559814.html
Copyright © 2020-2023  润新知