二十、双向绑定原理
双向绑定的原理也叫响应式原理,面试时候经常会问到。
1、Vue时采用对象设计模式之发布者-订阅者模式的方式,通过Object.defineProperty()属性的setter,getter,在数据变动时
发布消息给订阅者,触发相应的监听回调。来完成双向绑定。
2、Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
3、Object.defineProperty有三个参数,
1>第一个:需要定义属性的当前对象。
2>第二个:当前需要定义的属性名。
3>第三个:属性描述符。
<!--步骤1、Object.defineProperty方法的使用。--> <script> var data={}; Object.defineProperty(data,'name',{ get(){//获取值getter }, set(val){//作用1:监听数据发生变化。作用2:设置值,setter。 console.log(val);//输出结果:李四 } }); data.name='李四'; </script>
<!--步骤2、调用windows的addEventListener方法,监听input元素,执行回调函数--> <input type="text"> <script> window.addEventListener("input",function(e){ console.log(e.target.value);//输出结果:输入框输入的值 }); </script>
<!--步骤3、(结合步骤1和步骤2代码,)在步骤2中,把监听input元素后获取到的值,赋值步骤1中的data.name元素即可。--> <input type="text"> <script> var data={}; Object.defineProperty(data,'name',{ get(){}, set(val){//监听data的name属性值是否发生改变,改变成什么值 console.log(val);//输出的就是data的name属性值改变后的值 } }); window.addEventListener("input",function(e){ data.name=e.target.value; //步骤3的关键是在这一句代码 }) </script>
<!--步骤4、(在步骤3的基础上)增加一个span元素,把监听到的数据变化后的值,赋值给span元素的文本内容。这样就实现input元素内容改变,span元素内容也随之同步更新的效果。--> <input type="text"> <span id="text"></span> <script> var data={}; Object.defineProperty(data,'name',{ get(){}, set(val){ text.innerHTML=val;//把监听到数据变化后的值,赋值给span元素的文本内容。 } }); window.addEventListener("input",function(e){ data.name=e.target.value; }); </script>
<!--尝试:在步骤4基础上,尝试获取数据变化后的data对象失败--> <input type="text"> <span id="text"></span> <script> var data={}; Object.defineProperty(data,'name',{ get(){}, set(val){ text.innerHTML=val;//把监听到数据变化后的值,赋值给span元素的文本内容。 } }); window.addEventListener("input",function(e){ data.name=e.target.value; console.log(data)//输出结果:{name: undefined}。 //因为在Object.defineProperty中,没有返回变化后的新数据。所以在这里获取不到data对象的新数据。 }); </script>
<!--步骤5、(在步骤4的基础上,)设置一个全局变量value,在set方法中把监听到数据变化后的值val赋值给value,再在get方法中返回value--> <input type="text"> <span id='text'></span> <script> var data={}; var value='';//关键1:设置全局变量 Object.defineProperty(data,'name',{ get(){ return value;//关键3:返回全局变量。 }, set(val){ text.innerHTML=val; value=val;//关键2:把监听到数据变化后的值,赋值给全局变量。 } }); window.addEventListener("input",function(e){ data.name=e.target.value; console.log(data.name) }) </script>