Vue.js - Vue.js响应式原理(1/2)

一. 数据驱动

数据响应式:数据改变,则视图改变,避免频繁的Dom操作,提高运行效率

双向绑定:数据改变,则视图改变;视图改变,则数据也随之改变

数据驱动:开发过程中只需关注数据本身,不用关心数据如何渲染出视图

 

二. Vue.js 数据响应式原理

2.1 Vue2数据响应式原理 - Object.defineProperty - 兼容IE9及以上

<html>
<head>
</head>
<body>
  <h1>Vue响应式原理-Vue2 Object.defineProperty()</h1>
  <div id="app"></div>
</body>
<script>
  let data = {
    msg: 'hello~'
  }
  let vm = {} // 模拟Vue实例
  // 数据劫持:当访问或设置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
      document.querySelector('#app').textContent = data.msg
    }
  })

  // 测试
  vm.msg = 'Hello~ World~'
  setTimeout(() => {
    console.log(vm.msg)
  }, 12000)
</script>

</html>

 

2.2 Vue3数据响应式原理 - new Proxy() - ES6中新增 IE不支持 

new Proxy()相比于Object.defineProperty()是直接监听对象,而非属性,性能优于Object.defineProperty()。

<html>
<head>
</head>
<body>
  <h1>Vue响应式原理-Vue3 new Proxy()</h1>
  <div id="app"></div>
</body>
<script>
  let data = {
  msg: 'hello',
  count: 0
}
// 模拟Vue实例
let vm = new Proxy(data, {
  // 执行代理行为的函数
  // 当访问vm的成员会执行
  get(target, key) {
    console.log('get, key: ', key, target[key])
    return target[key]
  },
  // 当设置vm的成员会执行
  set(target, key, newValue) {
    console.log('set, key: ', key, newValue)
    if(target[key] === newValue) {
      return
    }
    target[key] = newValue
    document.querySelector('#app').textContent = target[key]
  }
})
// 测试
vm.msg = 'HELLO WORLD!'
console.log(vm.msg)
</script>

</html>

 

三. 发布订阅模式和观察者模式

3.1 发布订阅模式-有事件中心

例1  Vue的自定义事件:

let vm = new Vue()
vm.$on('dataChange', () => { // 事件订阅
  console.log('dataChange')
})
vm.$on('dataChange', () => { // 事件订阅
  console.log('dataChange1') 
})
vm.$emit('dataChange') // 事件发布

例2  Vue的兄弟组件通信:

// eventBus.js
// 事件中心
let eventHub = new Vue()

// ComponentA.vue 发布者
addTodo: () => {
  eventHub.$emit('add-todo', { text: this.newTodoText })
  this.newTodoText = ''
}

// ComponentB.vue 订阅者
created: () => {
  eventHub.$on('add-todo', this.addTodo)
}

例3 模拟发布订阅模式:

// 模拟发布订阅模式-事件触发器
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]) {
      const handlers = this.subs[eventType]
      handlers.forEach(handler => {
        handler()
      });
    }
  }
}
// 测试
const em = new EventEmitter()
em.$on('change', () => {
  console.log('change01')
})
em.$on('change', () => {
  console.log('change02')
})
setTimeout(() => {
  em.$emit('change')
  em.$emit('click')
}, 2000)

 

3.2 观察者模式

发布者知道有哪些订阅者,每个订阅者提供一个update方法,当事件触发时,发布者将调用每个订阅者的update方法。

和发布订阅模式相比,观察者模式无事件中心,所以观察者模式的发布者和观察者之间存在依赖。

而发布订阅模式有事件中心,事件中心记录了哪些事件有哪些订阅者,解除了发布者和订阅者的依赖。

例1: 模拟观察者模式

// 发布者(依赖)
class Dep {
  constructor() {
    // 记录所有订阅者
    this.subs = []; // subscriber
  }
  // 添加订阅者
  addSub(sub) {
    if(sub && sub.update) {
      this.subs.push(sub)
    }
  }
  // 发布通知
  notify() {
    this.subs.forEach(sub => {
      sub.update()
    })
  }
}

// 订阅者(观察者)
class Wather {
  constructor(name) {
    this.name = name
  }
  update() {
    console.log(`${this.name} got update message and do something!`)
  }
}

// 测试
const dep = new Dep()
const wather1 = new Wather('wather1')
dep.addSub(wather1)
const wather2 = new Wather('wather2')
dep.addSub(wather2)
dep.notify()

本文 完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值