Vue中双向绑定详解(defineProperty和Proxy)

  • Post author:
  • Post category:vue

1.首先复习一下我们平时是怎么写双向绑定的

<div id="app">
    <input type="text" v-model="msg">
    <p> {{msg}}</p>
  </div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
 new Vue({
   el:'#app',
   data() {
     return {
       msg:'',
     }
   },
 })
</script>

基本原理如图:
在这里插入图片描述
2.现在,让我们来看一下双向绑定的原理,此时我们先要了解到一个es6的对象添加属性的方法:defineProperty
a.defineProperty给对象赋值的写法:

<script>
  var obj = {};
  //defineProperty有三个参数,不写全会报错
  Object.defineProperty(obj, 'name', {
    get() {
      console.log('取值了')
    },

    set() {
      console.log('赋值了')
    }
  })
</script>

这样做的好处是什么呢?- – –可以监听属性的赋值和取值
当赋值时,会触发set事件,当取值时,会触发get事件
如果你抱有疑惑,可以执行上面代码,在浏览器中调试,你会得到下面的结果:
在这里插入图片描述
b.规范写法:get中:必须返回 _属性名 set中:必须写 _属性名=value
这里的value,就是你传过来的值

<script>
  var obj = {};
  //defineProperty有三个参数,不写全会报错
  Object.defineProperty(obj, 'name', {
    get() {
      console.log('取值了')
      // 必须返回 _属性名
      return _name;
    },

    set(value) {
      // 必须写 _属性名=value
      _name=value;
     console.log('赋值了:' + value)
    }
  })
</script>

这样写之后,你会发现obj中的name有值了(任意注释一个再执行,然后观察结果,你可以试一下)
在这里插入图片描述
3.让我们回过头来再来看看双向绑定的特点:
我们需要接收文本框输入的值,给msg,具体而言是data里面的msg,data.msg再把值赋给p标签;相当于:我们要监听文本框输入的值,一边输入,一边把值赋给msg
让我们仿写一下,代码如下:


    <!-- 写一个输入框和几个p标签 v-mode和v-bind是一个行内属性 只是模拟一下-->
  <input type="text"  v-model>

  <p v-bind></p>
  <p v-bind></p>
  <p v-bind></p>
  <p v-bind></p>
 <script>
   var txt=document.querySelector('[v-model]')
   txt.oninput=function(){
     // 那我们什么时候知道值发送改变了呢? 当data.msg赋值的时候,就会调用set方法
     data.name=txt.value
     //这样写后,就已经实现了把输入框的value双向绑定到了name属性中了,你可以去set中打印进行验证
   }
   
   // 为了模仿的像一点 我们把对象的名字改为data
   var data={};

   Object.defineProperty(data,'name',{
     get(){
       console.log('取值了')
       return _name;
     },

     set(value){
       _name=value;
        console.log(data.name) 
       //但是如何绑定到P标签呢?
       var list=document.querySelectorAll('[v-bind]')
       for(var i=0;i<list.length;i++) {
         list[i].innerHTML=value;
       }
     }
   })
 </script>

效果如下图:
在这里插入图片描述
换言之:当我们在输入框输入值时,会触发oninput方法,然后txt.value将得到的值赋值给data.name,这时会触发set方法,在set中,不仅完成了赋值,还找到了所有绑定的p标签然后把文本框输入的值给了P标签,最终实现了双向绑定

这就是目前vue2.0中的双向绑定,但是尤大神说将在vue3.0中使用proxy来实现双向绑定

4.proxy中的双向绑定原理:
a.使用proxy代码如下:

<script>
    var data={}

    var dataProxy=new Proxy(data,{
      get(obj,prop) {
        console.log('调用了')
      },

      set(obj,prop,value) {
        console.log('赋值了')
      }
    })

    dataProxy.name='jack'
    console.log(dataProxy.name)
  </script>

执行结果如下:
在这里插入图片描述
看到这里,你也许会问,proxy和defineproprety有什么区别吗?
defineProperty只能监听到自己所写的属性,其他的无法监听,但是proxy可以监听到所有写的属性,例如我们在调试时写其他的属性,也会监听到,如图:
在这里插入图片描述
b.利用proxy实现双向绑定,代码如下:

<input type="text"  v-model>

<p v-bind></p>
<script>
  var txt=document.querySelector('[v-model]')
  txt.oninput=function(){
    dataProxy.prop=txt.value
  }

  var data={}

  var dataProxy=new Proxy(data,{
    get(obj,prop) {
      return obj[prop]
      console.log('调用了')
    },

    set(obj,prop,value) {
      obj[prop]=value;    
      //console.log(obj==data);//true
      //console.log('赋值了')
      document.querySelector('[v-bind]').innerHTML=value
    }
  })

  // dataProxy.name='jack'
  // console.log(dataProxy.name)
</script>
  • 与defineProperty类似,proxy在get中要返回 return obj[prop],在set中,要赋值 obj[prop]=value
  • obj是我们传过来的对象 打印console.log(obj==data),得到的值为true
  • prop为属性名
  • value为属性值
    实现的结果如图:
    在这里插入图片描述

版权声明:本文为qq_43378800原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。