Knockout双向绑定
knockout双工绑定基于 observe 模式,性能高。核心就是observable对象的定义。这个函数最后返回了一个也叫做 observable 的函数,也就是用户定义值的读写器(accessor)。
this.firstName=ko.observable(“Bert”);
this.firstName();
this.firstName(“test”);
ko.observable做了什么
ko.observable = function (initialValue) {
var _latestValue = initialValue; //保留上一次的参数,与observable形成闭包
function observable() {
if (arguments.length > ) {
// Write,Ignore writes if the value hasn't changed
if (observable.isDifferent(_latestValue, arguments[])) {
observable.valueWillMutate();
_latestValue = arguments[];
if (DEBUG) observable._latestValue = _latestValue;
observable.valueHasMutated();
}
return this; // Permits chained assignments
}
else {
// Read
ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
return _latestValue;
}
}
ko.subscribable.call(observable);
ko.utils.setPrototypeOfOrExtend(observable, ko.observable['fn']);
if (DEBUG) observable._latestValue = _latestValue;
/**这里省略了专为 closure compiler 写的语句**/
return observable;
}
通过 ko.subscribable.call(observable); 使这个函数有了被订阅的功能,让 firstName 在改变时能通知所有订阅了它的对象。其实就是维护了一个回调函数的队列,当自己的值改变时,就执行这些回调函数。根据上面的代码,回调函数是在 observable.valueHasMutated(); 执行的。
ko.computed做了什么
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
$.computed = function(obj, scope){
//computed是由多个$.observable组成
var getter, setter
if(typeof obj == "function"){
getter = obj
}else if(obj && typeof obj == "object"){
getter = obj.getter;
setter = obj.setter;
scope = obj.scope;
}
var v
var ret = function(neo){
if(arguments.length ){
if(typeof setter == "function"){//setter不一定存在的
if(v !== neo ){
setter.call(scope, neo);
v = neo;
}
}
return ret;
}else{
v = getter.call(scope);
return v;
}
}
return ret;
}
$.dependencyDetection = (function () {
var _frames = [];
return {
begin: function (ret) {
_frames.push(ret);
},
end: function () {
_frames.pop();
},
collect: function (self) {
if (_frames.length > ) {
self.list = self.list || [];
var fn = _frames[_frames.length - ];
if ( self.list.indexOf( fn ) >= )
return;
self.list.push(fn);
}
}
};
})();
$.valueWillMutate = function(observable){
var list = observable.list
if($.type(list,"Array")){
for(var i = , el; el = list[i++];){
el();
}
}
}
双向绑定如何实现
$.buildEvalWithinScopeFunction = function (expression, scopeLevels) {
var functionBody = "return (" + expression + ")";
for (var i = ; i < scopeLevels; i++) {
functionBody = "with(sc[" + i + "]) { " + functionBody + " } ";
}
return new Function("sc", functionBody);
}
$.applyBindings = function(model, node){
var nodeBind = $.computed(function (){
var str = "{" + node.getAttribute("data-bind")+"}"
var fn = $.buildEvalWithinScopeFunction(str,);
var bindings = fn([node,model]);
for(var key in bindings){
if(bindings.hasOwnProperty(key)){
var fn = $.bindingHandlers["text"]["update"];
var observable = bindings[key]
$.dependencyDetection.collect(observable);//绑定viewModel与UI
fn(node, observable)
}
}
},node);
return nodeBind
}
$.bindingHandlers = {}
$.bindingHandlers["text"] = {
'update': function (node, observable) {
var val = observable()
if("textContent" in node){
node.textContent = val;
}
}
}
window.onload = function(){
var model = new MyViewModel();
var node = document.getElementById("node");
$.applyBindings(model, node);
}
KO使用
1、ko绑定方式,立即执行用于需要后处理的一些数值
//点击事件
data-bind="click:$root.fun1.bind($param1,param2)"
//立即执行
data-bind="attr: { src : $root.fun2(param1,param2) }”
//缺省参数
data-bind="event: { mouseover: myFunction }"
<script type="text/javascript">
var viewModel = {
myFunction: function(data, event) {
if (event.shiftKey) {
//do something different when user has shift key down
} else {
//do normal action
}
}
};
ko.applyBindings(viewModel);
</script>
注意:在bind方式传递参数时,data和event两个参数依然被缺省传递。 新加入的参数,在使用时排在第一位,定义时只能排在$data后面
2、event事件
<input type="text" placeholder="输入关键字搜索" data-bind="event:{keyup:$root.fun1.bind($data,$element)}">
3、
self.weeklyRecommend(this); //监控对象整体发生变化时响应
self.weeklyRecommend(ko.mapping.fromJs(this)); //可以监控对象下每个元素的改变
4、ko事件注册
ko.bindingHandlers.singleExamHover = {
init: function(element, valueAccessor){
$(element).hover(
function(){
//todo
},
function(){
//todo
}
);
},
update:function(element, valueAccessor){
var _value = ko.unwrap(valueAccessor());
if(_value){
$(element).addClass("current");
}else{
$(element).removeClass("current");
}
}
};
<div class="h-set-homework" data-bind="singleExamHover:question.checked”>
5、事件冒泡
By default, Knockout will allow the click event to continue to bubble up to any higher level event handlers。
If necessary, you can prevent the event from bubbling by including an additional binding that is named clickBubble and passing false to it
<div data-bind="click: myDivHandler">
<button data-bind="click: myButtonHandler, clickBubble: false">
Click me
</button>
</div>
Normally, in this case myButtonHandler would be called first, then the click event would bubble up to myDivHandler. However, the clickBubble binding that we added with a value of false prevents the event from making it past myButtonHandler.
6、$data
$data and $root are equivalent. Inside a nested binding context, this parameter will be set to the current data item (e.g., inside a with: person binding, $data will be set to person). $data is useful when you want to reference the viewmodel itself, rather than a property on the viewmodel.<div data-bind="click:changeEditor.bind($data,$element,param1,param2)"></div>
<script>
changeEditor : function(ele,param1,param2){
console.log(this)
console.log(ele==event.currenttarget)
}
</script>
Knockout双向绑定的更多相关文章
- Knockout 双向绑定的理解
今天做了个需求就是上传图片,然后在代码中通过jQuery给一个标签赋值,经过前台的debug,发现这个值赋值成功了,但是提交到后台的请求里就没了,然后经历了一顿度娘,结果中发现了问题. 既然knock ...
- ASP.NET Web API实践系列07,获取数据, 使用Ninject实现依赖倒置,使用Knockout实现页面元素和视图模型的双向绑定
本篇接着上一篇"ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API",尝试获取数据. 在Models文件夹下创 ...
- 前端MVVM框架avalon揭秘 - 双向绑定原理
avalon大家可能不熟悉,但是Knockout估计或多或少听过用过,那么说说KO的几个概念 监控属性(Observables)和依赖跟踪(Dependency tracking) 声明式绑定(Dec ...
- 数据的双向绑定 Angular JS
接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同.为此,记录了一些思考,给自己回顾,也供他人参考. 初步大致有以下几个方面: 数据双向绑定 ...
- vue.js初级入门之最基础的双向绑定操作
首先在页面引入vue.js以及其他需要用到的或者可能要用到的插件(这里我多引用了bootstrap和jquery) 引用的时候需要注意文件的路径,准备工作这样基本就完成了,下面正式开始入门. vue. ...
- RAC textView的双向绑定
今天在写关于textView的数据绑定时原先写法是这样的: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #78 ...
- AnjularJS系列3 —— 数据的双向绑定
第三篇,双向的数据绑定 数据绑定是AnguarJS的特性之一,避免书写大量的初始代码从而节约开发时间 数据绑定指令提供了你的Model投射到view的方法.这些投射可以无缝的,毫不影响的应用到web应 ...
- 我的angularjs源码学习之旅3——脏检测与数据双向绑定
前言 为了后面描述方便,我们将保存模块的对象modules叫做模块缓存.我们跟踪的例子如下 <div ng-app="myApp" ng-controller='myCtrl ...
- Angularjs 双向绑定机制解析
文章转自:http://www.2cto.com/kf/201408/327594.html AngularJs 的元素与模型双向绑定依赖于循环检测它们之间的值,这种做法叫做脏检测,这几天研究了一下其 ...
随机推荐
- 用友 SAP 金蝶 季报
用友 2018Q3季报 营收:.42亿 营收收入同比增长:42.36% 净利润:.35万 净利润同比增长率:113.83% 销售毛利率:66.88% 销售净利率:19.29% 用友2017财年年报 营 ...
- ueditor与mvc4中坑 -编辑时显示源码问题
最近一次使用 ueditor 时,在MVC中的修改新闻内容时发现,怎么调用都是编辑器保存下来的源码,代码如下 <script id="ucontent" name=" ...
- InnoDB 5.6 新特性之一:FullTEXT Indexes[1.简单介绍]
先来看一条SQL语句: SELECT * FROM aa where acol like '%like_normal%'; 当我们使用Innodb时,无论如何对这条语句进行优化,都是无意义的:有的人会 ...
- shell脚本学习—正则表达式
正则表达式概念.特点 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”, 这个“规则字符串”用来表达对字符串的一种过滤辑. 给定一个 ...
- CodeForces - 955B(用char会超时。。。)
#include <bits/stdc++.h> #define mem(a, b) memset(a, b, sizeof(a)) using namespace std; , INF ...
- CentOS 7下安装pptp服务端手记 ok
主要配置步骤 1. 安装前检查系统支持 2. 安装必要包 3. 修改相关配置文件 4. 设置开机自动启动 pptpd, iptables 5. iptables配置网络 6. 阿里云ECS可能还需要几 ...
- 史上最全面,清晰的SharedPreferences解析
基础用法获取Sp:getput监听器原理分析获取SharedPreferences构造SharedPreferencesgetX原理分析putX原理分析创建editorputStringapplyap ...
- 利用MSXSL.exe绕过AppLocker应用程序控制策略
1.需要用到微软工具MSXSL.exe,msxsl.exe是微软用于命令行下处理XSL的一个程序,所以通过他,我们可以执行JavaScript进而执行系统命令,其下载地址为: https://www. ...
- mysql三-1:存储引擎
一 什么是存储引擎 mysql中建立的库===>文件夹 库中建立的表===>文件 现实生活中我们用来存储数据的文件有不同的类型,每种文件类型对应各自不同的处理机制:比如处理文本用txt类型 ...
- JavaScript的变量预解析特性
JavaScript是解释型语言是毋庸置疑的,但它是不是仅在运行时自上往下一句一句地解析的呢?事实上或某种现象证明并不是这样的,通过<JavaScript权威指南>及网上相关资料了解到,J ...