深入了解Vue中双向数据绑定原理

 更新时间:2022年05月19日 09:48:39   作者:几何心凉  
vue是一个mvvm框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。本文将通过示例详解其中原理,需要的可以参考一下

数据的变化反应到视图

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

命令式操作视图

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

<div id="app">
  <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 id="app">
  <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 id="app">
  <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 id="app">
  <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双向数据绑定的资料请关注脚本之家其它相关文章!

相关文章

  • el-table表头根据内容自适应完美解决表头错位和固定列错位

    el-table表头根据内容自适应完美解决表头错位和固定列错位

    这篇文章主要介绍了el-table表头根据内容自适应完美解决表头错位和固定列错位,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Vue ECharts图表通用配置详解

    Vue ECharts图表通用配置详解

    这篇文章主要介绍了Vue ECharts图表通用配置,Echarts,它是一个与框架无关的 JS 图表库,但是它基于Js,这样很多框架都能使用它,例如Vue,估计IONIC也能用
    2022-12-12
  • Vue 2源码解析HTMLParserOptions.start函数方法

    Vue 2源码解析HTMLParserOptions.start函数方法

    这篇文章主要为大家介绍了Vue 2源码解析HTMLParserOptions.start函数方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • vue项目中实现的微信分享功能示例

    vue项目中实现的微信分享功能示例

    这篇文章主要介绍了vue项目中实现的微信分享功能,结合实例形式分析了基于vue.js实现的微信分享功能具体定义与使用方法,需要的朋友可以参考下
    2019-01-01
  • VUE正则表达式用法全集整理(推荐!)

    VUE正则表达式用法全集整理(推荐!)

    正则表达式是由一些特定的字符组成,代表一个规则,可以用来检验数据格式是否合法,也可以在一段文本中查找满足要求的内容,这篇文章主要给大家介绍了关于VUE正则表达式用法的相关资料,需要的朋友可以参考下
    2024-02-02
  • Vue项目中new Vue()和export default{}的区别说明

    Vue项目中new Vue()和export default{}的区别说明

    这篇文章主要介绍了Vue项目中new Vue()和export default{}的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • vue中如何实时监听本地存储

    vue中如何实时监听本地存储

    这篇文章主要介绍了vue中如何实时监听本地存储,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • webpack项目调试以及独立打包配置文件的方法

    webpack项目调试以及独立打包配置文件的方法

    下面小编就为大家分享一篇webpack项目调试以及独立打包配置文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • Vue实现骨架屏的示例代码

    Vue实现骨架屏的示例代码

    骨架屏就是在页面数据尚未加载前先给用户展示出页面的大致结构。本文将利用Vue实现简单的骨架屏,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • Vue大屏数据展示示例

    Vue大屏数据展示示例

    公司的大数据工作组就需要通过数据大屏展示一些处理过后有价值的信息,本文主要介绍了Vue大屏数据展示示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11

最新评论