BootstrapTable与KnockoutJS相结合实现增删改查功能【二】


Posted in Javascript onMay 10, 2016

在上篇文章给大家介绍了BootstrapTable与KnockoutJS相结合实现增删改查功能【一】,介绍了下knockout.js的一些基础用法。接下来通过本文继续给大家介绍。如果你也打算用ko去做项目,且看看吧!

Bootstrap是一个前端框架,解放Web开发者的好东东,展现出的UI非常高端大气上档次,理论上可以不用写一行css。只要在标签中加上合适的属性即可。

KnockoutJS是一个JavaScript实现的MVVM框架。非常棒。比如列表数据项增减后,不需要重新刷新整个控件片段或自己写JS增删节点,只要预先定义模板和符合其语法定义的属性即可。简单的说,我们只需要关注数据的存取。

一、效果预览

其实也没啥效果,就是简单的增删改查,重点还是在代码上面,使用ko能够大量节省界面DOM数据绑定的操作。下面是整个整个增删改查逻辑的js代码:

BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

页面效果:

BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

二、代码示例

好了,进入重点吧!博主打算分两块介绍,第一部分是表格初始化部分,第二部分是按钮操作增删改部分。

1、表格初始化

1.1、准备工作

首先看看需要引用的js和css文件

<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="~/Content/bootstrap-table/knockout.bootstraptable.js"></script>
<script src="~/scripts/Department.js"></script>

都是一些常用的css和js文件,我们自定义的js文件主要有两个: knockout.bootstraptable.js 和 Department.js 。上篇我们介绍过使用ko可以自定义我们的data-bind。同样,这里对于table的绑定,我们也定义一个自定义的绑定,代码 knockout.bootstraptable.js 里面。

//添加ko自定义绑定
ko.bindingHandlers.myBootstrapTable = {
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) {}
};
//初始化
(function ($) {
//向ko里面新增一个bootstrapTableViewModel方法
ko.bootstrapTableViewModel = function (options) {
var that = this;
this.default = {
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");
};
};
})(jQuery);

代码释疑:这个js文件主要做了两件事

1.自定义data-bind属性myBootstrapTable。对于ko.bindingHandlers.myBootstrapTable里面的update方法,如非必须,可以不用定义。

2.通过向ko对象里面添加bootstrapTableViewModel来封装bootstrapTable。

1.2、html标签启动绑定

<table id="tb_dept" data-bind="myBootstrapTable:$root">
<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>

代码释疑:定义一个table标签,使用自定义绑定myBootstrapTable,上篇说过,$root可以理解为初始化的意思。为了简单,所有的colums就直接在<th>里面写了。

1.3、激活ko的绑定

在页面加载完成之后,启动ko的绑定:

//初始化
$(function () {
//1、初始化表格
tableInit.Init();
//2、注册增删改事件
operate.operateInit();
});
//初始化表格
var tableInit = {
Init: function () {
//绑定table的viewmodel
this.myViewModel = new ko.bootstrapTableViewModel({
url: '/Department/GetDepartment', //请求后台的URL(*)
method: 'get', //请求方式(*)
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], //可供选择的每页的行数(*)
});
ko.applyBindings(this.myViewModel, document.getElementById("tb_dept"));
}
};

代码释疑:页面加载完成之后,调用上面封装的bootstrapTableViewModel对象合并传递的参数,最后激活绑定,将this.myViewModel作为绑定的viewmodel激活。调试代码可知,当执行到 ko.applyBindings(this.myViewModel, document.getElementById("tb_dept")); 这一句的时候,自定义绑定才会生效,程序才会进入到 ko.bindingHandlers.myBootstrapTable 对象的init方法去初始化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);
}
}

上文中的init方法,通过第二个参数valueAccessor,我们得到的是当前绑定的viewmodel,也就是我们上面的this.myViewModel这个对象,博主觉得这一点有利于你理解自定义绑定的逻辑。基本上执行到 var $ele = $(element).bootstrapTable(oViewModel.params); 这一句的时候,我们表格的初始化就完成了。后台对应的方法博主随便定义了一个集合,为了完整,这里还是贴出来:

DepartmentController

2、按钮操作

上面通过bootstrapTable的初始化完成了我们的自定义data-bind的使用。下面的按钮操作我们来体验一把使用监控属性的“爽歪歪”。

2.1、view页面

首先在view页面上面定义我们的增删改按钮

<div id="toolbar" class="btn-group">
<button id="btn_add" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
</button>
<button id="btn_edit" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改
</button>
<button id="btn_delete" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除
</button>
</div>

