js 实现angylar.js view层和model层双绑定(改变view刷新 model,改变model自动刷新view)
近段时间研究了下angular.js 觉得它内部实现的view和model层之间存在很微妙的关系,如下图
如上图说的,view的改变会update 数据层model, 数据层会update视图层view,这双方之所以能实现互相的监听,就是通过中间层(理解为监听层),代码初始化的时候就会将view和model的相关状态都保存在监听层里面(可以理解为保存一个handler的函数到监听层里面),
view和model的改变都触发监听器里面的绑定的handler,实现状态的共享;
个人简单实现了下,可能实现得不太好,望拍砖(没有实现啥兼容性的哈,只在chrome下运行),希望各位大神给点意见!!
(function(win){
var doc = win.document,
_bind_key = "data-bind-" ,
_event_prefix = "message-",
_data = {};//存放数据的空间 /*生成唯一的gid*/
var gid = (function(){
var id =1;
return function(){
return "ng-"+(id++);
}
})(); /*事件存放的容器*/
var publisher = {
callbacks : {},
on : function( type , callback ){
this.callbacks[type] = this.callbacks[type]||[];
this.callbacks[type].push(callback);
},
fire : function( type ){
var callback = this.callbacks[type]||[];
for(var i=0,len= callback.length;i<len;i++){
callback[i].apply( this , arguments );
}
}
}; var user = {
set : function( id, key , value){
if(arguments<3){
return _data[object_id];
}
this.setData( id,key,value );
publisher.fire(type,key, value);
},
setData : function( id, key , value ){
_data[id][key] = value;
}
} /**
* @param {Node} : elem it can be a nodeList or one item
* @param {Function} callback : //数据层,view层改变后会触发此函数
*/
win.twoWayBind = function( elem ,callback){
var id = gid();
this.attr(elem ,_bind_key+id , true);
this.propoties = {
"id" : id,
"data-attr" : _bind_key+id,
"type" : "message-"+id
} this.init( callback );
} win.twoWayBind.prototype = {
set : function(key , value){
this.propoties[key] = value;
},
get : function(key){
return this.propoties[key];
},
attr : function( elems , key, value ){
//为elem元素设置相关属性
if(!elems){return;}
if(elems.nodeName || elems.nodeType===1){
elems = [elems];
}
for(var i =0 , len = elems.length;i<len;i++){
if( value ){
elems[i].setAttribute(key,value);
}else{
return elems[i].getAttribute(key);
}
}
},
/**
* @description 次函数用于外层调用,以实现改变数据的时候能监听器里面的函数
*/
setData : function( key , value ){
if(arguments.length<2){
return;
}
user.set( this.get('id'),key, value );
},
/*初始化*/
init : function( callback ){
var id = this.get('id');
this.domBinder();
this.dataBinder();
if(callback){
publisher.on(this.get('type'), callback);
}
},
domBinder : function(){
var object_id = this.get('id'),
data_attr = this.get('data-attr');
/*view监听的事件*/
var handler = function( evt ){
var target = evt.target || evt.srcElement,
prop_name = target.getAttribute(data_attr); if( prop_name ){
publisher.fire(type,prop_name,target.value);
}
} if(doc.addEventListener){
doc.addEventListener('change' , handler , false );
}else{
doc.attachEvent('change' , handler);
} /*dom触发事件*/
publisher.on(this.get('type') , function( evt , prop_name ,newValue , current ){
if(!evt){ return; }//如果触发此事件的目标不是一个元素//则不执行下面的代码
var elems = doc.querySelectorAll("["+data_attr+"]");
for(var i=0,len= elems.length;i<len;i++){
elem = elems[i];
if(elem.nodeName.toLowerCase()==="input" || elem.nodeName.toLowerCase()=="textarea"){
elem.value = newValue;
}else{
elem.innerHTML = newValue;
}
}
});
},
dataBinder : function(){
var object_id = this.get('id');
_data[object_id] = _data[object_id] || {};
var data_attr = _bind_key+object_id;
type = "message-"+object_id; /*dom触发事件*/
publisher.on(this.get('type') , function( evt , key ,value , isDataChange ){
user.setData(object_id,key,value);
console.log(evt);
});
}
} })(window)
完整代码如下:


