Knockout.js随手记(7)

时间:2023-01-08 16:10:37

数组元素的新增/移除事件

前两篇博客已经很清楚的知道knockout.js通过observableArray()数组元素增减,可以实时的反映在UI上。当然我们想在数组增加或移除元素时加上自定义逻辑就好比一个触发器的感觉,可以吗?

foreach提供了afterAdd及beforeRemove两个额外的事件,允许在数组新增、移除元素时执行特定逻辑。在此继续沿用先前的用户列表呈现范例,加上两个效果:

  • 新增数据时,将最新加入的数据和表格进行着色修饰
  • 删除数据时,加上数据淡出特效

而在ViewModel里我们加上两个函数:

   //添加对象后才触发,第一次forach并不会触发
self.afterAddEvent = function (element, index, data) {
//通过nodeType过滤,只处理Element Node
if (element.nodeType==1)
{
$(".new").removeClass("new");
$(element).addClass("new");
}
};
//注意: beforeRemove事件后,要自已移除被刪除元素
self.beforeRemoveEvent = function (element, index, data) {
if (element.nodeType == 1) {
$(element)
.css("background-color", "#ff6a00")
.animate({ opacity: 0.2 },1000, function () {
$(this).remove();
}) }
};

afterAdd及beforeRemove函数会固定收到三个参数,element、index及data,其中element为模板容器中的各元素,即:

          <tr>
<td><span data-bind="text: id"></span></td>
<td><span data-bind="text: name"></span></td>
<td><span data-bind="text: score"></span></td>
<td><a href='#' data-bind="click: $root.removeUser">Remove</a></td>
</tr>

实际运作时afterAdd/beforeRemove会收到不同的element被呼叫三次,原因是除了<tr>之外,<tbody>到<tr>之间的空白、</tr>到</tbody>间的空白也各算一个Element,(FF和chrome是忽略这个空格的)其nodeType为3即TEXT_NODE,代表TEXT_NODE。因此三次传入的element分别为TEXT_NODE、ELEMENT_NODE、TEXT_NODE,而第二次传入的ELEMENT_NODE是<tr>...</tr>间的内容,才是我们需要处理的对象,故加入if (elems.nodeType == 1)的判断。

要注意,一旦调用了了beforeRemove,konckout.js就不再自动帮你移除该笔数据在网页对应的元素,必须自行处理,但这也提供开发人员绝对的控制权,可*安排HTML元素要怎么从网页上退出。

