数据绑定简介
数据绑定是一个通用的技术,用来绑定来自提供者和消费者的数据源并同步它们。
这是一个通用定义,概括了数据绑定技术的通用构建模块
- 一种定义数据提供者和消费者的语法
- 一种定义哪些变化会触发同步的语法
- 一种在提供者中监听这些变化的方法
- 当这些变化发生时运行的一个同步函数。从现在开始,我将把这个函数称为
handler()
。
以上的步骤在不同的数据绑定技术中会以不同的方式实现。接下来将会介绍两种技术,即脏检查和存取器方法。他们都有优缺点,我将在介绍后简要讨论。
脏检查
脏检查是最为人熟知的数据绑定方法。它的概念很简单,不需要复杂的语言特性,这使得它可以作为一个很好的候选缺省选择。
语法
定义提供者和消费者不要求任何特别的语法,只需要一个简单的 JavaScript 对象。
const provider = {
message: 'Hello World'
}
const consumer = document.createElement('p')
同步通常是提供者上的属性变化触发。需要监听变化的属性,必须明确映射到各自的 handler()
函数。
observe(provider, 'message', message => {
consumer.innerHTML = message
})
observe()
函数只保存 (provider, property) -> handler
映射供以后使用。
function observe(provider, prop, handler) {
provider._handlers[prop] = handler
}
这样,我们就有一个定义提供者和消费者的语法,以及一种为属性改变而注册 handler()
函数的方法。我们库的公共 API 已经准备好了,现在介绍其内部实现。
监听变化
脏检查因一个原因而被称为脏。它定时检查而不是直接监听属性变化。从现在起,我们把这个检查称为摘要周期。一个摘要周期遍历每一个由 observe()
函数添加的 (provider, property) -> handler
入口,并且检查自上次遍历以来属性值是否发生变化。如果变化则运行 handler()
函数。一个简单的实现类似如下:
function digest() {
providers.forEach(digestProvider)
}
function digestProvider (provider) {
for (let prop in provider._handlers) {
if (provider._prevValues[prop] !== provider[prop]) {
provider._prevValues[prop] = provider[prop]
handler(provider[prop])
}
}
}
digest()
函数需要一直不停地运行以确保状态同步。