双向绑定
胖大人本胖
共 264 字
预计
4
分钟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class pubSub { constructor() { this.events = {}; } publish(event, ...args) { this.events[event].forEach(cb => cb(...args)); } subscribe(event,cb) { if(this.events[event]) { this.events[event].push(cb); } else { this.events[event] = [cb]; } } unSubscribe(event,callback) { this.events[event] = this.events[event].filter(cb => cb !== callback); } }
|
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
| class Vue extends EventTarget{ constructor(options) { super(); this.$options = options; this.compile(); this.$data = this.$options.data; this.observe(this.$options.data); } async observe(data) { if(!data || data.constructor.name !== 'Object') return; Object.keys(data).forEach(key => { this.defineReactive(data,key,data[key]) }) } defineReactive(obj,key,value) { const self = this; this.observe(value); Object.defineProperty(obj,key, { enumerable: true, configurable: true, get() { return value; }, set(newValue) { const eventName = new CustomEvent(key, {detail: {newValue}}); self.dispatchEvent(eventName); value = newValue; } }) } async compile() { const elem = document.querySelector(this.$options.el); const childNodes = elem.childNodes; this.parseHtml(childNodes); } parseHtml(childNodes) { [...childNodes].forEach(dom => { if (dom.nodeType === 1) { this.parseHtml(dom.childNodes) } else if(dom.nodeType === 3) { const reg = /\{\{\s*(\S+)\s*\}\}/g; if (reg.test(dom.textContent)) { const keys = RegExp.$1.split('.'); dom.textContent = this.$options.data[RegExp.$1]; this.addEventListener(RegExp.$1, ({detail: {newValue}}) => { dom.textContent = newValue; }) } } }) } render() {
} }
|