初衷

上一篇已经实现了数据的双向绑定,但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双向绑定框架(二):控制器继承的更多相关文章

  1. Vue.js双向绑定的实现原理和模板引擎实现原理(##########################################)

    Vue.js双向绑定的实现原理 解析 神奇的 Object.defineProperty 这个方法了不起啊..vue.js和avalon.js 都是通过它实现双向绑定的..而且Object.obser ...

  2. Vue.js双向绑定的实现原理

    Vue.js最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统.本文仅探究几乎所有Vue的开篇介绍都会提到的hello world双向绑定是怎样实现的.先讲涉及的知识点,再参考源码,用尽可能少 ...

  3. Vue.js双向绑定原理

    Vue.js最核心的功能有两个,一个是响应式的数据绑定系统,另一个是组件系统.本文仅仅探究双向绑定是怎样实现的.先讲涉及的知识点,再用简化的代码实现一个简单的hello world示例. 一.访问器属 ...

  4. vue.js双向绑定之--select获取text

    在大多数情况下select下拉菜单都是value和text设置不同的值的,value一般来说是与后台交互的值,而text是前端用来显示的文本: 但是,vue.js对到表单的双向绑定时如果option设 ...

  5. js 双向绑定

    //双向绑定实例 <input name="" ng-bind-123="name" /> function DataBinder( object_ ...

  6. Angular js 双向绑定时字符串的转换成 数字类型的问题

    问题: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <scrip ...

  7. js 双向绑定数据

    let aaa = []; let bbb = [1,2,3]; let ccc = [0,9,8]; aaa = bbb; //此时aaa与bbb被绑定(aaa指向bbb的指向) ,若使用push则 ...

  8. js双向绑定和地址传递带来的痛苦解决方案之对象拷贝

    function cloneObj(obj) { var newObj = {}; if (obj instanceof Array) { newObj = []; } for (var key in ...

  9. node.js面向对象实现(二)继承

    http://blog.sina.com.cn/s/blog_b5a53f2e0101nrdi.html 继承是面向对象中非常重要的一个概念,那么在Node.js中如何实现继承呢? node.js在u ...

随机推荐

  1. Oracle审计--AUD$占用空间较大处理方案

    Oracle 11G以后,数据库默认是开启审计功能的,因此有时候我们忘记了关闭该功能导致SYSTEM表空间暴满,但由于关闭审计功能需要重启数据库,此类操作生产环境下是不允许的,因此我们需要找出哪类审计 ...

  2. ajax回调中window.open弹出的窗口会被浏览器拦截的解决方法

    存在问题:处理页面ajax请求过程中,异步请求成功后需要新开窗口打开 url,使用的是 window.open() 方法 来实现,最终都被浏览器拦截了.不会跳到对应的页面,如下 原因:浏览器之所以拦截 ...

  3. GNURADIO简单运用

    本文是关于 RF hacking..所以这个就此不表…还是让我们来看看关键的无线解锁器吧..通常我们 hacking 一个无线设备的第一步就是找到目标的工作频率. 我们可以通过每个无线设备自带的FCC ...

  4. OpenGL.Vertex Array Object (VAO) [转]

    http://www.cppblog.com/init/archive/2012/02/21/166098.html 一 OpenGL抛弃glEnable(),glColor(),glVertex() ...

  5. [Python爬虫] 之二十三:Selenium +phantomjs 利用 pyquery抓取智能电视网数据

    一.介绍 本例子用Selenium +phantomjs爬取智能电视网(http://news.znds.com/article/news/)的资讯信息,输入给定关键字抓取资讯信息. 给定关键字:数字 ...

  6. 【Hadoop】伪分布式环境搭建、验证

    Hadoop伪分布式环境搭建: 自动部署脚本: #!/bin/bash set -eux export APP_PATH=/opt/applications export APP_NAME=Ares ...

  7. SSH 错误解决案例1:Read from socket failed: Connection reset by peer

    今天早上天天连接的开发机突然报出连接错误. 这个错误是SSH最常见错误,造成的原因也是千奇百怪(具体可goole),下面描述我的server的问题: 客户端报错 [root@server]# ssh ...

  8. (转)spring boot实战(第三篇)事件监听源码分析

    原文:http://blog.csdn.net/liaokailin/article/details/48194777 监听源码分析 首先是我们自定义的main方法: package com.lkl. ...

  9. python基础语法(一)

    Python的特点 1. 简单 Python是一种代表简单思想的语言. 2. 易学 Python有极其简单的语法. 3. 免费.开源 Python是FLOSS(自由/开放源码软件)之一. 4. 高层语 ...

  10. Json_decode:详解

    Json_decode:详解 json_decode - 对 JSON 格式的字符串进行编码   mixed json_decode ( string $json [, bool $assoc = f ...