深入理解vue响应式原理

vue响应式原理分析

vue的响应式原理请看下图
深入理解vue响应式原理_第1张图片
在 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()
    })
  }
}

调用方法


<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>

你可能感兴趣的:(vue,vue响应式原理,MVVM,发布订阅模式)