<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input placeholder="按enter提交代码" type="text" id="text" />
<div>
<button value="1" onclick="setData(this)">设置字段value的值为1</button>
<button value="2" onclick="setData(this)">设置字段value的值为2</button>
</div>
<ul id='list'></ul>
<script type="text/javascript">
(function(win){
var doc = win.document,
_bind_key = "data-bind-" ,
_event_prefix = "message-",
_data = {};//存放数据的空间 /*生成唯一的gid*/
var gid = (function(){
var id =1;
return function(){
return "ng-"+(id++);
}
})(); /*事件存放的容器*/
var publisher = {
callbacks : {},
on : function( type , callback ){
this.callbacks[type] = this.callbacks[type]||[];
this.callbacks[type].push(callback);
},
fire : function( type ){
var callback = this.callbacks[type]||[];
for(var i=0,len= callback.length;i<len;i++){
callback[i].apply( this , arguments );
}
}
}; var user = {
set : function( id, key , value){
if(arguments<3){
return _data[object_id];
}
this.setData( id,key,value );
publisher.fire(type,key, value);
},
setData : function( id, key , value ){
_data[id][key] = value;
}
} /**
* @param {Node} : elem it can be a nodeList or one item
* @param {Function} callback : //数据层,view层改变后会触发此函数
*/
win.twoWayBind = function( elem ,callback){
var id = gid();
this.attr(elem ,_bind_key+id , true);
this.propoties = {
"id" : id,
"data-attr" : _bind_key+id,
"type" : "message-"+id
} this.init( callback );
} win.twoWayBind.prototype = {
set : function(key , value){
this.propoties[key] = value;
},
get : function(key){
return this.propoties[key];
},
attr : function( elems , key, value ){
//为elem元素设置相关属性
if(!elems){return;}
if(elems.nodeName || elems.nodeType===1){
elems = [elems];
}
for(var i =0 , len = elems.length;i<len;i++){
if( value ){
elems[i].setAttribute(key,value);
}else{
return elems[i].getAttribute(key);
}
}
},
/**
* @description 次函数用于外层调用,以实现改变数据的时候能监听器里面的函数
*/
setData : function( key , value ){
if(arguments.length<2){
return;
}
user.set( this.get('id'),key, value );
},
/*初始化*/
init : function( callback ){
var id = this.get('id');
this.domBinder();
this.dataBinder();
if(callback){
publisher.on(this.get('type'), callback);
}
},
domBinder : function(){
var object_id = this.get('id'),
data_attr = this.get('data-attr');
/*view监听的事件*/
var handler = function( evt ){
var target = evt.target || evt.srcElement,
prop_name = target.getAttribute(data_attr); if( prop_name ){
publisher.fire(type,prop_name,target.value);
}
} if(doc.addEventListener){
doc.addEventListener('change' , handler , false );
}else{
doc.attachEvent('change' , handler);
} /*dom触发事件*/
publisher.on(this.get('type') , function( evt , prop_name ,newValue , current ){
if(!evt){ return; }//如果触发此事件的目标不是一个元素//则不执行下面的代码
var elems = doc.querySelectorAll("["+data_attr+"]");
for(var i=0,len= elems.length;i<len;i++){
elem = elems[i];
if(elem.nodeName.toLowerCase()==="input" || elem.nodeName.toLowerCase()=="textarea"){
elem.value = newValue;
}else{
elem.innerHTML = newValue;
}
}
});
},
dataBinder : function(){
var object_id = this.get('id');
_data[object_id] = _data[object_id] || {};
var data_attr = _bind_key+object_id;
type = "message-"+object_id; /*dom触发事件*/
publisher.on(this.get('type') , function( evt , key ,value , isDataChange ){
user.setData(object_id,key,value);
console.log(evt);
});
}
} })(window)
</script>
<script type="text/javascript">
var tipsContainer = document.getElementById('list');
var binder = new twoWayBind( document.getElementById('text') ,function( e, key ,value ){
var li = document.createElement('li');
li.innerHTML = "当前input的值是:"+ value;
tipsContainer.appendChild(li);
});
function setData(elem){
var value = elem.value;
binder.setData("key" , value);
}
</script>
</body>
</html>
js 实现angylar.js view层和model层双绑定(改变view刷新 model,改变model自动刷新view)的更多相关文章
- MVC、MVP、MVVM、Angular.js、Knockout.js、Backbone.js、React.js、Ember.js、Avalon.js、Vue.js 概念摘录
注:文章内容都是摘录性文字,自己阅读的一些笔记,方便日后查看. MVC MVC(Model-View-Controller),M 是指业务模型,V 是指用户界面,C 则是控制器,使用 MVC 的目的是 ...
- js设置自动刷新
如何实现刷新当前页面呢?借助js你将无所不能. 1,reload 方法,该方法强迫浏览器刷新当前页面.语法:location.reload([bForceGet]) 参数: bForceGet, ...
- js自动刷新页面代码
<script language="JavaScript">function myrefresh(){window.location.reload();}setTime ...
- 读书笔记_MVC__关于通过js构建ORM,实现Model层
最近一直在学习MVC构建富应用的WEB程序,自己一直对MVC的设计模式理解的不是十分透彻,终于在研读了github上Spine的源码之后,对构建Model层有了一点自己的理解. 本文仅为个人理解,如有 ...
- 再探 Ext JS 6 (sencha touch/ext升级版) 变化篇 (编译命令、滚动条、控制层、模型层、路由)
从sencha touch 2.4.2升级到ext js 6,cmd版本升级到6.0之后发生了很多变化 首先从cmd说起,cmd 6 中sencha app build package不能使用了,se ...
- JS 点击按钮后弹出遮罩层,有关闭按钮
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <t ...
- 【Knockout.js 学习体验之旅】(3)模板绑定
本文是[Knockout.js 学习体验之旅]系列文章的第3篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...
- Angular.js vs Ember.js
Angular.js 拥抱 HTML/CSS Misko Hevery(Angular.js的开发者之一)回答了这一问题,他的主要观点如下: 在HTML中加入太多逻辑不是好做法.Angular.js只 ...
- HTML5学习+javascript学习:打飞机游戏简介以及Model层
本着好记性不如烂博客以及分享成功的喜悦和分享失败的苦楚,今天我来分享下一个练手项目:打飞机游戏~从小就自己想做游戏,可是一直没有机会.HTML5给了我们这个平台,这个平台可以有很多以前想都不敢想的东西 ...
随机推荐
- linux集群管理<转>
云在根本上是由硬件和软件组成的,这些组件需要经常细心地维护.出现故障的硬件需要修理或更换:软件需要应用补丁.更新和升级:必须根据需求和潜在的安全威胁提前配置系统.应用程序开发人员可能觉得计算云很方便. ...
- Drupal 7.31 SQL注入漏洞利用具体解释及EXP
有意迟几天放出来这篇文章以及程序,只是看样子Drupal的这个洞没有引起多少重视,所以我也没有必要按着不发了,只是说实话这个洞威力挺大的.当然.这也是Drupal本身没有意料到的. 0x00 首 ...
- TP复习15
## ThinkPHP 3.1.2 URL#讲师:赵桐正微博:http://weibo.com/zhaotongzheng 本节课大纲:一.URL规则 1.默认是区分大小写的 2.如果我们不想区分大小 ...
- 单片机modebus RTU通信实现,採用C语言,可适用于单片机,VC,安卓等
当前使用的是STM32+ucos_ii编写的,能够移植到安卓以及VC .NET等方便移植使用,採用modebus poll測试过. 仅仅须要改动响应的通信接口就可以,方便多串口使用 //modebus ...
- iOS开发——开发必备OC篇&UITableView设置界面完整封装(二)
UITableView设置界面完整封装(二) 简单MVC实现UITableView设置界面之Cell右边类型设置 首先来看看第一种方法证明使用,结合两种方法之后根据个人的爱好去选择就可以了, 一:使用 ...
- ChinaASP.Upload 错误 '80040002' You must add our copyright info
ChinaASP.Upload 错误 '80040002' You must add our copyright info: http://www.chinaasp.com 修改 第一步:在“开始-运 ...
- 如何避免MVC Model First 设计时添加的DataAnnotation被覆盖掉
结合多方资料做一系统,发现Code First中所有代码要自己写,无法自动生成(暂时没有找到方法,有知道的大能,给指点一下,好像在NuGet中有一个插件可以直接从数据库中生成Code First所需类 ...
- 关于Android WindowManager显示悬浮窗的动画效果
要实现WindowManager添加的窗口,实现动画显示,就需要添加如下红色的属性,其他的添加View只要设置其Animations属性也会实现动画,当然自己实现也可,但是能直接用系统的已经实现好的, ...
- LeetCode30 Substring with Concatenation of All Words
题目: You are given a string, s, and a list of words, words, that are all of the same length. Find all ...
- C++面向对象设计
一. 组合(复合),继承,委托 1.composition(组合)has-a 1.1 组合举例:(Adapter 设计模式) 关系: 利用deque功能实现所有queue功能 template < ...