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

作者:几何心凉 时间:2024-05-13 09:38:25 

数据的变化反应到视图

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

来源:https://blog.csdn.net/JHXL_/article/details/124842265

标签:Vue,双向,数据,绑定,原理
0
投稿

猜你喜欢

  • 通用分页存储过程

    2007-11-28 13:08:00
  • Vue编写多地区选择组件

    2024-06-07 15:24:40
  • Python中enumerate()函数编写更Pythonic的循环

    2023-06-09 14:01:29
  • python实现将多个文件分配到多个文件夹的方法

    2023-04-13 20:48:46
  • 利用Python实现数值积分的方法

    2023-07-11 10:16:31
  • python 实现自动远程登陆scp文件实例代码

    2022-04-02 20:25:31
  • Vue cli构建及项目打包以及出现的问题解决

    2023-07-02 16:46:46
  • Django admin禁用编辑链接和添加删除操作详解

    2021-01-13 05:01:01
  • OpenCV-Python实现图像梯度与Sobel滤波器

    2021-04-07 05:23:20
  • 最新WebStorm2020.2注册码永久激活(激活到2089年) <font color=red>原创</font>

    2023-03-20 19:28:51
  • golang NewRequest/gorequest实现http请求的示例代码

    2024-04-30 10:03:26
  • python flask框架详解

    2023-07-20 02:54:52
  • Python使用Asyncio进行web编程方法详解

    2022-08-11 17:03:56
  • Python中优化NumPy包使用性能的教程

    2021-03-27 21:08:43
  • Python中str is not callable问题详解及解决办法

    2023-10-30 05:34:42
  • Javascript世界的最大整数值

    2008-06-23 13:23:00
  • IE6与IE7的unshift 方法

    2010-01-19 13:59:00
  • Vue 自定义指令实现一键 Copy功能

    2024-05-05 09:08:48
  • Windows平台Python编程必会模块之pywin32介绍

    2023-11-05 10:45:35
  • MySql like模糊查询通配符使用详细介绍

    2024-01-24 12:25:03
  • asp之家 网络编程 m.aspxhome.com