angularjs 数据双向绑定简洁源码实现
2017-04-18 本文已影响18人
盛佳人
hello.html
<html>
<head>
<title>我的第一个 HTML 页面</title>
</head>
<body>
<input ng-model="name" />
<span>{{name}}</span>
<script type="text/javascript" src="hello.js"></script>
</body>
</html>
hello.js
var Scope = function( ) {
this.$$watchers = [];
};
Scope.prototype.$watch = function( watchExp, listener ) {
this.$$watchers.push( {
watchExp: watchExp,
listener: listener || function() {}
} );
};
Scope.prototype.$digest = function( ) {
var dirty;
do {
dirty = false;
for( var i = 0; i < this.$$watchers.length; i++ ) {
var newValue = this.$$watchers[i].watchExp(),
oldValue = this.$$watchers[i].last;
if( oldValue !== newValue ) {
this.$$watchers[i].listener(newValue, oldValue);
dirty = true;
this.$$watchers[i].last = newValue;
}
}
} while(dirty);
};
//angularjs从这里开始
var $scope = new Scope();
//初始化的时候,我定义了一个name,我希望他显示在页面上
$scope.name = '简书';
//所以在页面上我写了一个<span>{{name}}</span>,<input ng-model="name"/>,我会找到{{name}},或者ng-model="name"等然后用$scope.name的值替换他们
var modelList1 = [];//ng-model
var modelList2 = [];//{{}}
var spanList = document.querySelectorAll('span');
for(var i =0;i<spanList.length;i++) {
if(spanList[i].innerHTML === '{{name}}') {
spanList[i].innerHTML = $scope.name;
modelList2.push(spanList[i]);
//console.log(spanList[i].innerHTML);
}
}
//input
var inputList = document.querySelectorAll('input');
for(var i =0;i<inputList.length;i++) {
if(inputList[i].attributes["ng-model"].value === 'name') {
//初始化
inputList[i].value = $scope.name;
modelList1.push(inputList[i]);
//ng-model绑定事件
inputList[i].onkeyup = (function(i) {
return function() {
$scope.name = inputList[i].value;//视图到模型
$scope.$digest();//模型到视图
}
})(i);
//加个$watch事件,并加入到$$watchers队列中
$scope.$watch(function(){
return $scope.name;
}, (function(i) {
return function( newValue, oldValue ) {
//console.log('新值 ' + newValue);
//console.log('旧值 ' + oldValue);
//ng-model
for(var j=0;j<modelList1.length;j++) {
modelList1[j].value = $scope.name;
}
//{{}}
for(var j=0;j<modelList2.length;j++) {
modelList2[j].innerHTML = $scope.name;
}
}
})(i) );
}
}
//以上是初始化阶段,数据已经反应到视图上了,angularjs对应的应该是$compile+$rootScope+相关指令加事件和替换 进行编译然后渲染
//接下来是数据的双向绑定阶段
//我觉得应该是ng-model指令绑定的onkeydown起作用的,它起到监听赋值的操作。然后立即调用$digest()->$$watchers来实现模型到视图的数据变化
setTimeout(function(){
updateScopeValue();
},3000);
var updateScopeValue = function updateScopeValue( ) {
$scope.name = '我是自动三秒后变化的值';
$scope.$digest();
};