Vue数据双向绑定

本文介绍了Vue的双向绑定概念,包括数据到视图和视图到数据的同步。核心实现原理是通过数据劫持和订阅者发布者模式,利用`Object.defineProperty`的set和get方法监听数据变化。此外,还探讨了构造器的基础构造和模板编译,展示如何在实例中操作和显示数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,什么是双向绑定

双向数据 - > 视图、视图 - > 数据;   绑定:v-model、v-bind . . . 

从数据到视图。当数据变化时,视图也跟着变化。

从视图到数据。当input框中的内容变化时,数据也跟着变化。

二,实现原理:(个人理解)

        利用数据劫持结合订阅者发布者模式,通过objeck.defineproperty中的set和get方法(作用:拦截器),在数据变动时发布消息给订阅者(v-model、v-bind绑定的那个属性),触发相应的监听回调。set方法设置数据时触发,get是访问时触发监听。对比数据变动前后的虚拟DOM,计算出那些地方需要更新,只更新需要更新的地方。  

三,实现基本构造器

  • 写出构造器的基本架子,完成参数传递与获取。这里的参数只有两个:el,data

  • 实现数据拦截:

    • 在代码外部,让MVVM实例可以操作data选项中的属性。

    • 在代码内部,能通过this.属性名 的方式去操作data选项中的属性。

 

<script type="text/javascript">
      var data = {
        salary:15000
      }
          // 1. 完成参数传递与获取
          // 2. 实现数据拦截
          //   (1) 在代码外部,让实例能够操作data选项中的数据
          //   (2) 在代码内部,通过this.XXX来访问data选项中的属性值
      function MVVM (options) {
        // 用解构赋值,取出配置项中内容
        let {el, data} = options
        console.log(data)

        // 对data中所有的可枚举属性进行循环
        for(let key in data) {
          console.log(key)
          // 在构造器内部,this就会指向当前实例对象
          Object.defineProperty(this, key, {
            get () {
              console.log('get', key)
              return data[key]
            },
            set ( val ) {
              if (val != data[key]) {
                data[key] = val
              }
            }
          })
        }

        console.log(this.salary)
      }
      var vm = new MVVM({
          el:"#app",
          data
      })
      // console.log( vm.salary )
  </script>

模板编译并初始显示内容:

function MVVM (options) {
        // 用解构赋值,取出配置项中内容
        let {el, data} = options
        console.log(data)

        // 对data中所有的可枚举属性进行循环
        for(let key in data) {
          console.log(key)
          // 在构造器内部,this就会指向当前实例对象
          Object.defineProperty(this, key, {
            get () {
              console.log('get', key)
              return data[key]
            },
            set ( val ) {
              if (val != data[key]) {
                data[key] = val
              }
            }
          })
        }

        
        // 循环el下的所有的子节点
        // 如果某个节点上有v-html, v-model则需要特殊处理
        // 1. 取出所有的子节点
        let rootDom =document.querySelector(el)
        // console.dir(Array.isArray(rootDom.children))
        // console.dir(rootDom.children)
        // rootDom.children 表示所有的子结点,它是一个伪数组,要用循环,还要转一下。
        Array.from(rootDom.children).forEach(node => {
          // console.log(node)
          // 对每一个节点,分析是否有 v-html, v-model属性?
          console.log( node.hasAttribute('v-html'))
          if (node.hasAttribute('v-html')) {
            // 处理v-html指令: 把数据显示出来
            //以:  <h2 v-html="salary"></h2> 为例
            // (1) 把属性值取出来。把salary取出来
            let attrVal = node.getAttribute('v-html')
            console.log(attrVal) // attrVal : salary
            // (2) 找出对应的data中的salary的属性值15000
            console.log(this[attrVal])
            // (3) 15000 放入当前的node中
            node.innerHTML = this[attrVal]
          }
    })

}
// MVVM中的m: 数据项
var data = {
    salary:15000
}

// MVVM中的 vm
// 目标:自已写代码,实现类似Vue的功能
var vm = new MVVM({
    "el":"#app",
    "data": data
})
  • Array.from :把一个伪数组转成数组

  • hasAttribute判断一个dom是否有指定的属性

  • getAttribute是用来获取dom的指定属性的值

  • this[attrVal]

    • 获取对象的属性值。由于attrVal是一个变量,不能通过this.attrVal的方式来获取

    • this是当前的实例对象,在上一步 构造器 的过程,已经把数据的属性全挂在实例对象上了。所以,这里可以直接访问。

 效果:图1,图2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值