-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path02_mvvm.html
142 lines (121 loc) · 5.77 KB
/
02_mvvm.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
/*
* https://zhuanlan.zhihu.com/p/24475845?refer=mirone
*
* angularjs双向绑定-例子:
https://www.jianshu.com/p/ad0c48810bf1
* 原理:AngularJs 为 scope 模型上设置了一个 监听队列,用来监听数据变化并更新 view 。
每次绑定一个东西到 view(html) 上时 AngularJs 就会往 $watch 队列里插入一条 $watch,
用来检测它监视的 model 里是否有变化的东西。当浏览器接收到可以被 angular context 处理的事件时,
$digest 循环就会触发。$digest 会遍历所有的 $watch。从而更新DOM。
实现:
Scope {
$$watchers 监听多余的变量
$digest 数据循环检测
...
}
*/
function Scope(){
this.$$watchers=[]; //监听器
}
Scope.prototype.$watch=function(name,exp,listener){
this.$$watchers.push({
name:name, //数据变量名
last:'', //数据变量旧值
newVal:exp, //返回数据变量新值的函数
listener:listener || function(){} //监听回调函数,变量“脏”时触发
})
}
Scope.prototype.$digest=function(){
var bindList = document.querySelectorAll("[ng-bind]"); //获取所有含ng-bind的DOM节点
var dirty=true;
while(dirty){
dirty=false;
for(var i=0;i<this.$$watchers.length;i++){
var newVal=this.$$watchers[i].newVal();
var oldVal=this.$$watchers[i].last;
if(newVal!==oldVal && !isNaN(newVal) && !isNaN(oldVal)){
dirty=true;
// console.log(this.$$watchers[i].listener)
this.$$watchers[i].listener(oldVal,newVal); // 发现这句话并没有怎么监听
this.$$watchers[i].last=newVal;
for (var j = 0; j < bindList.length; j++) {
//获取DOM上的数据变量的名称
var modelName=bindList[j].getAttribute("ng-bind");
//数据变量名相同的DOM才更新
if(modelName==this.$$watchers[i].name) {
if (bindList[j].tagName == "INPUT") {
//更新input的输入值
bindList[j].value = this[modelName];
}
else {
//更新非交互式DOM的值
bindList[j].innerHTML = this[modelName];
}
}
}
}
}
}
};
window.onload=function(){
var $scope=new Scope();
$scope.count=0;
$scope.increment=function(){
this.count++;
};
//解析ng指令
var bindList=document.querySelectorAll("[ng-click]");
for(var i=0;i<bindList.length;i++){
bindList[i].onclick=(function(index){
return function() {
$scope[bindList[index].getAttribute("ng-click")]();
$scope.$digest(); //调用函数时触发$digest
}
})(i)
}
var inputList=document.querySelectorAll("input[ng-bind]");
for(var i=0;i<inputList.length;i++){
inputList[i].addEventListener("input",(function(index){
return function(){
$scope[inputList[index].getAttribute("ng-bind")]=inputList[index].value;
$scope.$digest(); //调用函数时触发$digest
}
})(i));
}
//绑定数据
for(var key in $scope){
if(key!="$$watchers" && typeof $scope[key]!="function") { //非函数数据才进行绑定
// console.log(key);
$scope.$watch(key, (function (index) {
return function(){
return $scope[index];
}
})(key),
function(newVal, oldVal){
console.log(newVal, oldVal)
})
}
}
$scope.$digest();
};
</script>
</head>
<body>
<div>
<form>
<input type="text" ng-bind="count" />
<button type="button" ng-click="increment" >increment</button>
</form>
<div ng-bind="count">
</div>
</div>
</body>
</html>