BootstrapTable+KnockoutJS

BootstrapTable+KnockoutJS实现增删改查解决方案(三):两个Viewmodel搞定增删改查

前言:之前博主分享过knockoutJS和BootstrapTable的一些基础用法,都是写基础应用,根本谈不上封装,仅仅是避免了html控件的取值和赋值,远远没有将MVVM的精妙展现出来。最近项目打算正式将ko用起来,于是乎对ko和bootstraptable做了一些封装,在此分享出来供园友们参考。封装思路参考博客园大神萧秦,如果园友们有更好的方法,欢迎讨论。

KnockoutJS系列文章:

本文原创地址:http://www.cnblogs.com/landeanfen/p/5656307.html

一、第一个viewmodel搞定查询

demo的实现还是延续上次的部门管理功能。以下展开通过数据流向来说明。

1、后台向View返回viewmodel的实现

        public ActionResult Index()
        {
            var model = new
            {
                tableParams = new
                {
                    url = "/Department/GetDepartment",
                    //pageSize = 2,
                },
                urls = new
                {
                    delete = "/Department/Delete",
                    edit = "/Department/Edit",
                    add = "/Department/Edit",
                },
                queryCondition = new
                {
                    name = "",
                    des = ""
                }
            };
            return View(model);
        }

代码释疑:这里返回的model包含三个选项

  • tableParams:页面表格初始化参数。由于js里面定义了默认参数,所以这里设置的参数是页面特定的初始化参数。
  • urls:包含增删改请求的url路径。
  • queryCondition:页面的查询条件。

2、cshtml页面代码

Index.cshtml页面代码如下:

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>

    <link href="~/Content/bootstrap/css/bootstrap.min.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/bootstrap-table/bootstrap-table.min.js"></script>
    <script src="~/Content/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>

    <script src="~/scripts/knockout/knockout-3.4.0.min.js"></script>
    <script src="~/scripts/knockout/extensions/knockout.mapping-latest.js"></script>
    <script src="~/scripts/extensions/knockout.index.js"></script>
    <script src="~/scripts/extensions/knockout.bootstraptable.js"></script><script type="text/javascript">
        $(function(){
            var data = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));
            ko.bindingViewModel(data, document.getElementById("div_index"));
        });

    </script>
</head>
<body>
    <div id="div_index" class="panel-body" style="padding:0px;overflow-x:hidden;">
        <div class="panel panel-default">
            <div class="panel-heading">查询条件</div>
            <div class="panel-body">
                <form id="formSearch" class="form-horizontal">
                    <div class="form-group">
                        <label class="control-label col-xs-1">部门名称</label>
                        <div class="col-xs-3">
                            <input type="text" class="form-control" data-bind="value:queryCondition.name">
                        </div>
                        <label class="control-label col-xs-1">部门描述</label>
                        <div class="col-xs-3">
                            <input type="text" class="form-control" data-bind="value:queryCondition.des">
                        </div>
                        <div class="col-xs-4" style="text-align:right;">
                            <button type="button"data-bind="click:clearClick" class="btn">清空</button>
                            <button type="button"data-bind="click:queryClick" class="btn btn-primary">查询</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
        <div id="toolbar" class="btn-group">
            <button data-bind="click:addClick" type="button" class="btn btn-default">
                <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
            </button>
            <button data-bind="click:editClick" type="button" class="btn btn-default">
                <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改
            </button>
            <button data-bind="click:deleteClick" type="button" class="btn btn-default">
                <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除
            </button>
        </div>
        <table data-bind="bootstrapTable:bootstrapTable">
            <thead>
                <tr>
                    <th data-checkbox="true"></th>
                    <th data-field="Name">部门名称</th>
                    <th data-field="Level">部门级别</th>
                    <th data-field="Des">描述</th>
                    <th data-field="strCreatetime">创建时间</th>
                </tr>
            </thead>
        </table>
    </div>

</body>
</html>

代码释疑:和上篇一样,需要引用JQuery、bootstrap、bootstraptable、knockout等相关文件。这里重点说明下两个文件:

  • knockout.index.js:封装了查询页面相关的属性和事件绑定。
  • knockout.bootstraptable.js:封装了bootstrapTable的初始化和自定义knockout绑定的方法。

以上所有的页面交互都封装在了公共js里面,这样就不用在页面上面写大量的DOM元素取赋值、事件的绑定等重复代码,需要在本页面写的js只有以上两句,是不是很easy。

3、JS封装

重点来看看上面的说的两个js文件knockout.bootstraptable.js和knockout.index.js。

(1)knockout.bootstraptable.js

