vue3.0双向数据绑定原理-vue的双向数据绑定原理是什么?

lxf2023-11-13 05:40:01
摘要

vue是一个mvvm框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。本文将通过示例详解其中原理,需要的可以参考一下

目录
  • 数据的变化反应到视图
    • 命令式操作视图
    • 声明式操作视图
    • 小结
  • 视图的变化反应到数据
    • 现存的问题

      数据的变化反应到视图

      前面我们了解到数据劫持之后,我们可以在数据发生修改之后做任何我们想要做的事情,操作视图当然也是OK的

      命令式操作视图

      目标:我们通过原始的操作dom的方式让每一次的name的最新值都能显示到p元素内部

      <div >
        <p></p>
      </div>
      <script>
         let data = {
              name: '小兰同学',
              age: 18,
              height:180
          }
          // 遍历每一个属性
          Object.keys(data).forEach((key)=>{
              // key 属性名
              // data[key] 属性值
              defineReactive(data,key,data[key])
          })
          function defineReactive(data,key,value){
              Object.defineProperty(data,key,{
                  get(){
                     return value
                  },
                  set(newVal){
                    value = newVal 
                    // 数据发生变化,操作dom进行更新
                    document.querySelector('#app p').innerhtml = data.name
                  }
              })
          }
        // 首次渲染
        document.querySelector('#app p').innerHTML = data.name
      </script>
      

      声明式操作视图

      目标:我们将data中name属性的值作为文本渲染到标记了v-text的p标签内部,在Vue中,我们把这种标记式的声明式渲染叫做指令

      <div >
        <p v-text="name"></p>
      </div>
      <script>
        let data = {
          name: '小兰同学',
          age: 18,
          height: 180
        }
        // 遍历每一个属性
        Object.keys(data).forEach((key) => {
          // key 属性名
          // data[key] 属性值
          // data 原对象
          defineReactive(data, key, data[key])
        })
        function defineReactive(data, key, value) {
          Object.defineProperty(data, key, {
            get() {
              return value
            },
            set(newVal) {
              value = newVal
              // 数据发生变化,操作dom进行更新
              compile()
            }
          })
        }
        // 
        function compile() {
          let app = document.getElementById('app')
          // 1.拿到app下所有的子元素
          const nodes = app.childNodes   //  [text, input, text]
          //2.遍历所有的子元素
          nodes.forEach(node => {
            // nodeType为1为元素节点
            if (node.nodeType === 1) {
              const attrs = node.attributes
              // 遍历所有的attrubites找到 v-model
              Array.from(attrs).forEach(attr => {
                const dirName = attr.nodeName
                const dataProp = attr.nodeValue
                if (dirName === 'v-text') {
                  node.innerText = data[dataProp]
                }
              })
            }
          })
        }
        // 首次渲染
        compile()
      </script>
      

      小结

      不管是指令也好,插值表达式也好,这些都是将数据反应到视图的标记而已,通过标记我们可以把数据的变化响应式的反应到对应的dom位置上去
      找标记,把数据绑定到dom的过程,我们称之为binding

      视图的变化反应到数据

      目标:将data中的message属性对应的值渲染到input上面,同时input值发生修改之后,可以反向修改message的值,在vue系统中,v-model指令就是干这个事情的,下面我们就实现一下v-model的功能

      <div >
        <input v-model="name" />
      </div>
      <script>
        let data = {
          name: '小兰同学',
          age: 18,
          height: 170
        }
        // 遍历每一个属性
        Object.keys(data).forEach((key) => {
          // key 属性名
          // data[key] 属性值
          // data 原对象
          defineReactive(data, key, data[key])
        })
        function defineReactive(data, key, value) {
          Object.defineProperty(data, key, {
            get() {
              return value
            },
            set(newVal) {
              // 数据发生变化,操作dom进行更新
              if (newVal === value) {
                return
              }
              value = newVal
              compile()
            }
          })
        }
        // 编译函数
        function compile() {
          let app = document.getElementById('app')
          // 1.拿到app下所有的子元素
          const nodes = app.childNodes   //  [text, input, text]
          //2.遍历所有的子元素
          nodes.forEach(node => {
            // nodeType为1为元素节点
            if (node.nodeType === 1) {
              const attrs = node.attributes
              // 遍历所有的attrubites找到 v-model
              Array.from(attrs).forEach(attr => {
                const dirName = attr.nodeName
                const dataProp = attr.nodeValue
                if (dirName === 'v-model') {
                  node.value = data[dataProp]
                  // 视图变化反应到数据 无非是事件监听反向修改
                  node.addEventListener('input', (e) => {
                    data[dataProp] = e.target.value
                  })
                }
              })
            }
          })
        }
        // 首次渲染
        compile()
      </script>
      

      现存的问题

      无法做到精准更新

      <div >
        <p v-text="name"></p>
        <p v-text="age"></p>
        <p v-text="name"></p>
      </div>
      <script>
        let data = {
          name: '小兰同学',
          age: 18,
          height: 180
        }
        // 遍历每一个属性
        Object.keys(data).forEach((key) => {
          // key 属性名
          // data[key] 属性值
          // data 原对象
          defineReactive(data, key, data[key])
        })
        function defineReactive(data, key, value) {
          Object.defineProperty(data, key, {
            get() {
              return value
            },
            set(newVal) {
              // 数据发生变化,操作dom进行更新
              if (newVal === value) {
                return
              }
              value = newVal
              compile()
            }
          })
        }
        // 编译函数
        function compile() {
          let app = document.getElementById('app')
          // 1.拿到app下所有的子元素
          const nodes = app.childNodes   //  [text, input, text]
          //2.遍历所有的子元素
          nodes.forEach(node => {
            // nodeType为1为元素节点
            if (node.nodeType === 1) {
              const attrs = node.attributes
              Array.from(attrs).forEach(attr => {
                const dirName = attr.nodeName
                const dataProp = attr.nodeValue
                console.log( dirName,dataProp)
                if (dirName === 'v-text') {
                  console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`)
                  node.innerText = data[dataProp]
                }
              })
            }
          })
        }
        // 首次渲染
        compile()
      </script>
      

      以上就是深入了解Vue中双向数据绑定原理的详细内容,更多关于Vue双向数据绑定的资料请关注编程网其它相关文章!