学习日记-vue双向绑定

243 阅读1分钟
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>Document</title>
	</head>
	<body>
		<div id="root"></div>
		<script>
            // 观察者
			class watcher {
				constructor(vm, exp, cb) {
					this.vm = vm;
					this.exp = exp;
					this.cb = cb;
					this.value = this.get();
				}
				update() {
					var value = this.vm.data[this.exp];//新数据
					if (value == this.value) {
						//如果数据无变化
						return false;
					} else {
                        //如果变化了 执行回调函数
						this.cb(this.vm, this.exp,value,this.value);
					}
				}
				get() {
                    Dep.target = this;
					var value = this.vm.data[this.exp];
					Dep.target = null;
					return value;
				}
			}
			//观察者队列
			class Dep {
				constructor(list = []) {
					this.list = list;
				}
				addWatch(item) {
					this.list.push(item);
				}
				notify() {
					this.list.forEach(item => item.update());
				}
            }

			function defineReactive(vm,data, key, val) {
				observe(vm,val);
				let dep = new Dep();
                vm._oberve=Object.defineProperty(data, key, {
					enumerable: true,
					configurable: true,
					get() {
                        console.log('get', key);
                        // 此时侦测到的数据进行push操作
						if (Dep.target) {
                            dep.addWatch(Dep.target);
                        }
						return val;
					},
					set(newVal) {
                        console.log('set', data, key);
                        // 如果数据重新赋值了,则刷新dep队列
						val = newVal;
						dep.notify();
					}
                });
                vm._dep=dep
			}
			//数据劫持中心
			function observe(vm,data) {
                // 只要对象才进行
				if (data instanceof Object && data) {
					Object.keys(data).forEach(item => {
						defineReactive(vm,data, item, data[item]);
					});
				} else {
					return false;
				}
            }
            // 简易版构造函数
			function selfVue(data, elName, exp) {
                // 提取data,并监听
				this.data = data;
                observe(this,data);
                // 获取dom节点
                let ele = document.querySelector(elName);
                ele.innerHTML = data[exp];
                // 初始化watcher,使数据进入dep数组
                new watcher(this,exp,(vm, exp,value,oldValue)=>{
                     ele.innerHTML = value
                })
                return this
            }
            // vue简易版初始化
			let self=new selfVue(
				{
                    name: 'hellow',
				},
				'#root',
				'name'
            );
            self.data.name="你好"
		</script>
	</body>
</html>