(function ($) {
    //向ko里面新增一个bootstrapTableViewModel方法
    ko.bootstrapTableViewModel = function (options) {
        var that = this;

        this.default = {
            toolbar: ‘#toolbar‘,                //工具按钮用哪个容器
            queryParams: function (param) {
                return { limit: param.limit, offset: param.offset };
            },//传递参数(*)
            pagination: true,                   //是否显示分页(*)
            sidePagination: "server",           //分页方式:client客户端分页,server服务端分页(*)
            pageNumber: 1,                      //初始化加载第一页,默认第一页
            pageSize: 10,                       //每页的记录行数(*)
            pageList: [10, 25, 50, 100],        //可供选择的每页的行数(*)
            method: ‘get‘,
            search: true,                       //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
            strictSearch: true,
            showColumns: true,                  //是否显示所有的列
            cache:false,
            showRefresh: true,                  //是否显示刷新按钮
            minimumCountColumns: 2,             //最少允许的列数
            clickToSelect: true,                //是否启用点击选中行
            showToggle: true,
        };
        this.params = $.extend({}, this.default, options || {});

        //得到选中的记录
        this.getSelections = function () {
            var arrRes = that.bootstrapTable("getSelections")
            return arrRes;
        };

        //刷新
        this.refresh = function () {
            that.bootstrapTable("refresh");
        };

    };

    //添加ko自定义绑定
    ko.bindingHandlers.bootstrapTable = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            //这里的oParam就是绑定的viewmodel
            var oViewModel = valueAccessor();
            var $ele = $(element).bootstrapTable(oViewModel.params);
            //给viewmodel添加bootstrapTable方法
            oViewModel.bootstrapTable = function () {
                return $ele.bootstrapTable.apply($ele, arguments);
            }
        },

        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {

        }
    };
})(jQuery);

代码释疑:上面代码主要做了两件事

  1. 自定义了bootstrapTable初始化的ViewModel。
  2. 添加ko自定义绑定。

如果园友不理解自定义绑定的使用,可以看看博主的前两篇博文(一)(二),有详细介绍。

(2)knockout.index.js

(function ($) {
    ko.bindingViewModel = function (data, bindElement) {

        var self = this;

        this.queryCondition = ko.mapping.fromJS(data.queryCondition);
        this.defaultQueryParams = {
            queryParams: function (param) {
                var params = self.queryCondition;
                params.limit = param.limit;
                params.offset = param.offset;
                return params;
            }
        };

        var tableParams = $.extend({}, this.defaultQueryParams, data.tableParams || {});
        this.bootstrapTable = new ko.bootstrapTableViewModel(tableParams);

        //清空事件
        this.clearClick = function () {
            $.each(self.queryCondition, function (key, value) {
                //只有监控属性才清空
                if (typeof (value) == "function") {
                    this(‘‘); //value(‘‘);
                }
            });
            self.bootstrapTable.refresh();
        };

        //查询事件
        this.queryClick = function () {
            self.bootstrapTable.refresh();
        };

        //新增事件
        this.addClick = function () {
            var dialog = $(‘<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>‘);
            dialog.load(data.urls.edit, null, function () { });

            $("body").append(dialog);
            dialog.modal().on(‘hidden.bs.modal‘, function () {
                //关闭弹出框的时候清除绑定(这个清空包括清空绑定和清空注册事件)
                ko.cleanNode(document.getElementById("formEdit"));
                dialog.remove();
                self.bootstrapTable.refresh();
            });
        };

        //编辑事件
        this.editClick = function () {
            var arrselectedData = self.bootstrapTable.getSelections();
            if (arrselectedData.length <= 0 || arrselectedData.length > 1) {
                alert("每次只能编辑一行");
                return;
            }
            var dialog = $(‘<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>‘);
            dialog.load(data.urls.edit, arrselectedData[0], function () { });

            $("body").append(dialog);
            dialog.modal().on(‘hidden.bs.modal‘, function () {
                //关闭弹出框的时候清除绑定(这个清空包括清空绑定和清空注册事件)
                ko.cleanNode(document.getElementById("formEdit"));
                dialog.remove();
                self.bootstrapTable.refresh();
            });
        };

        //删除事件
        this.deleteClick = function () {
            var arrselectedData = self.bootstrapTable.getSelections();
            if (!arrselectedData||arrselectedData.length<=0) {
                alert("请至少选择一行");
                return;
            }
            $.ajax({
                url: data.urls.delete,
                type: "post",
                contentType: ‘application/json‘,
                data: JSON.stringify(arrselectedData),
                success: function (data, status) {
                    alert(status);
                    self.bootstrapTable.refresh();
                }
            });
        };

        ko.applyBindings(self, bindElement);
    };
})(jQuery);

