原理:
实现响应式需要: 1.数据联动(双向绑定) 2.需要捕获到修改
实现原理: 发布订阅 + 数据劫持 Object.defineProperty
双向绑定通过Object.defineProperty ,但要实现响应式还缺少通知,于是加入一个发布订阅
初始化加载:
使用变量的模板 —-> 生成虚拟Dom —->生成真实Dom
更新时:
劫持数据(data) —>watcher(可以看做是整个data) —-发布—> 使用变量的模板 —-> 更新虚拟Dom —->更新真实
代码
<body><div id="app">订阅视图1-<span class="box-1"></span>订阅视图2-<span class="box-2"></span></div></body><script>// 订阅器模型let Dep = {clientList: {}, //容器//添加订阅 key: 唯一id, fn: 做什么事listen: function (key, fn) {//(短路表达式)是否添加过订阅 没有则为[] 并添加执行事件到clientList容器 统一执行(this.clientList[key] || (this.clientList[key] = [])).push(fn)},//发布trigger: function () {//不接收参数 而是通过arguments 此处转换为真数组Array.prototype.slice.call(arguments);//shift() 方法从数组中删除第一个元素,并返回该元素的值let key = Array.prototype.shift.call(arguments);//获取订阅的事件let fns = this.clientList[key];//如果没有事件if (!fns || fns.length === 0) {return false;}//执行事件//for循环简写方式 定义变量i和fn//for (let i = 0, fn; fn = fns[i++];) {//fn.apply(this, arguments)//}for (let i = 0; i < fns.length; i++) {fns[i].apply(this, arguments)}}}//数据劫持let dataHi = function ({data,tag,datakey,selector}) {let value = '';//获取目标元素let el = document.querySelector(selector);Object.defineProperty(data, datakey, {get: function () {return value},set: function (val) {value = val//发布Dep.trigger(tag, val)}})//先订阅 后发布//订阅 tag=目标元素Dep.listen(tag, function (text) {el.innerText = text;})}//调用let obj = {};dataHi({data: obj,tag: 'view-1',datakey: 'one',selector: '.box-1'})dataHi({data: obj,tag: 'view-2',datakey: 'two',selector: '.box-2'})//初次渲染 一次obj.one = '这是视图1'obj.two = '这是视图2'//更新时 劫持数据,更新这赋值重新渲染 N次</script>

