很easy的js双向绑定框架(二):控制器继承
初衷
上一篇已经实现了数据的双向绑定,但model的控制范围是整个文档。在实际project中必需要有作用范围,以便做ui模块的拆分。
这一篇,我们希望实现像angularjs一样的控制器继承:
1. 父controller的Model能够在子controller里被訪问到
2. 子controller的model不影响父controller
3. controller继承关系在html中指定。而不是js中指定
目标
html里,用isi-controller属性去声明控制器:
<body> <div isi-controller="ParentController"> <input data-bind="name"> <div isi-controller="SubController"> <input data-bind="name"> </div> </div> </body
希望上面的input name 改了。以下的会跟着变,而以下的变了,上面的不变。
js里,用和上面isi-controller属性值同名的函数定义控制器:
function ParentController() { var model = new Model(); model.set('name', 'parent'); } function ParentController() { var model = new Model(); model.set('name', 'sub'); }
对用户来说,仅仅要写这些。就完事儿了。
实现
版本号1
这个版本号採用最简单直观的思路:框架去找$(‘[isi-controller]’)的元素。然后给这些元素分别去绑定监听器、运行控制器函数
代码先列了:
index.html:
<html> <head> <title>simple MVVM</title> <script src="js/ParentController.js"></script> <script src="js/SubController.js"></script> <script src="js/frame_v2.js"></script> </head> <body isi-controller="ParentController"> <input type="text" data-bind="name"> <div isi-controller="SubController"> <input type="text" data-bind="name"> </div> </body> </html>
ParentController.js:
function ParentController() { var model = new Model(); model.set('name', 'parent'); }
SubController.js:
function SubController() { var model = new Model(); model.set('name','sub'); }
frame_v2.js: (对比上一篇,主要修改在绑监听器和new Model的自己主动化)
var pubsub = ... //见上一篇 var Model = ... //见上一篇 // listener capture view changes --> publish model.change event var changeHandler = function(event) { var target = event.target, propName = target.getAttribute('data-bind'); if( propName && propName !== '' ) { pubsub.pub('model.change', propName, target.value); } event.stopPropagation(); } /*----------- Init --------------*/ window.onload = function() { /* first step: * find controllers' dom */ var controllerRanges = document.querySelectorAll('[isi-controller]'); /* second step: * bind listeners for each controllers' range, * view.change event --> change each controllers' range */ for(var i=0, len=controllerRanges.length; i<len; i++) { controllerRanges[i].addEventListener('change', changeHandler, false); // view.change event --> change view (function(index){ pubsub.sub('view.change', function(propName, newVal) { var elements = controllerRanges[index].querySelectorAll('[data-bind=' + propName +']'), tagName; for(var i=0,l=elements.length; i<l; i++) { tagName = elements[i].tagName.toLowerCase(); if(tagName==='input' || tagName==='textarea' || tagName==='select') { elements[i].value = newVal; } else { elements[i].innerHTML = newVal; } } }); })(i); } /* third step: * execute each controller function */ for(var i=0, len=controllerRanges.length; i<len; i++) { var controllerName = controllerRanges[i].getAttribute('isi-controller'); eval(controllerName+'()'); } }
看看效果:
悲剧了。
没有实现第二个初衷:子控制器不影响父控制器。
这个问题该怎样解决呢?
版本号二,子不影响父
细致看代码,之所以会出现故障,是由于view.change信道的作用范围是有问题的。无论哪个model发出的view.change事件,两个控制器的view都会改变。
所以,我们给公布view.change事件的时候,多公布一个控制器名。好让接收view.change的时候知道应不应该修改html:
var Model = function(controllerName) { var model = { controllerName:controllerName, props: {}, set: function(propName, value) { this.props[propName] = value; pubsub.pub('view.change', propName, value, this.controllerName); //就是这里!控制器里new Model的时候注意把controller的名字初始化进去:} }
ParentController.js:
function ParentController() { var model = new Model('ParentController'); model.set('name', 'parent'); }
最后接收view.change信道消息的时候,推断下controllerName:
pubsub.sub('view.change', function(propName, newVal, controllerName) { .... thisControllerName = controllerRanges[index].getAttribute('isi-controller'), if(thisControllerName !== controllerName) return; .... }
当然。监听器公布model.change的时候也是一样。要把控制器名称公布出去。代码就不贴了。
再看看效果:
妥了
全部代码:
github/victorisildur
- 非常简单的js双向绑定框架(二):控制器继承
- 非常简单的js双向绑定框架(一)
- 迷你MVVM框架 avalonjs 学习教程21、双向绑定链
- 非常简单的js双向数据绑定框架(三):js model黑科技
- Vue.js学习笔记:v-model双向绑定
- JavaScript中MVVM框架是如何实现双向绑定的
- 解决Vue.js 2.0 有时双向绑定img src属性失败的问题
- 如何用javascript实现双向数据绑定 / Backbone.js简单入门范例
- angularjs input ng-model 双向绑定无效的问题
- vue.js v-model数据双向绑定实例
- [Vue.js启航]——数据的双向绑定
- 实现非常简单的js双向数据绑定
- Vue.js的组件(四)父组件与子组件的数据联系 之 双向绑定
- js原生代码实现数据双向绑定
- Angular.js基本概念和用法--(一双向数据绑定)
- JS中的双向数据绑定
- Js原生 双向数据绑定
- (八)简单了解下angularJS框架中NB的双向数据绑定机制,大大减少需要重复的开发代码量
- Node.js的原型继承函数util.inherits + 开发框架Express4.x