为了简便,博主使用了一个隐藏的弹出框用来包含新增和编辑的文本框。当然,一般情况下,可能这里用的是部分视图,你的项目里面可能会有一个Edit.cshtml,但这里博主将这些都放在一个页面上面,因为这不是文本的重点。

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<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">×</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:Name" class="form-control" id="txt_departmentname" placeholder="部门名称">
</div>
<div class="form-group">
<label for="txt_departmentlevel">部门级别</label>
<input type="text" name="txt_departmentlevel" data-bind="value:Level" class="form-control" id="txt_departmentlevel" placeholder="部门级别">
</div>
<div class="form-group">
<label for="txt_des">描述</label>
<input type="text" name="txt_des" data-bind="value:Des" class="form-control" id="txt_des" 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="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
</div>
</div>
</div>
</div>

2.2、JS初始化按钮操作

//操作
var operate = {
//初始化按钮事件
operateInit: function () {
this.operateAdd();
this.operateUpdate();
this.operateDelete();
this.DepartmentModel = {
id: ko.observable(),
Name: ko.observable(),
Level: ko.observable(),
Des: ko.observable(),
CreateTime: ko.observable()
};
},
//新增
operateAdd: function(){
$('#btn_add').on("click", function () {
$("#myModal").modal().on("shown.bs.modal", function () {
var oEmptyModel = {
id: ko.observable(),
Name: ko.observable(),
Level: ko.observable(),
Des: ko.observable(),
CreateTime: ko.observable()
};
ko.utils.extend(operate.DepartmentModel, oEmptyModel);
ko.applyBindings(operate.DepartmentModel, document.getElementById("myModal"));
operate.operateSave();
}).on('hidden.bs.modal', function () {
ko.cleanNode(document.getElementById("myModal"));
});
});
},
//编辑
operateUpdate: function () {
$('#btn_edit').on("click", function () {
$("#myModal").modal().on("shown.bs.modal", function () {
var arrselectedData = tableInit.myViewModel.getSelections();
if (!operate.operateCheck(arrselectedData)) { return; }
//将选中该行数据有数据Model通过Mapping组件转换为viewmodel
ko.utils.extend(operate.DepartmentModel, ko.mapping.fromJS(arrselectedData[0]));
ko.applyBindings(operate.DepartmentModel, document.getElementById("myModal"));
operate.operateSave();
}).on('hidden.bs.modal', function () {
//关闭弹出框的时候清除绑定(这个清空包括清空绑定和清空注册事件)
ko.cleanNode(document.getElementById("myModal"));
});
});
},
//删除
operateDelete: function () {
$('#btn_delete').on("click", function () {
var arrselectedData = tableInit.myViewModel.getSelections();
$.ajax({
url: "/Department/Delete",
type: "post",
contentType: 'application/json',
data: JSON.stringify(arrselectedData),
success: function (data, status) {
alert(status);
//tableInit.myViewModel.refresh();
}
});
});
},
//保存数据
operateSave: function () {
$('#btn_submit').on("click", function () {
//取到当前的viewmodel
var oViewModel = operate.DepartmentModel;
//将Viewmodel转换为数据model
var oDataModel = ko.toJS(oViewModel);var funcName = oDataModel.id?"Update":"Add";
$.ajax({
url: "/Department/"+funcName,
type: "post",
data: oDataModel,
success: function (data, status) {
alert(status);
tableInit.myViewModel.refresh();
}
});
});
},
//数据校验
operateCheck:function(arr){
if (arr.length <= 0) {
alert("请至少选择一行数据");
return false;
}
if (arr.length > 1) {
alert("只能编辑一行数据");
return false;
}
return true;
}
}

代码释疑:说说这里的执行逻辑,首先在$(function(){})方法里面调用 operate.operateInit(); 。在operateInit()方法里面注册页面上面按钮的点击事件,同时也定义 this.DepartmentModel 作为我们新增编辑的viewmodel,这个viewmodel里面定义了和页面元素对应的监控属性。还记得上面隐藏的弹出框里面的一些data-bind吗,没错,里面对应的value值就是和这里的监控属性对应,这样设置绑定之后,js里面所有的导致 this.DepartmentModel 里面监控的变化,都会触发界面上面这些绑定标签的value值变化,反之,界面上面的所有标签的Value值的变化,也势必会引起它的监控属性值的变化,此之所谓双向绑定。下面具体看看双向绑定的执行。

2.3、新增操作