代码释疑:这个js主要封装了页面元素的属性和事件绑定,需要说明的几个地方

  • this.queryCondition = ko.mapping.fromJS(data.queryCondition):这一句的作用是将后台传过来的查询条件,从JSON数据转换成监控属性。只有执行了这一句,属性和页面元素才能双向监控。
  • self.bootstrapTable.refresh():这一句的含义是刷新表格数据,它实际上是调用的bootstrapTable的refresh方法,只不过博主在knockout.bootstraptable.js文件里面对它进行了简单封装。
  • dialog.load(data.urls.edit, null, function () { }):在新增和编辑的时候使用了jQuery的load()方法,这个方法的作用是请求这个url的页面元素,并执行url对应页面的js代码。此方法在动态引用js文件并执行js文件里面代码这方面功能很强大。

最后附上后台GetDepartment()方法对应的代码

        [HttpGet]
        public JsonResult GetDepartment(int limit, int offset, string name, string des)
        {
            var lstRes = DepartmentModel.GetData();
            if (!string.IsNullOrEmpty(name))
            {
                lstRes = lstRes.Where(x => x.Name.Contains(name)).ToList();
            }
            if (!string.IsNullOrEmpty(des))
            {
                lstRes = lstRes.Where(x => x.Des.Contains(des)).ToList();
            }
            lstRes.ForEach(x=> {
                x.strCreatetime = x.Createtime.ToString("yyyy-MM-dd HH:mm:ss");
            });
            var oRes = new
            {
                rows = lstRes.Skip(offset).Take(limit).ToList(),
                total = lstRes.Count
            };
            return Json(oRes, JsonRequestBehavior.AllowGet);
        }

至此,查询页面的查询、清空功能即可实现。

你是否还有一个疑问:如果我们需要自定义bootstrapTable的事件怎么办?不能通过后台的viewmodel传过来吧?

确实,从后台是无法传递js事件方法的,所以需要我们在前端自定义事件的处理方法,比如我们可以这样:

<script type="text/javascript">
        $(function(){
            var data = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));
            data.tableParams.onLoadSuccess = function(data){          alert("加载成功事件");       };
            ko.bindingViewModel(data, document.getElementById("div_index"));
        });

    </script>

二、第二个viewmodel搞定编辑

上面的一个viewmodel搞定了查询和删除的功能,但是新增和编辑还需要另一个viewmodel的支持。下面来看看编辑的封装实现。

1、ActionResult的实现

通过上面查询的代码我们可以知道,当用户点击新增和编辑的时候,会请求另一个View视图→/Department/Edit。下面来看看Edit视图的实现

    public ActionResult Edit(Department model)
        {
            var oResModel = new
            {
                editModel = model,
                urls = new
                {
                    submit = model.id == 0 ? "/Department/Add" : "/Department/Update"
                }
            };
            return View(oResModel);
        }

代码释疑:上述代码很简单,就是向视图页面返回一个viewmodel,包含编辑的实体和提交的url。通过这个实体主键是否存在来判断当前提交是新增实体还是编辑实体。

2、cshtml代码

Edit.cshtml代码如下:

<form id="formEdit">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title" id="myModalLabel">操作</h4>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label for="txt_departmentname">部门名称</label>
                    <input type="text" name="txt_departmentname" data-bind="value:editModel.Name" class="form-control" placeholder="部门名称">
                </div>
                <div class="form-group">
                    <label for="txt_departmentlevel">部门级别</label>
                    <input type="text" name="txt_departmentlevel" data-bind="value:editModel.Level" class="form-control" placeholder="部门级别">
                </div>
                <div class="form-group">
                    <label for="txt_des">描述</label>
                    <input type="text" name="txt_des" data-bind="value:editModel.Des" class="form-control" placeholder="描述">
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>关闭</button>
                <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
            </div>
        </div>
    </div>
</form>
<link href="~/Content/bootstrapValidator/css/bootstrapValidator.css" rel="stylesheet" />
<script src="~/Content/bootstrapValidator/js/bootstrapValidator.js"></script>
<script src="~/scripts/extensions/knockout.edit.js"></script>
<script type="text/javascript">
    $(function () {
     var editData = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));
        ko.bindingEditViewModel(editData, {});
    });
</script>

代码释疑:由于我们加了验证组件bootstrapValidator,所以需要引用相关js和css。knockout.edit.js这个文件主要封装了编辑页面的属性和事件绑定。重点来看看这个js的实现代码。

