数据绑定:视图到模型

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


事件,还是事件

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

一般的,对于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

时间: 2024-10-08 19:18:29

数据绑定:视图到模型的相关文章

ASP.NET MVC5(二):控制器、视图与模型

前言 本篇博文主要介绍ASP.NET MVC中的三个核心元素:控制器.视图与模型,以下思维导图描述了本文的主要内容. 控制器 控制器简介 在介绍控制器之前,简单的介绍一下MVC工作原理:URL告知路由机制该使用哪个控制器(Controller),调用该控制器中的哪个方法(Action),并为该方法提供需要的参数.控制器响应用户的输入,在响应时修改模型(Model),并决定使用哪个视图(View),并对该视图进行渲染.注意:MVC模式提供的是方法调用结果,而不是动态生成的页面. 以上内容对于初学者

Nodejs之MEAN栈开发(二)----视图与模型

上一节做了对Express做了简单的介绍,提出了controller,介绍了路由.这一节将重点放到视图和模型上,完成几个静态页面并部署到heroku上. 导航 前端布局使用bootstrap,从官网下载后置于public文件夹下.打开layout.jade 先做一个导航. doctype html html head meta(name='viewport', content='width=device-width, initial-scale=1.0') title= title link(r

学习IOS开问题篇--视图的模型控件属性写在私有分类中的原因

在说原型模式之前,我们先来看java里面的深复制和浅复制: 1. 浅复制:被复制的对象的所有变量都持有和原来对象的变量相同的值,而所有的对其他对象的引用都指向原来的对象. 2. 深复制:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他变量的对象.那些引用其他对象的变量将指向被复制过来的新对象,而不是原来那些被引用的对象.深复制需要把要复制的对象的所有引用都复制一遍. 这两者的区别就是关于引用对象的处理,浅复制是不考虑引用对象,而深复制需要考虑引用对象的问题. 对java中的clon

angular.js 中同步视图和模型数据双向绑定,$watch $digest $apply 机制

Angular.js 中的特性,双向绑定. 让视图的改变直接反应到数据中,数据的改变又实时的通知到视图,如何做到的? 这要归功于 scope 下面3个重要的方法: $watch $digest $apply 他们的区别是什么,我们来介绍下: $watch 这是一个监听 scope 上数据的监听器 方法说明: $scope.$watch('参数',function(newValue,oldValue){ //逻辑处理 }) 上面我们就是创建了一个监听器. ‘参数’ 就是$scope对象下的一个对象

数据绑定:模型到视图

Object.defineProperty 听说vuejs和avalon都是使用这种方式实现的. Object.defineProperty最早是由IE8实现的,但是IE8的实现有许多问题而且不能hack...所以vuejs才支持IE9+,avalon才使用VBScript这个鬼. 我们可以在Object.defineProperty里用getter和setter方法来定义对象的属性,这个属性叫存储器属性(JavaScript权威指南的翻译,JavaScript高级程序设计翻译为访问器属性,英文

springMVC4(7)模型视图方法源代码综合分析

在完整web开发中.springMVC主要充当了控制层的角色.它接受视图层的请求.获取视图层请求数据,再对数据进行业务逻辑处理.然后封装成视图层须要的模型数据,再将数据导向到jsp等视图界面. 在前面,我们通过对@RequestMapping和方法入參绑定的分析,完毕了视图层->控制层的数据交接,然后业务逻辑处理主要由Service层进行.那么接下来非常关键的就是,怎样将视图数据导向到特定的视图中. 广泛意义上,视图,并不是是单指前端界面如jsp\html等.我们可能须要给安卓.IOS等写后台接

[.net 面向对象程序设计深入](6).NET MVC 6 —— 模型、视图、控制器、路由等的基本操作

[.net 面向对象程序设计深入](6).NET MVC 6 —— 模型.视图.控制器.路由等的基本操作 1. 使用Visual Studio 2015创建Web App (1)文件>新建>项目,选择Web>ASP.NET Web 应用程序 (2)在新项目MyFirstWebApp对话框中,选择ASP.NET 5模板>Web Application 由于是RC版,这里的”添加单元测试“暂时不能选,上面的WebForms MVC WebAPI将合并,前面一节介绍过了,因此也不需要再选

OPENCV学习笔记3-4_使用模型-视图-控制器设计应用程序

此节介绍的架构模式(MVC),将联合使用模型-视图-控制器(Model-View-Controller)三个模式以及其他的类.其清晰地分离程序中的逻辑部分与用户交互部分.此节将使用MVC模式构建一个基于QT的图形界面应用程序. 模型包含关于应用程序的信息,它拥有所有由应用程序处理的数据.当出现新的数据,它将告知控制器,后者要求视图来显示结果.通常模型将集合多个算法,它们很有可能按照策略模式进行实现. 视图职责之一是发送用户的命令到控制器.当新数据可用时,它会刷新自己以显示新的信息. 控制器将视图

QML中的模型/视图 十二

QML中对于数据的存储和显示使用模型/视图框架. 1. QML数据模型 视图项目(如ListView.GridView和Repeater等)需要使用数据模型来为其提供数据进行显示.这些项目通常也需要一个委托(delegate)组件来为模型中的每一个条目创建一个实例.模型可以是静态的,也可以进行动态的修改.插入.移除或者移动项目.Qt帮助参考QML Data Models关键字. Item{ width:200; height:250 ListModel{ id:myModel ListEleme