Vue2和Vue3 双向数据绑定原理-技术鸭论坛-前端交流-技术鸭(jishuya.cn)

Vue2和Vue3 双向数据绑定原理

Vue2

需求:双向数据绑定(数据变了,视图改变;视图改变,数据也变)

const data = {
  name: 'ifer'
}

/* const tempData = { ...data }
    Object.defineProperty(data, 'name', {
      get() {
        // 获取 name 的时候会走这儿
        return tempData.name
      },
      set(newValue) {
        // 设置 name 的时候会走这儿
        tempData.name = newValue
      }
    })

    // console.log(data.name) // 'ifer'
    data.name = 'elser'
    console.log(data.name) */

/* const tempData = { ...data }
    Object.defineProperty(data, 'name', {
      get() {
        // 获取 name 的时候会走这儿
        return tempData.name
      },
      set(newValue) {
        // model => view => Data bindings
        // #2 设置 name 的时候会走这儿
        tempData.name = newValue
        oP.innerHTML = newValue
        oInput.value = newValue
      }
    })

    // view => model => DOM Listeners
    oInput.oninput = function (e) {
      // #1
      data.name = e.target.value
    } */

/* oInput.oninput = function (e) {
      oP.innerHTML = e.target.value
    } */

Vue3

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <p id="oP"></p>
    <input id="oInput" type="text" />
    <script>
      // 需求:双向数据绑定(数据变了,视图改变;视图改变,数据也变)

      const data = {
        name: 'ifer',
        address: '北京'
      }

      /* const tempData = { ...data }
    Object.keys(data).forEach(key => {
      Object.defineProperty(data, key, {
        get() {
          return tempData[key]
        },
        set(newValue) {
          tempData[key] = newValue
          oP.innerHTML = newValue
          oInput.value = newValue
        }
      })
    })
    oInput.oninput = function (e) {
      data.address = e.target.value
    } */

      // 上面 Vue2 的问题:如果 data 里面有 100 个属性,那可不是要循环 100 次吗?

      // p 就是一个代理,我对 p 的任何操作都会影响到 data
      const p = new Proxy(data, {
        get(target, attr) {
          // 获取的时候触发
          // console.log(target, attr)
          // target => data
          // attr => 属性
          return target[attr]
        },
        set(target, attr, newValue) {
          target[attr] = newValue
          oP.innerHTML = newValue
          oInput.value = newValue
        }
      })
      // p.name = 'xxx'
      // console.log(data.name);

      /* p.name = 'xxx'
    console.log(p.name) */

      oInput.oninput = function (e) {
        // p.address = e.target.value
        p.test = e.target.value
      }
    </script>
  </body>
</html>

 

 

结论

Vue2.0 使用 Object.defineProperty 对象以及对象属性的劫持+发布订阅模式,只要数据发生变化直接通知变化 并驱动视图更新。

Vue3.0 中的响应式采用了ES6中的 Proxy 方法。 可以理解成,在目标对象之前架设一层 “拦截” ,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

 

 

请登录后发表评论

    请登录后查看回复内容