3、js封装

knockout.edit.js代码:

(function ($) {
    ko.bindingEditViewModel = function (data, validatorFields) {

        var that = {};

        that.editModel = ko.mapping.fromJS(data.editModel);

        that.default = {
            message: ‘验证不通过‘,
            fields: { },
            submitHandler: function (validator, form, submitButton) {
                var arrselectedData = ko.toJS(that.editModel);
                $.ajax({
                    url: data.urls.submit,
                    type: "post",
                    contentType: ‘application/json‘,
                    data: JSON.stringify(arrselectedData),
                    success: function (data, status) {
                        alert(status);
                    }
                });
                $("#myModal").modal("hide");
            }
        };
        that.params = $.extend({}, that.default, {fields: validatorFields} || {});
        $(‘#formEdit‘).bootstrapValidator(that.params);
        ko.applyBindings(that, document.getElementById("formEdit"));
    };

})(jQuery);

代码释疑:这个js主要封装了编辑模型的属性和提交的事件绑定。由于用到了bootstrapValidator验证组件,所以需要表单提交。其实公共js里面是不应该出现页面id的,比如上面的“formEdit”和“myModal”,可以将此作为参数传过来,这点有待优化。参数validatorFields表示验证组件的验证字段,如果表单不需要验证,则传一个空的Json或者不传都行。上文我们没有做字段验证,其实一般来说,基础表都会有一个或者几个非空字段,比如我们可以加上部门名称的非空验证。在Edit.cshtml页面的代码改成这样:

<form id="formEdit">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title" id="myModalLabel">操作</h4>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label for="txt_departmentname">部门名称</label>
                    <input type="text" name="Name" data-bind="value:editModel.Name" class="form-control" placeholder="部门名称">
                </div>
                <div class="form-group">
                    <label for="txt_departmentlevel">部门级别</label>
                    <input type="text" name="Level" data-bind="value:editModel.Level" class="form-control" placeholder="部门级别">
                </div>
                <div class="form-group">
                    <label for="txt_des">描述</label>
                    <input type="text" name="Des" data-bind="value:editModel.Des" class="form-control" placeholder="描述">
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>关闭</button>
                <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
            </div>
        </div>
    </div>
</form>
<link href="~/Content/bootstrapValidator/css/bootstrapValidator.css" rel="stylesheet" />
<script src="~/Content/bootstrapValidator/js/bootstrapValidator.js"></script>
<script src="~/scripts/extensions/knockout.edit.js"></script>
<script type="text/javascript">
    $(function () {
     var editData = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));
        ko.bindingEditViewModel(editData, {
            Name: {
                validators: {
                    notEmpty: {
                        message: ‘名称不能为空!‘
                    }
                }
            }
        });
    });

</script>

那么就会在提交的时候自动进行验证:

注意:验证属性Name对应的是input标签的name属性,所以要做验证,这个name属性必须设置正确。