$('#btn_add').on("click", function () {
$("#myModal").modal().on("shown.bs.modal", function () {
var oEmptyModel = {
id: ko.observable(),
Name: ko.observable(),
Level: ko.observable(),
Des: ko.observable(),
CreateTime: ko.observable()
};
ko.utils.extend(operate.DepartmentModel, oEmptyModel);
ko.applyBindings(operate.DepartmentModel, document.getElementById("myModal"));
operate.operateSave();
}).on('hidden.bs.modal', function () {
ko.cleanNode(document.getElementById("myModal"));
});
});

当我们界面触发新增操作的时候,首先会弹出上面说的隐藏模态框。在模态框显示的时候,首先定义一个空的viewmodel,然后调用 ko.utils.extend(operate.DepartmentModel, oEmptyModel); 这一句,将全局的operate.DepartmentModel被空的viewmodel覆盖。ko.utils.extend()这个方法的作用和jquery里面的$.extend()作用类似,都是根据后面对象合并前面对象,合并之后,使用新的viewmodel激活绑定。激活绑定之后,注册保存按钮的click事件。这样新增的时候,弹出模态框,由于viewmodel里面的监控属性都是空的,对应界面元素的value也会被清空,所以新增我们看到是这样:

BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

当弹出框关闭后,我们通过关闭的事件,执行 ko.cleanNode(document.getElementById("myModal")); 这一句,这个很重要,因为对于同一个dom,ko只能绑定一次,如果需要再次绑定,需要先清空绑定,并且cleanNode()这个方法,它不仅会清空绑定,还是会dom里面注册的事件也会清空,使用的时候需要注意下!

2.4、编辑操作

$('#btn_edit').on("click", function () {
$("#myModal").modal().on("shown.bs.modal", function () {
var arrselectedData = tableInit.myViewModel.getSelections();
if (!operate.operateCheck(arrselectedData)) { return; }
//将选中该行数据有数据Model通过Mapping组件转换为viewmodel
ko.utils.extend(operate.DepartmentModel, ko.mapping.fromJS(arrselectedData[0]));
ko.applyBindings(operate.DepartmentModel, document.getElementById("myModal"));
operate.operateSave();
}).on('hidden.bs.modal', function () {
//关闭弹出框的时候清除绑定(这个清空包括清空绑定和清空注册事件)
ko.cleanNode(document.getElementById("myModal"));
});
});

当我们触发编辑操作的时候,界面还是弹出框。在弹出框的弹出事件里面,我们取到当前选中的行,然后校验是否选中了一行。最好通过 ko.mapping.fromJS(arrselectedData[0]) 这一句,将普通的Json对象转换为带有监控属性的viewmodel,上篇说过,这个方法需要 knockout.mapping-latest.js 这个js文件的支持。转换之后,还是通过ko.utils.extend()方法更新viewmodel,然后激活绑定。由于viewmodel被当前选中行的数据更新了,所以得到结果:

BootstrapTable与KnockoutJS相结合实现增删改查功能【二】

2.5、保存操作

在新增和编辑弹出框之后,修改相关信息后点击保存,就会触发保存事件。

$('#btn_submit').on("click", function () {
//取到当前的viewmodel
var oViewModel = operate.DepartmentModel;
//将Viewmodel转换为数据model
var oDataModel = ko.toJS(oViewModel);
var funcName = oDataModel.id?"Update":"Add";
$.ajax({
url: "/Department/"+funcName,
type: "post",
data: oDataModel,
success: function (data, status) {
alert(status);
tableInit.myViewModel.refresh();
}
});
});

当触发保存事件的时候,我们首先取到页面绑定的viewmodel,即operate.DepartmentModel,然后使用ko.toJS()方法将带有监控属性的viewmodel转换为纯数据的Json对象,这个方法是ko内置的,不需要其他js支持。得到json对象之后,发送ajax请求,去新增或者编辑数据。这样就很好地体现了双向绑定,界面上面所有文本框的value发生了变化之后,也会触发operate.DepartmentModel的变化。

2.6、删除操作

删除操作没什么好说的,和ko关系不大。

三、总结

以上通过一个简单的增删改查操作,介绍了下ko和bootstrapTable的联合使用。ko可以让你从DOM中解放出来,把关注点放在viewmodel上面。纵观整个js代码,几乎看不到jquery的val()、text()等对界面dom做取值和赋值的操作,是不是看着干净清爽,并且高大上了呢~~当然,这或许只是ko的一些比较基础的用法,毕竟博主学习ko才3天,更多高级用法还有待摸索,等过段时间用熟了,再将它的一些高级用法分享给大家。如果你觉得本文能够帮助你理解ko的原理以及它的一些用法,不妨推荐下,小编在此感激不尽!

