码迷,mamicode.com
首页 > 其他好文 > 详细

数据绑定:视图到模型

时间:2015-08-25 20:55:25      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:

上一篇数据绑定:模型到视图简单的介绍了从模型到视图的绑定,而我们想要的不止如此,我们希望视图改变的时候也能影响到数据模型。应用最多的场景应该就是表单了,这样的话,改变了视图也就改变了要提交的数据,这样我们的工作量就可以大大减少。


事件,还是事件

在用户在表单内操作的时候,自然会通过键盘或者鼠标触发相应的事件,我们捕获这些事件进行处理,在事件处理函数里对模型进行操作。

一般的,对于DOM事件,框架都会用自定义的指令来做,比如angular里用ng-开头,regular里用on-开头。

 

不过有时候视图的改变并不是事件触发的,或者是用户在JS代码里更新了视图的某部分,比如: input.setAttribute(value, 1000) ,那么我们也要监听到然后改变数据模型。

一般来说,会通过订阅/发布(PubSub)这种模式来处理,也就是自定义事件,原理大概就是:

提前把某个自定义事件名称一系列的监听函数push进数组里,当收到fire/trigger/emit(名字真多)通知的时候,监听函数全部执行。

var events = (function(){
  var topics = {};
  var hOP = topics.hasOwnProperty;

  return {
    subscribe: function(topic, listener) {
      // Create the topic‘s object if not yet created
      if(!hOP.call(topics, topic)) topics[topic] = [];

      // Add the listener to queue
      var index = topics[topic].push(listener) -1;

      // Provide handle back for removal of topic
      return {
        remove: function() {
          delete topics[topic][index];
        }
      };
    },
    publish: function(topic, info) {
      // If the topic doesn‘t exist, or there‘s no listeners in queue, just leave
      if(!hOP.call(topics, topic)) return;

      // Cycle through topics queue, fire!
      topics[topic].forEach(function(item) {
              item(info != undefined ? info : {});
      });
    }
  };
})();

简单的实现来自Pub/Sub JavaScript Object。还有更加精细的实现:PubsubJS

脏检查

数据绑定:模型到视图的最后,给力脏检查双向绑定的例子。一般的情况下框架会自动进入$degist阶段,但在一些特殊情况下,用户也可以通过框架暴露的方法手动进行,像Regular就提供了$update方法。

MutationObserver

振奋人心的时候到了:

MutationObserver给开发者们提供了一种能在某个范围内的DOM树发生变化时作出适当反应的能力。

而且支持情况也还是凑合的:

技术分享

通过MutationObserver,我们可以获取到DOM树的变化,不管你是事件的还是莫名其妙的变化。。。。

用法也是极其的简单:

//设置要监察的行为
var
observeConfig = { attributes: true, childList: true, characterData: true, attributeOldValue :true, subtree: true, attributeFilter:[value] } var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; var observer = new MutationObserver(function(mutations) { //每当有变化就会触发次方法,循环打印变化的记录 mutations.forEach(function(record, i) { console.log(record); }); }); observer.observe(element, observeConfig);

这样的话,我们在监听函数里就可以为所欲为了。

不过这里其实有个问题,对于表单元素,比如输入框,输入或删除一些字符,并不会触发监听方法,像这样:input.value = xxx这样操作也不会触发。

这是因为MutationObserver只是监听DOM书的变化,也就是说Nodes和Attributes,而输入或删除以及直接value并不会引起DOM树的变化,打印一些input.getAttribute(‘value‘)你发现值根本没变!!!

所有还是要求助事件了。

input.onkeyup = function(e) {
    var target = e.target;
    target.setAttribute(value, target.value);
}

这样就OK了。

 

其实IE中早就实现了onpropertychange事件,不过标准里只有一个oninput只能监听value值,不过这也给兼容提供了一个思路。

 

DOM Attributes on the prototype chain

刚写完这篇博文,不小心看到了一篇文章:DOM Attributes now on the prototype chain,中文翻译在这里

Chrome在IE、Firefox也支持了原型链DOM,我觉得这也应该是视图到模型绑定的方式,我们可以给DOM节点上自定义属性,然后像这样:

Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
    get: function() { return true; },
    set: function() { /* some logic to set it up */ },
});

在setter里可以做我们想做的事情。可以轻易的实现像**-model之类的指令。

<input type="text" z-model="">
var data = {};
var input = document.querySelector(‘input‘);

Object.defineProperty(input, ‘z-model‘, {
    get: function() {
        return data.name;
    },
    set: function(n) {
        data.name = n;
        input.value = n;
    }
}); 

然后再简单一改,双向绑定也有了。。。

var data = {};
var _name = ‘init‘;
var input = document.querySelector(‘input‘);

Object.defineProperty(data, ‘name‘, {
    get: function() {
        return _name;
    },
    set: function(n) {
        _name = n; 
        input.value = n;
    }
});

Object.defineProperty(input, ‘z-model‘, {
    get: function() {
        return data.name;
    },
    set: function(n) {
        data.name = n;
        input.value = n;
    }
});

 

参考资料:

组件事件

DOM世界的观察者

MDN MutationObserver

测试是否支持DOMAttrModified

 

数据绑定:视图到模型

标签:

原文地址:http://www.cnblogs.com/zjzhome/p/4758346.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!