最好附上增删改的后台方法:

        [HttpPost]
        public JsonResult Add(Department oData)
        {
            DepartmentModel.Add(oData);
            return Json(new { }, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public JsonResult Update(Department oData)
        {
            DepartmentModel.Update(oData);
            return Json(new { }, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public JsonResult Delete(List<Department> oData)
        {
            DepartmentModel.Delete(oData);
            return Json(new { }, JsonRequestBehavior.AllowGet);
        }

至此,我们整个页面的增删改查效果就OK了,简单看下效果:

三、总结

以上简单封装了bootstrapTable+ko的增删改查业务,只是一个最初级的封装。如果你需要将这些运用都你的项目中,可能还需要一些简单的优化措施,比如:

1、如果单纯是一个页面的viewmodel,是否可以不用从后台的ActionResult里面返回,直接写在View页面里面感觉更好,省去了序列化和参数传递的问题。这点有待优化。

2、公共js里面不应该出现页面元素的id,可以通过参数将页面元素传递进来。

3、新增和编辑事件方法里面弹出框的部分有很多重复代码,这部分的最好做法是将弹出框封装成一个单独的组件去调用,可以减少大部分的js代码。

4、如果查询条件以及编辑的属性里面存在select下拉框元素,可能还需要封装下拉框的datasourse等属性,这一部分是非常常见的,等博主整理好demo后将这块加进去。

可能你要说,对于单表的增删改查,实际项目中能有多少。确实,项目中大部分的业务是跨表的,但是,如果根据你的业务去建立对应的viewmodel,那么上述封装还是能起到一定简化代码的作用。还是那句话,你的需求决定了你的封装思路。如果你觉得本文能够帮到你,可以打赏博主,也可以推荐下,博主一定继续努力!

欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利

时间: 2024-08-05 07:08:43

BootstrapTable+KnockoutJS的相关文章

BootstrapTable+KnockoutJS实现增删改查解决方案

BootstrapTable+KnockoutJS实现增删改查解决方案 前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4的语法,虽然没有完全掌握,但是算是有了一个大致的了解.于是乎有了今天的这篇文章:通过T4模板快速生成页面. KnockoutJS系列文章: JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(

JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(三):两个Viewmodel搞定增删改查

前言:之前博主分享过knockoutJS和BootstrapTable的一些基础用法,都是写基础应用,根本谈不上封装,仅仅是避免了html控件的取值和赋值,远远没有将MVVM的精妙展现出来.最近项目打算正式将ko用起来,于是乎对ko和bootstraptable做了一些封装,在此分享出来供园友们参考.封装思路参考博客园大神萧秦,如果园友们有更好的方法,欢迎讨论. KnockoutJS系列文章: JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(一) JS组件

JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(二)

前言:上篇 JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(一) 介绍了下knockout.js的一些基础用法,由于篇幅的关系,所以只能分成两篇,望见谅!昨天就觉得应该快点完成下篇,要不然有点标题党的感觉,思及此,博主心有不安,于是加班赶出了下篇.如果你也打算用ko去做项目,且看看吧! 一.效果预览 其实也没啥效果,就是简单的增删改查,重点还是在代码上面,使用ko能够大量节省界面DOM数据绑定的操作.下面是整个整个增删改查逻辑的js代码: 页面效果: 二.

BootstrapTable+KnockoutJS自定义T4模板快速生成增删改查页面

前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4的语法,虽然没有完全掌握,但是算是有了一个大致的了解.于是乎有了今天的这篇文章:通过T4模板快速生成页面. KnockoutJS系列文章: JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(一) JS组件系列——BootstrapTable+KnockoutJS

JS组件系列——KnockoutJS用法

前言:出于某种原因,需要学习下Knockout.js,这个组件很早前听说过,但一直没尝试使用,这两天学习了下,觉得它真心不错,双向绑定的机制简直太爽了.今天打算结合bootstrapTable和Knockout去实现一个简单的增删改查,来体验一把神奇的MVVM.关于WebApi的剩余部分,博主一定抽时间补上. 一.Knockout.js简介 1.Knockout.js和MVVM 如今,各种前端框架应接不暇,令人眼花缭乱,有时不得不感叹作为程序猿也真是苦逼,总有学不完的技术,何时是尽头,除非你转化

使用插件bootstrap-table实现表格记录的查询、分页、排序等处理

在业务系统开发中,对表格记录的查询.分页.排序等处理是非常常见的,在Web开发中,可以采用很多功能强大的插件来满足要求,且能极大的提高开发效率,本随笔介绍这个bootstrap-table是一款非常有名的开源表格插件,在很多项目中广泛的应用.Bootstrap-table插件提供了非常丰富的属性设置,可以实现查询.分页.排序.复选框.设置显示列.Card view视图.主从表显示.合并列.国际化处理等处理功能,而且该插件同时也提供了一些不错的扩展功能,如移动行.移动列位置等一些特殊的功能,插件可

扩展BootstrapTable的treegrid功能

扩展BootstrapTable的treegrid功能 阅读目录 一.效果预览 二.代码示例 三.组件需要完善的地方 四.总结 正文 前言:上篇  JS组件系列--自己动手封装bootstrap-treegrid组件 博主自己动手封装了下treegrid的功能,但毕竟那个组件只是一个单独针对树形表格做的,适用性还比较有限.关注博主的园友应该知道,博主的博客里面写了很多bootstrapTable的扩展,今天打算在直接在bootstrapTable的基础上扩展一个treegrid的功能,很多长期关

KnockOutJs初次体验

最近忙着一个项目的上线,突然想起好久没上博客园了 跑进来看了一下,好像已经过了有四个月了 想想也是过了蛮久了,所以进来发表一点什么东西 偶然机会看了一个叫KnockOutJs的东西,体验了一下,觉得还是蛮好玩的 首先引用官方的knockoutjs,然后写上js代码 var ViewModel = function(first, middle,last) { this.firstName = ko.observable(first); this.middleName=ko.observable(m

bootstraptable表格基本

function tableint(){   $("#tableFromData").bootstrapTable({    url:BASE_URL+"/do/front/main_xp.do",//请求后台的URL(*)    striped: true,//是否显示行间隔色    cache: false,                       //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)    pagination: tr