vue响应式原理

122 阅读1分钟

数据驱动

数据响应式

  • 数据模型仅仅是普通的javascript对象,而当我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率

双向绑定

  • 数据改变,视图改变;视图改变,数据也随之改变
  • 我们可以使用v-model在表单元素上创建双向数据数据

数据驱动是Vue最独特的特性之一

  • 开发过程中仅需要关注数据本身,不需要关心数据是如何渲染到视图

数据响应式的核心原理

1. Vue 2.x

  • Vue 2.x深入响应式原理

  • Object.defineProperty

  • 浏览器兼容IE8以上(不兼容IE8)

 <!DOCTYPE html>
  <html lang="cn">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>defineProperty</title>
  </head>
  <body>
    <div id="app">
      hello
    </div>
    <script>
      // 模拟 Vue 中的 data 选项
      let data = {
        msg: 'hello'
      }
  
      // 模拟 Vue 的实例
      let vm = {} 
  
      Object.defineProperty(vm, 'msg', {
        // 可枚举(可遍历)
        enumerable: true,
        // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义)
        configurable: true,
        // 当获取值的时候执行
        get () {
          console.log('get: ', data.msg)
          return data.msg
        },
        // 当设置值的时候执行
        set (newValue) {
          console.log('set: ', newValue)
          if (newValue === data.msg) {
            return
          }
          data.msg = newValue
          // 数据更改,更新 DOM 的值
          document.querySelector('#app').textContent = data.msg
        }
      })
  
      // 测试
      vm.msg = 'Hello World'
      console.log(vm.msg)
    </script>
  </body>
  </html>
  • 如果有一个对象中多个属性需要被转换getter、setter 如何处理?遍历这个对象的所有属性

2.Vue3.x

image.png

1. 发布订阅模式

<!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>发布订阅模式</title>
</head>
<body>
  <script>
    // 时间触发器,自定义事件
    class EventEmitter {
      constructor () {
        // { click: [fn1, fn2], 'change': [fn]}
        this.subs = Object.create(null)   // 创建空对象没有原型,提升性能
      }

      $on (eventType, handler) {
        this.subs[eventType] = this.subs[eventType] || []
        this.subs[eventType].push(handler)
      }

      $emit (eventType) {
        if (this.subs[eventType]) {
          this.subs[eventType].forEach(handler => {
            handler()
          })
        }
      }
    }
    let em = new EventEmitter()
    em.$on('click', function() {
      console.log('1111')
    })
    em.$on('click', function() {
      console.log('2222')
    })
    em.$emit('change')
  </script>
</body>
</html>

发布订阅模式包括:订阅者,发布者,信号中心

我们假定,存在一个”信号中心“,某个任务执行完成,就向信号中心”发布“(publish)一个信号,其他任务可以向信号中心”订阅“(subscribe)这个信号,从而知道什么时候自己开始执行,这就叫做”发布/订阅模式“(publish-subscribe pattern)

2. 观察者模式

观察者(订阅者)- Watcher

update(): 当事件发生时,具体要做的事情

目标(发布者) - Dep

  • subs数组:存储所有的观察者
  • addSub(): 添加观察者
  • notify(): 当事件发生,调用所有观察者的update()方法
  • 没有事件中心

image.png