原始 JS 中的双向数据绑定(POC)
作为前端工程师,我们主要使用库和/或框架来开发和维护复杂的 Web 应用,但底层究竟是什么?你会问自己这个问题吗?你不会!?好吧,你应该问!🙃
在这篇文章中,我想将前面的示例扩展为双向数据绑定。🕺
双向数据绑定🤓
如果您不熟悉这个概念,双向数据绑定意味着状态的每个更改都会立即传播到视图(反之亦然)。
查看下面的演示以获得一个简单的示例:
演示
让我们分解一下
我们需要什么来进行双向数据绑定?
- 在我们的示例 HTML 中是一个视图。
- 一种状态,用 JavaScript 保存在内存中。
主要特点是:
每次状态改变时,视图都需要更新(单向数据绑定)
但是也
每次视图发生变化时,状态都需要更新
假设我们有一个 HTML视图:
<div class="field">
<label for="name">Enter your name:</label>
<input id="name" type="text" name="name" data-model="name" />
</div>
<div class="field">
<label for="title">Enter your title:</label>
<input id="title" type="text" name="title" data-model="title" />
</div>
<div class="results">
<h1 data-binding="name"></h1>
<h2 data-binding="title"></h2>
</div>
和一个州:
const state = {
name: 'Francesco',
title: 'Front-end Developer'
};
我们第一次就可以轻松设置视图:
document.querySelector('[data-binding="name"]').innerHTML = state.name
document.querySelector('[data-binding="title"]').innerHTML = state.title
document.querySelector('[data-model="name"]').value = state.name
document.querySelector('[data-model="title"]').value = state.title
但是我们想要一些魔法,以便当我们更新状态时:
state.name = 'Richard'
state.title = 'Technical Lead'
视图也应该更新。
set
为了实现这一点,我们可以修改对象属性的默认行为state
,这样除了更新状态之外,它还会更新我们的视图。
在 JavaScript 中实现这一点的一种方法是使用代理对象:
const createState = (state) => {
return new Proxy(state, {
set(target, property, value) {
target[property] = value; // default set behaviour
render(); // updates the view every time the state changes
return true;
}
});
};
const state = createState({
name = 'Francesco'
title = 'Front-end Engineer'
});
借助代理的强大功能,每次我们更新 时state
,该render
函数都会被调用。
的一个可能实现render
如下:
const render = () => {
document.querySelector('[data-binding="name"]').innerHTML = state.name;
document.querySelector('[data-binding="title"]').innerHTML = state.title;
document.querySelector('[data-model="name"]').value = state.name;
document.querySelector('[data-model="title"]').value = state.title;
};
我们只差最后一点。每次修改view时,state 都应该随之改变。我们可以通过在输入框中添加一个事件监听器来实现这一点:😎
const listener = (event) => {
state[event.target.dataset.model] = event.target.value;
});
document.querySelector('[data-model="name"]').addEventListener('keyup', listener);
document.querySelector('[data-model="title"]').addEventListener('keyup', listener);
瞧!魔术完成了!👨💻