class Watch { constructor(context) { this.page = context this.observers = new Map() this.init() } // 将 watch 数据写入观察者队列 init() { const ctx = this.page Object.keys(ctx.watch).forEach(path => { if (this.inData(path)) { this.observers.set(path, ctx.watch[path]) } }) } // 更新值并触发回调 不更新视图 data(path, newVal) { if (this.inData(path)) { this.setter(this.page.data, path, newVal) } } // 更新值并触发回调 并更新视图 setData(obj) { const oldData = JSON.parse(JSON.stringify(this.page.data)); this.page.setData(obj) Object.keys(obj).forEach(path => { if (this.observers.has(path)) { this.notify(path, obj[path], this.getter(oldData, path)) } }) } // 触发key的对应回调 notify(key, newVal, oldVal) { if (!this.observers.has(key)) return this.observers.get(key).call(this.page, newVal, oldVal) } // 删除观察者 unSubscribe(key) { this.observers.delete(key) } /** * 根据路径设置 data 值 * @param {string} path * @param {any} newVal */ setter(data, path, newVal) { if (!this.inData(path)) return let oldVal const pathArr = this._getPathArr(path) let res = pathArr.reduce((res, currentPath, currentIndex) => { // assign the new value to the key if (currentIndex === pathArr.length - 1) { oldVal = res[currentPath] res[currentPath] = newVal } return res[currentPath] }, data) if (this.observers.has(path)) { this.notify(path, newVal, oldVal) } return res } /** * getter 根据路径获取对应 key 的 value * * @param {object} data data 对象 * @param {string} path data 对象下的某一键值对的索引 * @return {any} keyValue * * e.g. * var data = {"a":{"b":{"c":{"d":123}}}} * getter(data, 'a.b[c]') // return {"d":123} */ getter(data, path) { const pathArr = this._getPathArr(path) return pathArr.reduce((res, currentPath) => { const currentValueType = Object.prototype.toString.call(res) return /String|Number|Boolean|Null|Undefined/.test(currentValueType) ? undefined : res[currentPath] }, data) } // check if data.path exist inData(path) { return this.getter(this.page.data, path) !== undefined } _getPathArr(path) { const REG_KEY = /\[((?:\S+?))\]|\./g return path.toString().split(REG_KEY).filter(item => !!item) } } export default Watch