推荐答案
// www.javascriptcn.com code example
class SimpleVue {
constructor(options) {
this.$options = options;
this._data = options.data;
this._proxyData(this._data);
this._compile(options.el);
}
_proxyData(data) {
for (let key in data) {
Object.defineProperty(this, key, {
get() {
return data[key];
},
set(newValue) {
data[key] = newValue;
this._updateDOM(key, newValue);
}
});
}
}
_compile(el) {
const element = document.querySelector(el);
const children = element.children;
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child.hasAttribute('v-model')) {
const key = child.getAttribute('v-model');
child.value = this._data[key];
child.addEventListener('input', () => {
this[key] = child.value;
});
}
}
}
_updateDOM(key, value) {
const elements = document.querySelectorAll(`[v-model="${key}"]`);
elements.forEach(element => {
element.value = value;
});
}
}
// 使用示例
const app = new SimpleVue({
el: '#app',
data: {
message: 'Hello, Vue!'
}
});本题详细解读
1. 实现思路
双向数据绑定的核心是通过 Object.defineProperty 来劫持数据的 get 和 set 操作。当数据发生变化时,自动更新视图;当视图发生变化时,自动更新数据。
2. 代码解析
_proxyData方法:遍历data对象中的每个属性,使用Object.defineProperty将其代理到SimpleVue实例上。这样,当访问或修改这些属性时,会触发get和set方法。_compile方法:遍历指定元素的所有子元素,查找带有v-model属性的元素。将这些元素的值初始化为data中对应的值,并为其添加input事件监听器。当输入框内容发生变化时,更新对应的数据。_updateDOM方法:当数据发生变化时,更新所有绑定该数据的 DOM 元素的值。
3. 使用示例
在 HTML 中,可以通过以下方式使用:
<div id="app">
<input type="text" v-model="message">
<p>{{ message }}</p>
</div>当输入框内容发生变化时,message 数据会自动更新,并且页面中所有绑定 message 的地方都会同步更新。
4. 注意事项
- 该实现是一个简化版本,仅支持
v-model指令,并且只处理了文本输入框的情况。 - 实际应用中,Vue.js 等框架会处理更多的指令和复杂的场景,如列表渲染、条件渲染等。