请选择 进入手机版 | 继续访问电脑版
在双向绑定的简单实现——基于“脏检测”中,我们使用“脏检测”的机制,实现了一个简单的双向绑定计数器。尽管逻辑比较清晰简单,性能也还可以,但每次都遍历DOM节点,也是会有一些性能浪费的。ES5提供了Object.defineProperty与Object.defineProperties两个API,允许我们为对象的属性增设getter/setter函数。利用它们,我们可以很方便地监听数据变更,并且在变更时加入自己的逻辑。
本文我将利用ES5对象的getter/setter机制,模仿Vue的原理,来实现一个简单的数据动态绑定(暂且称为Lue吧)。

语法设计

本次我基于Vue的三个指令:v-model、v-bind和v-click,来实现数据双向绑定(不考虑深层次对象的数据绑定)。DOM依然沿用上篇文章中的结构:
  1. [/code]我们希望使用类似Vue的语法创建一个Lue实例:
  2. [code]
复制代码
开始

开始的开始,我们需要创建一个Lue类:
  1. [/code]其中包含一个_init初始化函数,定义如下:
  2. [code]
复制代码
绑定数据对象的改造

为了实现双向绑定,首先我们需要使用Object.defineProperty对data中的数据对象进行改造,添加getter/setter函数,使其在赋值和取值时能够被监听。
  1. [/code]对data中的数据对象进行遍历调用convert:
  2. [code]
复制代码
在控制台做如下测试,可以看到已经成功添加了getter与setter:
数据动态绑定的简单实现——基于ES5对象的getter/setter机制-1.png
绑定函数的改造

对于methods域中的函数,由于API要求我们的函数作用域与vm.$data一致,因此需要对其中的函数进行改造:
  1. [/code]上述两个改造流程必须发生在初始化阶段,因此我们需要更改一下之前定义的_init函数:
  2. [code]
复制代码
至此,对于Lue实例的数据与函数的初始化就完成了。下面需要考虑的是,当数据发生变化时,如何更新DOM元素呢?
最容易想到的一个做法是遍历所有含有v-bind指令的DOM模板,利用相应的绑定数据在内存中拼装成一个fragment,然后再将新的fragment替换旧的DOM结构。但是这个方案存在两个问题:
    修改未绑定至DOM的数据时,也会引发DOM的重新渲染。修改某个数据会导致所有DOM重新渲染,而非只更新数据变动了的相关DOM 。
为了解决这个问题,我们需要引入Directive。
Directive(指令)

Directive的作用就是建立一个DOM节点和对应数据的映射关系。它的定义和原型方法如下:
  1. [/code][code]
复制代码
如此便实现了更改某个数据,只触发其对应DOM节点的更新。下面我们需要考虑的问题是,如何让数据对象的setter在触发时,调用与之相关的directive?

首先我们需要在实例化时建立一个_binding对象,该对象集合了真正与DOM绑定的那些数据对象(data中声明的对象的子集)。因此我们又一次修改_init函数:
  1. [/code]_binding对象中属性的一个例子如下:
  2. [code]
复制代码
然后我们改写遍历数据域的函数与绑定数据时的setter函数:
  1. [/code][code]
复制代码
如此,我们便能实现在数据变更后,进行精准的DOM节点更新。
编译DOM节点

实现双向绑定的最后一步,就是编译带有v-model、v-click与v-bind指令的DOM节点。我们加入一个名为_compile的原型函数:
  1. [/code]改写Lue的_init原型方法,使其在初始化时即对DOM进行编译:
  2. [code]
复制代码
至此,我们便实现了一个基于getter/setter,模仿Vue的简单的双向绑定。整个体系搭建并不复杂,只需要注意其中三个核心的部分:getter/setter,Directive以及binding。细心的读者不难发现,在本文的实现中,如果线程频繁触发数据变更,会导致DOM频繁更新,非常影响性能。在真正的生产环境中,DOM的更新不是数据变更后立马更新,而是被加入到批处理队列,等待主线程运行完后再进行批处理。
整个Lue实例结构如下:
数据动态绑定的简单实现——基于ES5对象的getter/setter机制-2.png
完整代码

[code][/code]推荐阅读

Vue源码解析

ES5关于Object的新特性
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|翁笔

© 2001-2018 Wengbi.com

返回顶部