photoshop网站模板设计教程,手机网站支持微信支付吗,周口logo设计公司,做网站不好做双向数据绑定是非常重要的特性 —— 将JS模型与HTML视图对应#xff0c;能减少模板编译时间同时提高用户体验。我们将学习在不使用框架的情况下#xff0c;使用原生JS实现双向绑定 —— 一种为Object.observe_(译注#xff1a;现已废弃#xff0c;作者写博客时为14年11月)能减少模板编译时间同时提高用户体验。我们将学习在不使用框架的情况下使用原生JS实现双向绑定 —— 一种为Object.observe_(译注现已废弃作者写博客时为14年11月)另一种为覆盖get / set。PS: 第二种更好详情请参阅底部的TL;DR(译注too longdont read. 直译为“太长不想看”意译为“简单粗暴来吧”)_。1: Object.observe 和 DOM.onChangeObject.observe()是一种新特性其在ES7中实现但在最新的Chrome中已可用 —— 允许对JS对象进行响应式更新。简单说就是 —— 只要对象(的属性)发生变化就调用回调函数。一般用法为log console.loguser {}Object.observe(user, function(changes){changes.forEach(function(change) {user.fullName user.firstName user.lastName;});});user.firstName Bill;user.lastName Clinton;user.fullName // Bill Clinton复制代码这很方便且能实现响应式编程 —— 保证所有内容都是最新的。如下//user {};div $(#foo);Object.observe(user, function(changes){changes.forEach(function(change) {var fullName (user.firstName || ) (user.lastName || );div.text(fullName);});});user.firstName Bill;user.lastName Clinton;div.text() //Bill Clinton复制代码如上我们自己实现了模型到数据的绑定封装一下(译注此处原文为Let’s DRY ourselves with a helper function. DRY即 dont repeat yourself)//function bindObjPropToDomElem(obj, property, domElem) {Object.observe(obj, function(changes){changes.forEach(function(change) {$(domElem).text(obj[property]);});});}user {};bindObjPropToDomElem(user,name,$(#foo));user.name William$(#foo).text() //William复制代码换一种方式 —— 将DOM元素与JS值绑定起来。简单的方法是使用jQuery.change//$(#foo).val();function bindDomElemToObjProp(domElem, obj, propertyName) {$(domElem).change(function() {obj[propertyName] $(domElem).val();alert(user.name is now user.name);});}user {}bindDomElemToObjProp($(#foo), user, name);//enter obama into inputuser.name //Obama.复制代码简直不要太方便在实际开发时可以将两者结合通过函数来创建一个双向数据绑定function bindObjPropToDomElem(obj, property, domElem) {Object.observe(obj, function(changes){changes.forEach(function(change) {$(domElem).text(obj[property]);});});}function bindDomElemToObjProp(obj, propertyName, domElem) {$(domElem).change(function() {obj[propertyName] $(domElem).val();console.log(obj is, obj);});}function bindModelView(obj, property, domElem) {bindObjPropToDomElem(obj, property, domElem)bindDomElemToObjProp(obj, propertyName, domElem)}复制代码注意在双向绑定时需正确进行DOM操作因为不同的DOM元素(inputdivtextareaselect)有不同的取值方式(textval)。同时注意双向数据绑定并不是必须的 —— “输出型”元素一般不需要视图到模型的绑定而“输入型”元素一般不需要模型到视图的绑定。下面为第二种方式2: 深入get和set属性上面的解决方法并不完美。比如直接的修改并不会自动触发jQuery的“change”事件 —— 例如直接通过代码对DOM进行修改比如以下代码不起作用$(#foo).val(Putin)user.name //still Obama. Oops.复制代码现在我们来用一种更激进的方式实现 —— 重写getter和setter。因为我们不仅要监测变化我们将重写JS最底层的功能即get/setting变量的能力所以不那么“安全”。后面我们将会看到这种元编程的方式有多强大。那么如果我们可以重写get和set对象值的方法会怎么样呢这也是数据绑定的实质。用 Object.defineProperty() 即可实现.其实以前就有已废弃且非标准实现方式但通过Object.defineProperty的实现方式更好(最重要的是标准)如下所示user {}nameValue Joe;Object.defineProperty(user, name, {get: function() { return nameValue },set: function(newValue) { nameValue newValue; },configurable: true //to enable redefining the property later});user.name //Joeuser.name Bobuser.name //BobnameValue //Bob复制代码现在user.name是nameValue的别名。但可做的不仅仅是创建新的变量名 - 我们可以通过它来保证模型和视图的一致。如下//Object.defineProperty(user, name, {get: function() { return document.getElementById(foo).value },set: function(newValue) { document.getElementById(foo).value newValue; },configurable: true //to enable redefining the property later});复制代码user.name现在绑定到#foo元素。这种底层的方式非常简洁 —— 通过定义(或扩展)变量属性的get / set实现。由于实现非常简洁因此可以根据情况轻松扩展/修改代码 —— 仅绑定或扩展get / set中的一个比如绑定其他数据类型。可封装如下function bindModelInput(obj, property, domElem) {Object.defineProperty(obj, property, {get: function() { return domElem.value; },set: function(newValue) { domElem.value newValue; },configurable: true});}复制代码使用user {};inputElem document.getElementById(foo);bindModelInput(user,name,inputElem);user.name Joe;alert(input value is now inputElem.value) //input is now Joe;inputElem.value Bob;alert(user.name is now user.name) //model is now Bob;复制代码注意上面的domElem.value只对input元素有效。(可在bindModelInput中扩展对不同的DOM类型使用对应的方法来设置它的值)。思考注意上面的实现中在某些场景下视图可认为是符合SPOT (single point of truth )原则的但该原则常常被忽视(因为双向数据绑定也就意味着等价)。然而深究下去可能就会发现问题了在实际开发中也会遇到。 —— 比如当删除DOM元素时关联的模型会自动注销么答案是不会。bindModelInput函数在domElem元素上创建了一个闭包使DOM元素常驻在内存中—— 并保持模型与模型的绑定关系 —— 即使DOM元素被移除。即使视图被移除了但模型依旧存在。反之一样 —— 若模型被移除了视图依然能够正常显示。在某些刷新视图和模型无效的情况下理解这些内部原理就能找到原因了。(译注SPOT简单翻译为“单点原则”即引起变化最好的是由单一入口引起的而不是由多个入口引起的比如一个函数其返回结果最好仅由参数决定这样输入和输出才能一致而不会由于其他变化导致用一个输入会出现不同的输出)这种自己实现的数据绑定方法与Knockout或Angular等框架的数据绑定相比有一些优点例如理解一旦掌握数据绑定的源码不仅理解更深入而且也能对其进行扩展和修改。性能不要将所有东西都绑定在一起只绑定所需的避免监测过多对象避免锁定若所用的框架不支持数据绑定则自行实现的数据绑定更强大缺点是由于不是真正的绑定(没有脏检查)有些情况会失败 —— 视图更新时不会触发模型中的数据所以当试着同步视图中的两个DOM元素时将会失败。也就是说将两个元素绑定到同一个模型上时只有更新模型则两个元素才会被正确更新。可以通过自定义一个更新函数来实现////input1 document.getElementById(input1)input2 document.getElementById(input2)user {}Object.defineProperty(user, name, {get: function() { return input1.value; },set: function(newValue) { input1.value newValue; input2.value newValue; },configurable: true});input1.onchange function() { user.name user.name } //sync both inputs.复制代码TL;DR当需要使用原生JS创建模型和视图的双向数据绑定时如下function bindModelInput(obj, property, domElem) {Object.defineProperty(obj, property, {get: function() { return domElem.value; },set: function(newValue) { domElem.value newValue; },configurable: true});}//user {}bindModelInput(user,name,document.getElementById(foo)); //hey presto, we now have two-way data binding.复制代码