实现一个mvvm
最近在团队内做了一次vue原理分享,现场手写了一个乞丐版mvvm,这里记录一下这个mvvm实现的过程。
源码:https://github.com/keller35/mvvm
这个mvvm是基于发布订阅模式实现(也是vue本身的实现原理),最终达到的效果如下:
使用方式也跟vue一样:
<html lang="en"> <head> <meta charset="UTF-8"> <title>mvvm</title> </head> <body> <div id="app"> <input type="text" v-model="text"> {{ text }} <button @click="reset" style="display:block;">重置</button> </div> <script src="./index.js"></script> <script> var vm = new Mvvm({ el: 'app', data: { text: 'hello world' }, methods: { reset() { this.text = ''; }, }, }); </script> </body> </html>
实现很简单:
class Mvvm { constructor(options) { const { el, data, methods } = options; this.methods = methods; this.target = null; // 初始化dispatcher this.observe(this, data); // 初始化watcher this.compile(document.getElementById(el)); } observe(root, data) { for (const key in data) { this.defineReactive(root, key, data[key]); } } defineReactive(root, key, value) { if (typeof value == 'object') { return this.observe(value, value); } const dep = new Dispatcher(); Object.defineProperty(root, key, { set(newValue) { if (value == newValue) return; value = newValue; // 发布 dep.notify(newValue); }, get() { // 订阅 dep.add(this.target); return value; } }); } compile(dom) { const nodes = dom.childNodes; for (const node of nodes) { // 元素节点 if (node.nodeType == 1) { const attrs = node.attributes; for (const attr of attrs) { if (attr.name == 'v-model') { const name = attr.value; node.addEventListener('input', e => { this[name] = e.target.value; }); this.target = new Watcher(node, 'input'); this[name]; } if (attr.name == '@click') { const name = attr.value; node.addEventListener('click', this.methods[name].bind(this)); } } } // text节点 if (node.nodeType == 3) { const reg = /\{\{(.*)\}\}/; const match = node.nodeValue.match(reg); if (match) { const name = match[1].trim(); this.target = new Watcher(node, 'text'); this[name]; } } } } } class Dispatcher { constructor() { this.watchers = []; } add(watcher) { this.watchers.push(watcher); } notify(value) { this.watchers.forEach(watcher => watcher.update(value)); } } class Watcher { constructor(node, type) { this.node = node; this.type = type; } update(value) { if (this.type == 'input') { this.node.value = value; } if (this.type == 'text') { this.node.nodeValue = value; } } }
原理:
- 最根本的原理很简单,无非是基于发布订阅的消息通知模式,消息发出方来自mvvm中modal层的变法,而订阅方来自view层。
- modal层的变化,是通过对data设置setter来实现响应式,只要数据发生变化,通知所有订阅者。
- view层的订阅,则是在compile阶段,compile会对所有数据依赖进行收集,然后在getter中注册监听。
相关推荐
姜海强 2020-08-01
chenjinlong 2020-06-10
conganguo 2020-06-09
88473166 2020-05-14
89427412 2020-05-06
conganguo 2020-05-06
yw00yw 2020-05-04
conganguo 2020-04-25
86523296 2020-04-22
89427412 2020-04-22
yw00yw 2020-04-20
86523296 2020-04-11
檀木雨林 2020-04-11
yw00yw 2020-04-11
yw00yw 2020-04-09
howema 2020-02-21
闲来也无事 2020-02-19
codercheng 2020-02-15
檀木雨林 2020-02-15