热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

运用Proxy完成简朴的MVVM模子

绑定完成的汗青绑定的基础是propertyChange事宜。怎样得知viewModel成员值的转变一直是开辟MVVM框架的主要题目。主流框架的处置惩罚有一下三大类:别的开辟一套AP

绑定完成的汗青

绑定的基础是 propertyChange 事宜。怎样得知 viewModel 成员值的转变一直是开辟 MVVM 框架的主要题目。主流框架的处置惩罚有一下三大类:

  1. 别的开辟一套 API。典范框架:Backbone.js

Backbone 有本身的 模子类 和 鸠合类。如许做虽然框架开辟简朴运转效力也高,但开辟者不能不运用这套 API 操纵 viewModel,致使上手庞杂、代码烦琐。

  1. 脏搜检机制。典范框架:angularjs

特点是直接运用 JS 原生操纵对象的语法操纵 viewModel,开辟者上手简朴、代码简朴。但脏搜检机制随之带来的就是机能题目。这点在我别的的一篇博文 《Angular 1 深度剖析:脏数据搜检与 angular 机能优化》 有细致解说这里不另加赘述。

  1. 替换属性。典范框架:vuejs
    vuejs 把开辟者定义的 viewModel 对象(即 data 函数返回的对象)中一切的(除某些前缀开首的)成员替换为属性。如许既能够运用 JS 原生操纵对象的语法,又是主动触发 propertyChange 事宜,效力也高。但这类要领也有一些限定,后文会剖析。

Object.observe

Object.observe 是谷歌关于简化双向绑定机制的尝试,在 Chrome 49 中引入。然则由于机能等题目,并没有被其他各大浏览器及 ES 规范所接收。挣扎了一段时候后谷歌 Chrome 团队宣告收回 Object.observe 的发起,并在 Chrome 50 中完全删除了 Object.observe 完成。

Proxy

Proxy(代办)是 ES2015 到场的新特征,用于对某些基础操纵定义自定义行动,相似于其他语言中的面向切面编程。它的个中一个作用就是用于(部份)替换 Object.observe 以完成双向绑定。

比方有一个对象

let viewModel = {};

能够组织对应的代办类完成对 viewModel 的属性赋值操纵的监听:

viewModel = new Proxy(viewModel, {
set(obj, prop, value) {
if (obj[prop] !== value) {
obj[prop] = value;
console.log(`${prop} 属性被改成 ${value}`);
}
return true;
}
});

这时候一切对 viewModel 的属性赋值的操纵都不会直接见效,而是将这个操纵转发给 Proxy 中注册的 set 要领,个中的参数 obj 是原始对象(注重不能直接用 a,不然还会触发代办函数,形成无穷递归),prop 是被赋值的属性名,value 是待赋的值。
假如有:

viewModel.test = 1;

这时候就会输出 test 属性被改成 1

用 Proxy 完成简朴的单向绑定。

有了 Proxy 就能够得知 viewModel 中属性的变动了,还须要更新页面上绑定此属性的元素。

简朴起见,我们用 this 示意 viewModel 本身,运用 this.XXX 就示意依靠 XXX 属性。有 DOM 以下:


起首要取得一切运用了单向绑定的元素:

const bindingElements = [...document.querySelectorAll('[my-bind]')];

猎取绑定表达式:

bindingElements.forEach(el => {
const expression = el.getAttribute('my-bind');
});

由于取得的表达式是个字符串,须要组织一个函数去实行它,获得表达式的效果:

const expression = el.getAttribute('my-bind');
const result = new Function('"use strict";\nreturn ' + expression).call(viewModel);

代码中会动态建立一个函数,内容就是将字符串剖析实行后将其效果返回(相似 eval,但更平安)。将效果放到页面上就能够了:

el.textCOntent= result;

与上文的 viewModel 结合起来:

const bindingElements = [...document.querySelectorAll('[my-bind]')];
window.viewModel = new Proxy({}, { // 设置全局变量轻易调试
set(obj, prop, value) {
if (obj[prop] !== value) {
obj[prop] = value;
bindingElements.forEach(el => {
const expression = el.getAttribute('my-bind');
const result = new Function('"use strict";\nreturn ' + expression)
.call(obj);
el.textCOntent= result;
});
}
return true;
}
});

假如现实放在浏览器中运转的话,转变 viewModel 中属性的值就会触发页面的更新。

示例中写了轮回会更新一切绑定元素,比较好的体式格局是只更新对当前变动属性有依靠的元素。这时候就要剖析绑定表达式的属性依靠。
简朴起见能够运用正则表达式剖析属性依靠:

let match;
while (match = /this(?:\.(\w+))+/g.exec(expression)) {
match[1] // 属性依靠
}

增加事宜绑定

事宜绑定即绑定原生事宜,在事宜触发时实行绑定表达式,表达式挪用 viewModel 中的某个回调函数。

click 事宜为例。依然是猎取一切绑定了 click 事宜的元素,并实行表达式(表达式的值被抛弃)。与单项绑定差别的是:实行表达式须要传入事宜的 event 参数。

