首页 技术 正文
技术 2022年11月21日
0 收藏 824 点赞 3,826 浏览 5167 个字

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)}">

完整的 key press 过程分为两个部分,按键被按下,然后按键被松开并复位。当按钮被松开时,发生 keyup 事件。它发生在当前获得焦点的元素上。keydown事件发生在键盘的键被按下的时候,接下来触发keypress事件。 keyup 事件在按键被释放的时候触发。KeyPress 只能捕获单个字符;KeyDown 和KeyUp 可以捕获组合键。 

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

This is the view model object in the current context. In the root context, $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>
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,082
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,556
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,406
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,179
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,815
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,898