简单实现一个mvvm Posted on 2019-07-01 什么是MVVMMVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。 上代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293<html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title></head><body><div id="app"> <h>姓名:</h> <p>{{name}}</p> <h>姓名:</h> <p>{{name}}</p> <h>年龄:</h> <p>{{age}}</p></div><script> let target = null class Mvvm { constructor(options) { this.options = options const root = document.querySelector(options.el) this.observer(options.data) // 初始化dom树 主要是填充绑定的值和触发各个值的getter this.compile(root) } observer(data) { Object.keys(data).forEach(key => { const dep = new Dep() data['_' + key] = data[key] Object.defineProperty(data, key, { set(newVal) { data['_' + key] = newVal dep.update(newVal) }, get() { target && dep.addSub(target) return data['_' + key] }, }) }) } compile(root) { Array.prototype.forEach.call(root.childNodes, child => { // 判断该节点是不是最底层节点 是就执行 不是就递归继续找 if (!child.firstElementChild && /\{\{(.*)\}\}/.test(child.innerHTML)) { // 拿到RegExp的全局只读属性 const key = RegExp.$1.trim() child.innerHTML = this.options.data[key] // 将该节点赋給target target = child // 触发这个key的get方法 将target以闭包的形式传到dep实例 this.options.data[key] target = null } else { this.compile(child) } }) } } class Dep { constructor() { this.subs = [] } addSub(sub) { this.subs.push(sub) } update(val) { this.subs.forEach(sub => { sub.innerHTML = val }) } } const vm = new Mvvm({ el: '#app', data: { name: '暂无', age: 20, }, }) setTimeout(function () { vm.options.data.name = 'demo' vm.options.data.age = 30 }, 2000)</script></body></html>