[...document.querySelectorAll('[my-click]')].forEach(el => {
const expression = el.getAttribute('my-click');
const fn = new Function('$event', '"use strict";\n' + expression);
el.addEventListener('click', event => {
fn.call(viewModel, event);
});
});

Function 对象的组织函数,前 n-1 个参数是天生的函数对象的参数名,末了一个是函数体。代码中组织了包括一个 $event 参数的函数,函数体就是直接实行绑定表达式。

双向绑定

双向绑定就是单项绑定和事宜绑定的结合体。绑定元素的 input 事宜来修正 viewModel 的属性,然后再单项绑定元素的 value 属性修正元素的值。

这里是一个较为完全的示例:http://sandbox.runjs.cn/show/…。完全的代码放在我的 GitHub 堆栈

运用 Proxy 完成双向绑定的优瑕玷

相较于 vuejs 的属性替换,Proxy 完成的绑定至少有以下三个长处:

  • 无需预先定义待绑定的属性。

vuejs 要做属性(getter, setter 要领)替换,起首须要晓得有哪些属性须要替换,如许致使必需预先定义须要替换的属性,也就是 vuejs 中的 data 要领。vuejs 中 data 要领必需定义完全一切绑定属性,不然对应绑定不能一般事情。
Vue 不能检测到对象属性的增加或删除:Property or method "XXX" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
Proxy 不须要,由于它监听的是悉数对象。

  • 对数组相性优越。

虽然说数组里的要领能够替换(push、pop等),然则数组下标却不能替换为属性,致使必需搞出一个 set 要领用于对数组下标赋值。

  • 更轻易调试的 viewModel 对象。

由于 vuejs 把对象中的一切成员悉数替换成了属性,假如想直接用 Chrome 的原生调试东西检察属性值,你不能不挨个去点属性背面的 (...):由于猎取属性的值现实上是实行了属性的 get 要领,实行一个要领可能会发生副作用,Chrome 把这个决定权留给开辟者。
Proxy 对象不须要。Proxyset 要领只是一层包装,Proxy 对象本身保护原始对象的值,天然也能够直接拿出原始值给开辟者看。检察一个 Proxy 对象,只须要睁开其内置属性 [[Target]] 即可看到原始对象的一切成员的值。你以至还能够看到包装原始对象的哪些 getset 函数——假如你感兴趣的话。

虽然说运用 Proxy 完成双向绑定的长处很明显,然则瑕玷也很明显:ProxyES2015 的特征,它没法被编译为 ES5,也没法 Polyfill。IE 天然全军尽没;其他各大浏览器完成的时候也较晚:Chrome 49、Safari 10。浏览器兼容性极大的限定了 Proxy 的运用。然则我置信,跟着时候的推移,基于 Proxy 的前端 MVVM 框架也会出如今开辟者面前。


推荐阅读
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • This post discusses an issue encountered while using the @name annotation in documentation generation, specifically regarding nested class processing and unexpected output. ... [详细]
  • 本文将继续探讨前端开发中常见的算法问题,重点介绍如何将多维数组转换为一维数组以及验证字符串中的括号是否成对出现。通过多种实现方法的解析,帮助开发者更好地理解和掌握这些技巧。 ... [详细]
  • 本文探讨了C++编程中理解代码执行期间复杂度的挑战,特别是编译器在程序运行时生成额外指令以确保对象构造、内存管理、类型转换及临时对象创建的安全性。 ... [详细]
  • 程序员如何优雅应对35岁职业转型?这里有深度解析
    本文探讨了程序员在职业生涯中如何通过不断学习和技能提升,优雅地应对35岁左右的职业转型挑战。我们将深入分析当前热门技术趋势,并提供实用的学习路径。 ... [详细]
  • 随着生活节奏的加快和压力的增加,越来越多的人感到不快乐。本文探讨了现代社会中导致人们幸福感下降的各种因素,并提供了一些改善建议。 ... [详细]
  • JavaScript中的数组是数据集合的核心结构之一,内置了多种实用的方法。掌握这些方法不仅能提高开发效率,还能显著提升代码的质量和可读性。本文将详细介绍数组的创建方式及常见操作方法。 ... [详细]
  • 本文介绍了如何在React和React Native项目中使用JavaScript进行日期格式化,提供了获取近7天、近半年及近一年日期的具体实现方法。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • Python自动化测试入门:Selenium环境搭建
    本文详细介绍如何在Python环境中安装和配置Selenium,包括开发工具PyCharm的安装、Python环境的设置以及Selenium包的安装方法。此外,还提供了编写和运行第一个自动化测试脚本的步骤。 ... [详细]
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
  • 使用JS、HTML5和C3创建自定义弹出窗口
    本文介绍如何结合JavaScript、HTML5和C3.js来实现一个功能丰富的自定义弹出窗口。通过具体的代码示例,详细讲解了实现过程中的关键步骤和技术要点。 ... [详细]
  • 本文探讨了如何利用HTML5和JavaScript在浏览器中进行本地文件的读取和写入操作,并介绍了获取本地文件路径的方法。HTML5提供了一系列API,使得这些操作变得更加简便和安全。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有