完整代码如下:

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index2</title>
<style>
table { width: 385px }
td,th { border: 1px solid #0094ff; text-align: center; }
.new { color: #0094ff; background-color:#b6ff00}
</style> <script src="~/Scripts/jquery-2.0.3.js"></script>
<script src="~/Scripts/knockout-2.3.0.js"></script>
<script type="text/javascript">
//定义user数据对象
function UserViewModel(id,name,score) {
var self = this;
self.id = id;
self.name =ko.observable(name);
self.score =ko.observable(score);
}
//定义ViewModel
function ViewModel() {
var self = this;
self.users = ko.observableArray();//添加动态监视数组对象
self.removeUser = function (user) {
self.users.remove(user);
}
self.totalscore = ko.computed(function () {
var total = 0;
$.each(self.users(), function (i, u) {
total += u.score();
})
return total;
});
//添加对象后才触发,第一次forach并不会触发
self.afterAddEvent = function (element, index, data) {
//通过nodeType过滤,只处理Element Node
if (element.nodeType==1)
{
$(".new").removeClass("new");
$(element).addClass("new");
}
};
//注意: beforeRemove事件后,要自已移除被刪除元素
self.beforeRemoveEvent = function (element, index, data) {
if (element.nodeType == 1) {
$(element)
.css("background-color", "#ff6a00")
.animate({ opacity: 0.2 },600, function () {
$(this).remove();
}) }
};
};
$(function () {
var vm = new ViewModel();
//预先添加一些数据
vm.users.push(new UserViewModel("d1", "rohelm", 121));
vm.users.push(new UserViewModel("d2", "halower", 125));
$("#btnAddUser").click(function () {
vm.users.push(new UserViewModel(
$("#u_id").val(),
$("#u_name").val(),
parseInt($("#u_score").val())));
});
$("#btnUpdateScore").click(function () {
vm.users()[vm.users().length-1].score(125).name("HelloWorld!");
});
ko.applyBindings(vm);
});
</script>
</head>
<body>
<section style="margin:250px">
<section>
ID<input type="text" id="u_id" style="width:30px">
Name<input type="text" id="u_name" style="width:30px">
Score<input type="text" id="u_score" style="width:30px"><br/>
<input value="Add" id="btnAddUser" type="button" style="width:200px; background-color:#ff6a00;"/><br/>
共 <span data-bind="text: users().length"></span> 条--------------合计 <span data-bind="text: totalscore"></span> 分
</section>
<section>
<table>
<thead>
<tr><th>ID</th><th>Name</th><th>Score </th><th>Option</th></tr>
</thead>
<tbody data-bind="foreach: { data: users, afterAdd: afterAddEvent, beforeRemove: beforeRemoveEvent}">
<tr>
<td><span data-bind="text: id"></span></td>
<td><span data-bind="text: name"></span></td>
<td><span data-bind="text: score"></span></td>
<td><a href='#' data-bind="click: $root.removeUser">Remove</a></td>
</tr>
</tbody>
</table>
<input value="Update测试" id="btnUpdateScore" type="button" style="width:200px; background-color:#ff6a00;"/><br/>
</section>
</section>
</body>
</html>

运行效果如下:

Knockout.js随手记(7)

备注:

    本文版权归大家共用,不归本人所有,所有知识都来自于官网支持,书本,国内外论坛,大牛分享等等......后续将学习knockout.js的常用功能。

                                如果你喜欢本文的话,推荐共勉,谢谢!

Knockout.js随手记(7)的更多相关文章

  1. Knockout&period;js随手记&lpar;2&rpar;

    计算属性 konckout.js的API文档,写的极为详细和生动,透过MVVM的运作原理,开发时只需专注于定义ViewModel逻辑,不需耗费心力处理TextBox.Select的onchange.o ...

  2. Knockout&period;js随手记&lpar;8&rpar;

    visible, disable, css绑定 这个例子非常简单,主要演示如何通过属性控制html元素的显示与否(visible),可用性(disable)以及根据属性添加相应的CSS样式. 先简单的 ...

  3. Knockout&period;js随手记&lpar;6&rpar;

    实时反映对象属性的变化 在前一篇博客中我们使用了如下代码去新增user对象,即push方法: $("#btnAddUser").click(function () { vm.use ...

  4. Knockout&period;js随手记&lpar;5&rpar;

    以列表方式呈现数据  处理以数组形式储存的多条数据,要先认识foreach.在ViewModel定义一个JavaScript Array或是ko.observableArray() (observab ...

  5. Knockout&period;js随手记&lpar;4&rpar;

    动态绑定下拉列表 在<select> data-bind的options选项如果绑定到ko.observableArray(),就可以动态新增选项效果,也就是可以利用其完成常见的级联效果的 ...

  6. Knockout&period;js随手记&lpar;3&rpar;

    下拉菜单 <select>也是网页设计重要的一环,knockout.js(以下简称KO)也有不错的支持.针对<select>,在data-bind除了用value可对应下拉菜单 ...

  7. Knockout&period;js随手记&lpar;1&rpar;

    新的开始,knockout.js 1.首先去http://knockoutjs.com/index.html下载knockout.js,最新的版本是2.3 2.知道什么是Knockout?它是个Jav ...

  8. 【Knockout&period;js 学习体验之旅】(3)模板绑定

    本文是[Knockout.js 学习体验之旅]系列文章的第3篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...

  9. 【Knockout&period;js 学习体验之旅】(2)花式捆绑

    本文是[Knockout.js 学习体验之旅]系列文章的第2篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...

随机推荐

  1. Hibernate的关联映射

    单向N-1关联 <many-to-one> 单向N-1关系,比如多个人对应同一个住址,只需要从人实体端找到对应的住址实体,无须关系某个地址的全部住户.程序在N的一端增加一个属性,该属性引用 ...

  2. 微软Face API体验——人脸检测

    微软推出了全新REST API,现在可免费获取密钥,大家可以赶快申请!申请地址:https://cn.projectoxford.ai/subscription 看了网站的API介绍,忍不住赶快体验一 ...

  3. 编译安装或者mysql启动时遇到的错误小记

    编译安装遇到的错误:进入mysql目录 [root@localhost software]# cd mysql-5.6.19 [root@localhost mysql-5.5.11]# cmake ...

  4. android jni

    1, java.lang.UnsatisfiedLinkError: Couldn't load xxxxx: findLibrary returned null 当 apk 是被放到 /system ...

  5. 【Valse首发】CNN的近期进展与实用技巧(上)

    作者:程程链接:https://zhuanlan.zhihu.com/p/21432547来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 深度学习大讲堂致力于推送人工智 ...

  6. HTTP权威指南-HTTP报文

    在开始学习本章之前,先来提一些问题,什么是报文?如何创建报文?怎么去理解报文?以及报文的用处有哪些? 什么是报文? 可以这么去理解,如果说HTTP是因特网的信使,那么HTTP报文就是它用来搬东西的包裹 ...

  7. JAVA HttpClient进行POST请求(HTTPS)

    目前,要为另一个项目提供接口,接口是用HTTP URL实现的,最初的想法是另一个项目用jQuery post进行请求. 但是,很可能另一个项目是部署在别的机器上,那么就存在跨域问题,而jquery的p ...

  8. Bootstrap框架(一)

    day57 参考:https://www.cnblogs.com/liwenzhou/p/8214637.html 下载:http://www.bootcss.com/   选择用于生产环境的 Boo ...

  9. Java中多线程重复启动

    在面试时候经常被问到多线程的相关问题: 今天在测试的时候发现下面的代码会抛出异常: java.lang.IllegalThreadStateException public static void m ...

  10. arm交叉编译器gnueabi、none-eabi、arm-eabi、gnueabihf的区别

    转自 https://www.cnblogs.com/linuxbo/p/4297680.html 命名规则 交叉编译工具链的命名规则为:arch [-vendor] [-os] [-(gnu)eab ...