1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| <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) 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)) { const key = RegExp.$1.trim() child.innerHTML = this.options.data[key] target = child 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>
|