很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
很easy的js双向绑定框架(二):控制器继承的更多相关文章
- Vue.js双向绑定的实现原理和模板引擎实现原理(##########################################)
Vue.js双向绑定的实现原理 解析 神奇的 Object.defineProperty 这个方法了不起啊..vue.js和avalon.js 都是通过它实现双向绑定的..而且Object.obser ...
- Vue.js双向绑定的实现原理
Vue.js最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统.本文仅探究几乎所有Vue的开篇介绍都会提到的hello world双向绑定是怎样实现的.先讲涉及的知识点,再参考源码,用尽可能少 ...
- Vue.js双向绑定原理
Vue.js最核心的功能有两个,一个是响应式的数据绑定系统,另一个是组件系统.本文仅仅探究双向绑定是怎样实现的.先讲涉及的知识点,再用简化的代码实现一个简单的hello world示例. 一.访问器属 ...
- vue.js双向绑定之--select获取text
在大多数情况下select下拉菜单都是value和text设置不同的值的,value一般来说是与后台交互的值,而text是前端用来显示的文本: 但是,vue.js对到表单的双向绑定时如果option设 ...
- js 双向绑定
//双向绑定实例 <input name="" ng-bind-123="name" /> function DataBinder( object_ ...
- Angular js 双向绑定时字符串的转换成 数字类型的问题
问题: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <scrip ...
- js 双向绑定数据
let aaa = []; let bbb = [1,2,3]; let ccc = [0,9,8]; aaa = bbb; //此时aaa与bbb被绑定(aaa指向bbb的指向) ,若使用push则 ...
- js双向绑定和地址传递带来的痛苦解决方案之对象拷贝
function cloneObj(obj) { var newObj = {}; if (obj instanceof Array) { newObj = []; } for (var key in ...
- node.js面向对象实现(二)继承
http://blog.sina.com.cn/s/blog_b5a53f2e0101nrdi.html 继承是面向对象中非常重要的一个概念,那么在Node.js中如何实现继承呢? node.js在u ...
随机推荐
- Python图像处理(16):图像金字塔
快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 图像金字塔是图像中多尺度表达的一种,最初用于机器视觉和图像压缩.一幅图像的金字塔是一系列以金字塔形 ...
- 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.10.配置用户NTF服务
2.10.配置用户NTF服务 2.10.1.配置节点RAC1 1) [root@linuxrac1 sysconfig]#sed -i 's/OPTIONS/#OPTIONS/g' /etc/sysc ...
- Java笔记4:JDBC纯驱动方式连接Oracle
JDBC纯驱动方式连接Oracle 1 下载Oracle提供的驱动程序包 下载地址: http://www.oracle.com/technetwork/database/enterprise-edi ...
- 转:TensorFlow和Caffe、MXNet、Keras等其他深度学习框架的对比
http://geek.csdn.net/news/detail/138968 Google近日发布了TensorFlow 1.0候选版,这第一个稳定版将是深度学习框架发展中的里程碑的一步.自Tens ...
- Androidproject师进阶之路 :《Android开发进阶:从小工到专家》上市啦!
封面 文件夹1 文件夹2 - 当当购买链接 - 京东购买链接 为什么写这本书 写这本书的念头由来已久了. 或许是从我打算写<Android源代码设计模式解析与实战>那时起就萌生了这个念头, ...
- lodash kebabCase
_.kebabCase([string='']) 转换字符串为 kebab case. _.kebabCase('Foo Bar'); // => 'foo-bar' _.kebabCase(' ...
- INSTALL_FAILED_OLDER_SDK
Uploading file local path: /Users/Rubert/Android/workspace/MyApplication/app/build/outputs/apk/app-d ...
- linux小技巧(1)
1.避免文件夹拼写错误 shopt命令: 演示一下: 我想进入/home文件夹可是不小心拼写错了: [fulinux@ubuntu ~]$ cd /hoem-bash: cd: /hoem: No s ...
- shell脚本循环嵌套
嵌套循环 在循环语句内使用任意类型的命令,包括其他循环命令,叫做嵌套循环.因为是在迭代中迭代,需要注意变量的使用以及程序的效率问题. 下面举一个for循环嵌套for循环的例子: wangsx@SC-2 ...
- Linux 常用命令速查
0x001 .在指定文件夹下递归查询包含一个字符串的文件(列出的文件内容片段) grep -r “要查找的串” 文件路径 如 : grep -r "helloworld&q ...