深入理解vue响应式原理

vue响应式原理分析

vue的响应式原理请看下图
在这里插入图片描述
在 new Vue的时候,内部会触发一个Observer劫持监听所有属性,还会有一个Compile解析指令,Compile可以订阅数据变化,添加Watcher订阅者,在watcher里面会有一个update的方法,用于更新视图。在Observer里面会通过Object.definepropry方法对数据进行劫持,在get中添加依赖所依赖的watcher,当触发set时说明有数据变化,此时调用dep.notify方法,其中dep是一个依赖集合,里面搜集了订阅者(依赖于改数据),在dep.notify里面触发wacther的update方法。

发布者

Vue作为一个发布者

class Vue {
  constructor(options) {
    this.$options = options || {}
    this.$data = options.data
    this.$el = document.querySelector(options.el)
    //this._dep = {}
    this.Observer(this.$data)
    this.Compile(this.$el)
  }
  // 劫持监听所有属性
  Observer(data) {
    for(let key in data) {
      const dep = new Dep()
      //this._dep[key] = []
      let Val = data[key]
      Object.defineProperty(this.$data, key, {
        get: function () {
          if(Dep.target) {
            dep.addSubs(Dep.target)
          }
          return Val
        },
        set: function(newVal) {
          if(newVal !== Val) {
            Val = newVal
            dep.notify()
          }
        }
      })
    }
  }

  // 解析指令
  Compile(el) {
    const children = el.children
    if(!children.length) throw new Error('挂载元素里面内容为空!')
    for(let i=0; i< children.length; i++) {
      const node = children[i]
      if(node.hasAttribute('v-text')) {
        const expValue = node.getAttribute('v-text')
        new Watcher(node, this, expValue, 'innerHTML')
        //this._dep[expValue].push()
      }
      if(node.hasAttribute('v-model')) {
        const expValue = node.getAttribute('v-model')
        new Watcher(node, this, expValue, 'value')
        //this._dep[expValue].push()
        node.addEventListener('input', (function() {
          return function() {
            this.$data[expValue] = node.value
          }
        })().bind(this))
      }
      if(node.children.length) {
        this.Compile(node)
      }
    }
  }
}

订阅者

watcher作为订阅者

class Watcher {
  constructor(el, vm, exp, attr) {
    this.el = el
    this.vm = vm
    this.exp = exp
    this.attr = attr
    this.update()
    this.value = this.get()
  }
  update() {
    this.el[this.attr] = this.vm.$data[this.exp]
    
  }
  get() {
    Dep.target = this // 缓存自己
    const value = this.vm.$data[this.exp]
    Dep.target = null // 释放自己
    return value
  }
}

依赖收集器

class Dep {
  constructor() {
    this.target = null
    this.subs = []
  }
  addSubs(sub) {
    this.subs.push(sub)
  }
  notify() {
    this.subs.forEach(item => {
      item.update()
    })
  }
}

调用方法

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>vue响应式原理</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="./index.js"></script>
</head>
<body>
  <div id="app">
    <h1>VUE响应式原理</h1>
    <div>
      <div v-text="myText"></div>
      <div v-text="myBox"></div>
      <p v-text="myBox"></p>
      <input type="text" v-model="myText">
      <input type="text" v-model="myBox">
    </div>
  </div>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        myText: '大吉大利,今晚吃鸡!!!',
        myBox: '我是一个盒子'
      }
    })
  </script>
</body>
</html>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值