答案:通过Object.defineProperty劫持数据,Dep收集依赖,Watcher监听变化并更新视图,Compiler解析模板指令,最终实现数据与视图的双向绑定。

实现一个简单的MVVM框架,关键在于理解数据绑定、响应式系统和视图更新机制。MVVM的核心是将数据模型(Model)与视图(View)通过 ViewModel 解耦,当数据变化时自动更新视图,反之亦然。下面从零开始一步步构建一个极简的 MVVM 框架,帮助理解其底层原理。
1. 响应式数据劫持(Observer)
要实现数据变化自动通知视图更新,首先要让 JavaScript 对象的属性变得“可观测”。我们可以利用 Object.defineProperty 来劫持对象的 getter 和 setter。
注意:现代框架如 Vue 3 已使用 Proxy 实现,但 defineProperty 更易于理解原理。
定义一个 Observer 类,遍历对象的所有属性并进行监听:
function defineReactive(obj, key, val) { // 递归监听子对象 observe(val); const dep = []; // 存储依赖(Watcher) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { // 收集依赖 if (Dep.target) { dep.push(Dep.target); } return val; }, set(newVal) { if (newVal === val) return; val = newVal; observe(newVal); // 新值如果是对象也需监听 // 通知所有依赖更新 dep.forEach(watcher => watcher.update()); } });}function observe(obj) { if (typeof obj !== 'object' || obj === null) { return; } Object.keys(obj).forEach(key => { defineReactive(obj, key, obj[key]); });}
2. 依赖收集与发布订阅(Dep)
在 getter 中收集依赖,在 setter 中触发更新。我们需要一个依赖管理器 Dep 来统一处理。
立即学习“Java免费学习笔记(深入)”;
class Dep { constructor() { this.subs = []; } addSub(watcher) { this.subs.push(watcher); } notify() { this.subs.forEach(watcher => watcher.update()); }}// 全局唯一正在执行的 WatcherDep.target = null;
修改 defineReactive 中的 dep 逻辑,使用真正的 Dep 类:
function defineReactive(obj, key, val) { observe(val); const dep = new Dep(); Object.defineProperty(obj, key, { get() { if (Dep.target) { dep.addSub(Dep.target); } return val; }, set(newVal) { if (newVal === val) return; val = newVal; observe(newVal); dep.notify(); } });}
3. 视图更新器(Watcher)
Watcher 是连接数据和视图的桥梁。它会在初始化时读取对应的数据,触发 getter,从而被收集到依赖中。当数据变化时,执行回调函数(比如更新 DOM)。
class Watcher { constructor(vm, expr, cb) { this.vm = vm; this.expr = expr; this.cb = cb; // 保存初始值 this.value = this.get(); } get() { Dep.target = this; // 标记当前 Watcher const value = this.vm.$data[this.expr]; // 触发 getter,完成依赖收集 Dep.target = null; return value; } update() { const oldValue = this.value; const newValue = this.vm.$data[this.expr]; if (newValue !== oldValue) { this.value = newValue; this.cb(newValue); } }}
4. 模板解析与指令绑定(Compiler)
我们需要解析 DOM 模板中的 {{}} 插值语法,并为对应的节点创建 Watcher。
class Compiler { constructor(el, vm) { this.el = document.querySelector(el); this.vm = vm; this.compile(this.el); } compile(node) { const childNodes = node.childNodes; Array.from(childNodes).forEach(n => { if (n.nodeType === 1) { // 元素节点 this.compileElement(n); } else if (n.nodeType === 3) { // 文本节点 this.compileText(n); } if (n.childNodes && n.childNodes.length) { this.compile(n); } }); } compileText(node) { const text = node.textContent; const reg = /{{(.+?)}}/g; if (reg.test(text)) { const expr = RegExp.$1.trim(); node.textContent = text.replace(reg, this.vm.$data[expr]); // 创建 Watcher 监听数据变化 new Watcher(this.vm, expr, newValue => { node.textContent = text.replace(/{{(.+?)}}/g, newValue); }); } } compileElement(node) { // 可扩展 v-model、v-on 等指令 const attrs = node.attributes; Array.from(attrs).forEach(attr => { const attrName = attr.name; const exp = attr.value; if (attrName.startsWith('v-model')) { node.value = this.vm.$data[exp]; new Watcher(this.vm, exp, value => { node.value = value; }); node.addEventListener('input', e => { this.vm.$data[exp] = e.target.value; }); } }); }}
5. 整合为 MVVM 类
最后封装一个 MVVM 构造函数,整合所有模块。
class TinyVue { constructor(options) { this.$el = options.el; this.$data = options.data; // 数据响应化 observe(this.$data); // 数据代理到实例上(可选) Object.keys(this.$data).forEach(key => { this.proxyData(key); }); // 编译模板 new Compiler(this.$el, this); } proxyData(key) { Object.defineProperty(this, key, { get() { return this.$data[key]; }, set(newVal) { this.$data[key] = newVal; } }); }}
使用示例:
const app = new TinyVue({ el: '#app', data: { message: 'Hello MVVM' } });{{ message }}
输入框内容变化时,会触发数据更新,进而自动更新 p 标签的内容,实现双向绑定。
基本上就这些。这个极简 MVVM 实现了响应式数据、依赖收集、视图更新和基本指令解析,虽然功能有限,但清晰展示了 MVVM 的核心原理:数据劫持 + 依赖追踪 + 视图同步。不复杂但容易忽略细节,比如依赖收集时机和 Watcher 的正确触发。
以上就是从零实现一个简单的MVVM框架_javascript框架原理的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1534228.html
微信扫一扫
支付宝扫一扫