以上所述是小编给大家介绍的BootstrapTable与KnockoutJS相结合实现增删改查功能【二】的全部内容,希望对大家有所帮助!

Javascript 相关文章推荐
javascript &amp;&amp;和||运算法的另类使用技巧
Nov 28 Javascript
js监听输入框值的即时变化onpropertychange、oninput
Jul 13 Javascript
JavaScript中“+”的陷阱深刻理解
Dec 04 Javascript
jquery的总体架构分析及实现示例详解
Nov 08 Javascript
javascript跨域方法、原理以及出现问题解决方法(详解)
Aug 06 Javascript
javascript跨域的方法汇总
Oct 23 Javascript
使用微信内置浏览器点击下拉框出现页面乱跳转现象(iphone),该怎么办
Jan 04 Javascript
jQuery中用on绑定事件时需注意的事项
Mar 19 Javascript
Angular使用cli生成自定义文件、组件的方法
Sep 04 Javascript
vue实现todolist基本功能以及数据存储功能实例详解
Apr 11 Javascript
使用js原生实现年份轮播选择效果实例
Jan 12 Javascript
vue element和nuxt的使用技巧分享
Jan 14 Vue.js
JS实现登录页面记住密码和enter键登录方法推荐
May 10 #Javascript
详解JavaScript中的自定义事件编写
May 10 #Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【一】
May 10 #Javascript
JS组件系列之Bootstrap table表格组件神器【二、父子表和行列调序】
May 10 #Javascript
解决jquery无法找到其他父级子集问题的方法
May 10 #Javascript
JS组件系列之Bootstrap table表格组件神器【终结篇】
May 10 #Javascript
Bootstrap Fileinput文件上传组件用法详解
May 10 #Javascript
You might like
PHP初学者头疼问题总结
2006/07/08 PHP
PHP中对数据库操作的封装
2006/10/09 PHP
php 输出双引号&quot;与单引号'的方法
2010/05/09 PHP
php中unserialize返回false的解决方法
2014/09/22 PHP
php实现上传图片文件代码
2015/07/19 PHP
php 可变函数使用小结
2018/06/12 PHP
使用Laravel中的查询构造器实现增删改查功能
2019/09/03 PHP
php 实现银联商务H5支付的示例代码
2019/10/12 PHP
jquery右下角弹出提示框示例代码
2013/10/08 Javascript
使用Jquery实现每日签到功能
2015/04/03 Javascript
JavaScript实现信用卡校验方法
2015/04/07 Javascript
JavaScript的面向对象编程基础
2015/08/13 Javascript
jquery动态切换背景图片的简单实现方法
2016/05/14 Javascript
微信公众平台开发教程(六)获取个性二维码的实例
2016/12/02 Javascript
AngularJS 购物车全选/取消全选功能的实现方法
2017/08/14 Javascript
qrcode生成二维码微信长按无法识别问题的解决
2019/04/04 Javascript
使用JQuery自动完成插件Auto Complete详解
2019/06/18 jQuery
微信小程序实现聊天室
2020/08/21 Javascript
vue中template的三种写法示例
2020/10/21 Javascript
[27:28]Ti4 冒泡赛第二天 iG vs NEWBEE 1
2014/07/15 DOTA
[42:34]VP vs VG 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
解决Python中由于logging模块误用导致的内存泄露
2015/04/23 Python
VScode编写第一个Python程序HelloWorld步骤
2018/04/06 Python
python实现pdf转换成word/txt纯文本文件
2018/06/07 Python
Python实现监控键盘鼠标操作示例【基于pyHook与pythoncom模块】
2018/09/04 Python
python+logging+yaml实现日志分割
2019/07/22 Python
Python实现数值积分方式
2019/11/20 Python
Python切片列表字符串如何实现切换
2020/08/06 Python
分享30个新鲜的CSS3打造的精美绚丽效果(附演示下载)
2012/12/28 HTML / CSS
viagogo意大利票务平台:演唱会、体育比赛、戏剧门票
2018/01/26 全球购物
Dr. Martens马汀博士德国官网:马丁靴鼻祖
2019/12/26 全球购物
新加坡第一的杂货零售商:NTUC FairPrice
2020/12/05 全球购物
介绍一下Python中webbrowser的用法
2013/05/07 面试题
初三物理教学反思
2014/01/21 职场文书
知识就是力量演讲稿
2014/09/13 职场文书
给校长的一封检讨书
2014/09/20 职场文书