Vue中数据劫持

  • Post author:
  • Post category:vue




Vue中的数据劫持

Vue中响应式系统的核心: {


数据劫持: 使用Object.defineProperty(this, 属性名,{属性值的配置项} );

依赖收集: 因为上一步数据劫持后, 在解析模板时,替换模板中的变量就需要读取变量的数据,此时就会触发数据的get方法,在get方法中收集所有依赖这个数据的dom节点;

观察者模式; 后续数据发生变化, 就会走set方法, 此时读取以前收集所有依赖该数据的dom节点,进行更新(内部有虚拟dom比对的步骤);

}

<body>
 
   <div id="app">
       <p>{{msg}}</p>
       <div class="test">
           <div>
               <p>
                   <span>{{msg}}</span>
               </p>
           </div>
       </div>
   </div>

    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript">
        
        function Vue(options) { 
            const { data } = options //options是一个对象,因此data用对象形式解构
            console.log(data)
            /*
              打印结果: 
              Object
              foo: "bar"
              msg: "123"
              __proto__: Object
            */
  
            // 1. 数据劫持
            // 取得data的所有键名
            const keys = Object.keys(data)
            console.log(keys)
            /*
              打印结果:
              (2) ["msg", "foo"]
              0: "msg"
              1: "foo"
              length: 2
              __proto__: Array(0)
            */
  
  
            //   var a= 1
            //   console.log(a)  //获取数据触发 get函数
            //   a = 2  // 更新值时触发 set函数

            keys.forEach(key => {
                let value = data[key]
                Object.defineProperty(this, key, {
                    // 获取this.key的时候会执行get方法
                    get() {
                        console.log(`读取数据${key}的值:`, value)
                  
                        // 收集依赖:
                        // 收集一下依赖(每个被使用的数据都是一个依赖项);
                        // 每个依赖项声明一个对象,对象下记录一个属性: 属性的值是所有使用这个数据的dom节点;
                        // 例如: msg: { watchers: [dom1, dom2, dom3]} ;
                          // 这里的'msg'是依赖项, 'watchers'是对象下的属性(表示观察者), 
                          // 'dom1,dom2,dom3'是所有使用msg数据的dom节点;
    
                        return value
                    },
                    // 更新(重新设置)this.key的时候会执行set方法
                    set(val) { // val 指更新后的新值
                      console.log(`设置数据${key}的新值:`, val)
                      value = val
    
                      // 为(数据)依赖项更新值时,需要为所有使用这个数据的dom节点(观察者)更新
                      // 1个数据演示流程: 可以写死使用这个数据的dom节点的更新操作
                      document.querySelector('p').innerHTML = val
    
                      // 多个数据更新时,不能以写死的方式,一个一个去更新
                      // 数据更新时,去读取该数据的使用者(使用者 即dom节点,在模板编译的步骤中已经收集好这些dom节点)
                            // 去更新这些dom节点(更新的细节有虚拟dom的参与)
                    },
                })
            })
            // 2. 解析模板: 简化为直接操作对应的dom
            let msgE1 = (document.querySelector('p').innerHTML = this.msg)

            // 3. 更新数据
            setTimeout(() => {
                this.msg = Math.random
            }, 2000)
        }
 
 
        const vm = new Vue({
            // vue内部的this都指vue实例
            el: '#app',
            data: {
                msg: '123',
                foo: 'bar',
            },
        })
        /*
          打印结果: 
          {msg: "123", foo: "bar"}
          (2) ["msg", "foo"]
          读取数据msg的值: 123

          vue.js:8553 You are running Vue in development mode.
          Make sure to turn on production mode when deploying for production.
          See more tips at https://vuejs.org/guide/deployment.html
          
          设置数据msg的新值: ƒ random() { [native code] }
        */ 
    </Script>
  
</body>



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