欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

圖解Vue?響應(yīng)式流程及原理

 更新時間:2022年07月08日 17:29:41   作者:井柏然  
這篇文章主要為大家介紹了圖解Vue的響應(yīng)式原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

閱讀本文能夠幫助你什么?

  • 在學習vue源碼的時候發(fā)現(xiàn)組件化過程很繞?
  • 在響應(yīng)式過程中Observer、Dep、Watcher三大對象傻傻分不清?
  • 搞不清楚對象、數(shù)組依賴收集、派發(fā)更新的流程?dep、watcher互調(diào)造成混亂?
  • 學了一遍好像懂了又好像不全懂的感覺?而且缺乏大體流程概念?
  • 或者像我一樣,有段時間沒看vue源碼好像有點遺忘?但是想快速回顧卻無從下手?

本文主要分為1. 組件化;2. 響應(yīng)式原理;3. 彩蛋(computed和watch)進行講解。本文調(diào)試源碼的vue版本是v2.6.14。整篇將采用源碼講解 + 流程圖的方式詳細還原整個Vue響應(yīng)式原理的全過程。你可以了解到Dep.target、pushTarget、popTarget;響應(yīng)式中的三大Watcher;Dep、Wathcer多對多的,互相收集的關(guān)系。

這篇是進階的 Vue 響應(yīng)式源碼解析,文章比較長,內(nèi)容比較深,大家可以先mark后看。看不懂的不要強行看,可以先看看其他作者的偏簡單一點的源碼解析文章,然后好好消化。等過段時間再回來看這篇,相信你由淺入深后再看本文,一定會有意想不到的收獲~

一、組件化流程

在講解整個響應(yīng)式原理之前,先介紹一下Vue中另一個比較核心的概念——組件化,個人認為這也是學習響應(yīng)式的前置核心。搞懂組件化,響應(yīng)式學習如虎添翼!

1. 整個new Vue階段做了什么?

  • 執(zhí)行init操作。包括且不限制initLifecycle、initState
  • 執(zhí)行mount。進行元素掛載
  • compiler步驟在runtime-only版本中沒有。
    • compiler步驟對template屬性進行編譯,生成render函數(shù)。
    • 一般在項目中是在.vue文件開發(fā),通過vue-loader處理生成render函數(shù)。

執(zhí)行render。生成vnode

<div id="app">{{ message }}</div>
render (h) {
  return h('div', {
     attrs: {
        id: 'app'
      },
  }, this.message)
}
  • render例子,如下
  • 對應(yīng)手寫的render函數(shù)
  • patch。新舊vnode經(jīng)過diff后,渲染到真實dom上

2. 普通dom元素如何渲染到頁面?

  • 執(zhí)行$mount。
    • 實際執(zhí)行mountComponent
    • 這里會實例化一個Watcher
    • Watcher中會執(zhí)行get方法,觸發(fā)updateComponent
  • 執(zhí)行updateComponent。執(zhí)行vm._update(vm._render(), hydrating)
  • 執(zhí)行vm.render()。
    • render其實調(diào)用createElment(h函數(shù))
    • 根據(jù)tag的不同,生成組件、原生VNode并返回
  • 執(zhí)行vm.update()createElm() 到 createChildren() 遞歸調(diào)用
  • 將VNode轉(zhuǎn)化為真實的dom,并且最終渲染到頁面

3. 組件如何渲染到頁面?

這里以如下代碼案例講解更加清晰~沒錯,就是這么熟悉!就是一個初始化的Vue項目

// mian.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
  render: h => h(App),
}).$mount('#app')
// App.vue
<template>
    <div id="app">
      <p>{{ msg }}</p>
    </div>
</template>
<script>
    export default {
        name: 'App',
        data () {
            return {
                msg: 'hello world'
            }
        }
    }
</script>

主要講解組件跟普通元素的不同之處,主要有2點:

如何生成VNode——創(chuàng)建組件VNodecreateComponent

如何patch——組件new Vue到patch流程createComponent

$vnode:占位符vnode。最終渲染vnode掛載的地方。所有的組件通過遞歸調(diào)用createComponent直至不再存在組件VNode,最終都會轉(zhuǎn)化成普通的dom。

{
    tag: 'vue-component-1-App',
    componentInstance: {組件實例},
    componentOptions: {Ctor, ..., }
}

_vnode:渲染vnode。

{
    tag: 'div',
    {
        "attrs": {
            "id": "app"
        }
    },
    // 對應(yīng)占位符vnode: $vnode
    parent: {
        tag: 'vue-component-1-App',
        componentInstance: {組件實例},
        componentOptions: {Ctor, ..., }
    },
    children: [
        // 對應(yīng)p標簽
        { 
            tag: 'p',
            // 對應(yīng)p標簽內(nèi)的文本節(jié)點{{ msg }}
            children: [{ text: 'hello world' }]
        }, {
          // 如果還有組件VNode其實也是一樣的
          tag: 'vue-component-2-xxx'
        }              
    ]
}

(注意:這一步對應(yīng)上圖render流程的紫色塊的展開!??!)

區(qū)分普通元素VNode

  • 普通VNode:tag是html的保留標簽,如tag: 'div'
  • 組件VNode:tag是以vue-component開頭,如tag: 'vue-component-1-App'

(注意:這一步對應(yīng)上圖patch流程的紫色塊的展開!?。?

4. Vue組件化簡化流程

相信你看完細粒度的Vue組件化過程可能已經(jīng)暈頭轉(zhuǎn)向了,這里會用一個簡化版的流程圖進行回顧,加深理解

二、響應(yīng)式流程

案例代碼

// 案例
export default {
    name: 'App',
    data () {
        return {
            msg: 'hello world',
            arr = [1, 2, 3]
        }
    }
}

1. 依賴收集

這里會從Observer、Dep、Watcher三個對象進行講解,分 objectarray 兩種依賴收集方式。

  • 一定要注意!數(shù)組 的依賴收集 跟 對象的屬性 是不一樣的。對象屬性經(jīng)過深度遍歷后,最終就是以一個基本類型的數(shù)據(jù)為單位收集依賴,但是數(shù)組仍然是一個引用類型。
  • 如果這里不懂,先想一個問題: 我們用 this.msg = 'xxx' 能觸發(fā) setter 派發(fā)更新,但是我們修改數(shù)組并不是用 this.arr = xxx ,而是用 this.arr.push(xxx) 等修改數(shù)組的方法。很顯然,這時候并不是通過觸發(fā) arr 的 setter 去派發(fā)更新的。那是怎么做的呢?先帶著這個問題繼續(xù)往下看吧!

三個核心對象:Observer(藍)、Dep(綠)、Watcher(紫)

依賴收集準備階段——Observer、Dep的實例化

// 以下是initData調(diào)用的方法講解,排列遵循調(diào)用順序
function observe (value, asRootData) {
  if (!isObject(value)) return // 非對象則不處理
  // 實例化Observer對象
  var ob;
  ob = new Observer(value);
  return ob
}
function Observer (value) {
  this.value = value; // 保存當前的data
  this.dep = new Dep(); // 實例化dep,數(shù)組進行依賴收集的dep(對應(yīng)案例中的arr)
  def(value, '__ob__', this);    
  if (Array.isArray(value)) {
    if (hasProto) {
      // 這里會改寫數(shù)組原型。__proto__指向重寫數(shù)組方法的對象
      protoAugment(value, arrayMethods); 
    } else {
      copyAugment(value, arrayMethods, arrayKeys);
    }
    this.observeArray(value);
  } else {
    this.walk(value); 
  }
}
// 遍歷數(shù)組元素,執(zhí)行對每一項調(diào)用observe,也就是說數(shù)組中有對象會轉(zhuǎn)成響應(yīng)式對象
Observer.prototype.observeArray = function observeArray (items) {
  for (var i = 0, l = items.length; i < l; i++) {
    observe(items[i]);
  }
}
// 遍歷對象的全部屬性,調(diào)用defineReactive
Observer.prototype.walk = function walk (obj) {
  var keys = Object.keys(obj);
  // 如案例代碼,這里的 keys = ['msg', 'arr']
  for (var i = 0; i < keys.length; i++) {        
    defineReactive(obj, keys[i]);
  }
}
function defineReactive (obj, key, val) {
  // 產(chǎn)生一個閉包dep
  var dep = new Dep();
  // 如果val是object類型,遞歸調(diào)用observe,案例代碼中的arr會走這個邏輯
  var childOb = !shallow && observe(val);
  Object.defineProperty(obj, key, {    
    get: function reactiveGetter () { 
      // 求value的值
      var value = getter ? getter.call(obj) : val;
      if (Dep.target) { // Dep.target就是當前的Watcher
        // 這里是閉包dep
        dep.depend();
        if (childOb) {
          // 案例代碼中arr會走到這個邏輯
          childOb.dep.depend(); // 這里是Observer里的dep,數(shù)組arr在此依賴收集
          if (Array.isArray(value)) {
            dependArray(value);
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      // 下文派發(fā)更新里進行講解
    }
  });
}

注意 對象 、 數(shù)組 的不同處理方式。這里以 核心代碼 + 圖 進行講解

接下來核心分析 defineReactive 做了什么。注意 childOb ,這是數(shù)組進行依賴收集的地方(也就是為什么我們 this.arr.push(4) 能找到 Watcher 進行派發(fā)更新)

依賴收集觸發(fā)階段——Wather實例化、訪問數(shù)據(jù)、觸發(fā)依賴收集

// new Wathcer核心
function Watcher (vm, expOrFn, cb, options, isRenderWatcher) {
  if (typeof expOrFn === 'function') {
  // 渲染watcher中,這里傳入的expOrFn是updateComponent = vm.update(vm.render())
  // this.getter等價于vm.update(vm.render())
    this.getter = expOrFn; 
  } else {
    ...
  }
  // 這里進行判斷,lazy為true時(計算屬性)則什么都不執(zhí)行,否則執(zhí)行g(shù)et
  this.value = this.lazy
    ? undefined
    : this.get(); // 本次為渲染W(wǎng)atcher,執(zhí)行g(shù)et,繼續(xù)往下看~
}
// Watcher的get方法
Watcher.prototype.get = function get () {
  // 這里很關(guān)鍵,pushTarget就是把當前的Wather賦值給“Dep.target”
  pushTarget(this);
  var value;
  var vm = this.vm;
  try {
    // 1. 這里調(diào)用getter,也就是執(zhí)行vm.update(vm.render())
    // 2. 執(zhí)行vm.render函數(shù)就會訪問到響應(yīng)式數(shù)據(jù),觸發(fā)get進行依賴收集
    // 3. 此時的Dep.target為當前的渲染W(wǎng)atcher,數(shù)據(jù)就可以理所應(yīng)當?shù)陌裌atcher加入自己的subs中
    // 4. 所以此時,Watcher就能監(jiān)測到數(shù)據(jù)變化,實現(xiàn)響應(yīng)式
    value = this.getter.call(vm, vm);
  } catch (e) {
    ...
  } finally {
    popTarget();
    /*
    * cleanupDeps是個優(yōu)化操作,會移除Watcher對本次render沒被使用的數(shù)據(jù)的觀測
    * 效果:處于v-if為false中的響應(yīng)式數(shù)據(jù)改變不會觸發(fā)Watcher的update
    * 感興趣的可以自己去debugger調(diào)試,這里就不展開了
    */
    this.cleanupDeps(); 
  }
  return value
}

Dep.target相關(guān)講解

  • targetStack:棧結(jié)構(gòu),用來保存Watcher
  • pushTarget:往targetStackpush當前的Watcher(排在前一個Watcher的后面),并把Dep.target賦值給當前Watcher
  • popTarget:先把targetStack最后一個元素彈出(.pop),再把Dep.target賦值給最后一個Watcher(也就是還原了前一個Watcher)
  • 通過上述實現(xiàn),vue保證了全局唯一的Watcher,準確賦值在Dep.target

細節(jié)太多繞暈了?來個整體流程,從宏觀角度再過一遍(computed部分可看完彩蛋后再回來重溫一下)

2. 派發(fā)更新

派發(fā)更新區(qū)分對象屬性、數(shù)組方法進行講解

如果想要深入了解組件的異步更新,戳這里,了解Vue組件異步更新之nextTick。本文只針對派發(fā)更新流程,不會對異步更新DOM進行展開講解~

這里可以先想一下,以下操作會發(fā)生什么?

this.msg = 'new val'

this.arr.push(4)

是的,毫無疑問都會先觸發(fā)他們之中的get,那再觸發(fā)什么呢?我們接下來看

對象屬性修改觸發(fā)set,派發(fā)更新。this.msg = 'new val'

...
Object.defineProperty (obj, key, {
    get () {...},
    set: function reactiveSetter (newVal) {
      var value = getter ? getter.call(obj) : val;
      // 判斷新值相比舊值是否已經(jīng)改變
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      // 如果新值是引用類型,則將其轉(zhuǎn)化為響應(yīng)式
      childOb = !shallow && observe(newVal);
      // 這里通知dep的所有watcher進行更新
      dep.notify();
    }
}        
...

數(shù)組調(diào)用方法。this.arr.push(4)

// 數(shù)組方法改寫是在 Observer 方法中
function Observer () {
    if (hasProto) { 
        // 用案例講解,也就是this.arr.__proto__ = arrayMethods
        protoAugment(value, arrayMethods); 
    }
}   
// 以下是數(shù)組方法重寫的實現(xiàn)
var arrayProto = Array.prototype; // 保存真實數(shù)組的原型
var arrayMethods = Object.create(arrayProto); // 以真數(shù)組為原型創(chuàng)建對象
// 可以看成:arrayMethods.__proto__ = Array.prototype
var methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
];
// 一個裝飾器模型,重寫7個數(shù)組方法
methodsToPatch.forEach(function (method) {
  // 保存原生的數(shù)組方法
  var original = arrayProto[method];
  // 劫持arrayMethods對象中的數(shù)組方法
  def(arrayMethods, method, function mutator () {
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];
    var result = original.apply(this, args);
    var ob = this.__ob__; // 當我門調(diào)用this.arr.push(),這里就能到數(shù)組對象的ob實例
    var inserted;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args;
        break
      case 'splice':
        inserted = args.slice(2);
        break
    }
    if (inserted) { ob.observeArray(inserted); }
    // 由于數(shù)組對象在new Observer中實例化了一個dep,并通過childOb邏輯收集了依賴,這里就能在ob實例中拿到dep屬性
    ob.dep.notify();
    return result
  });
})
  • 這里可以聯(lián)合數(shù)組的依賴收集再看一遍,你就恍然大悟了。為什么 對象的屬性 、數(shù)組 的依賴收集方式不一樣

整個new Vue階段、到依賴收集、派發(fā)更新的全部流程就到這里結(jié)束了??梢钥v觀流程圖看出,Vue應(yīng)用就是一個個Vue組件組成的,雖然整個組件化、響應(yīng)式流程很多,但核心的路徑一旦走通,你就會恍然大悟。

三、彩蛋篇

1. computed依賴收集

  • 案例代碼
<template>
    <div id="app">
        {{ name }}
    </div>
</template>
<script>
export default {
    name: 'App',
    computed: {
      name () {
        return this.firstName + this.secondName
      }
    },
    data () {
        return {
            firstName: 'jing',
            secondName: 'boran'
        }
    }
}
</script>
  • 我們先看流程圖。圖有點大~大家可以放大看看,每個核心步驟都附有文字說明

根據(jù)案例概括一下,加深理解

// 訪問computed時觸發(fā)get的核心代碼 
function createComputedGetter (key) {
  return function computedGetter () {
    var watcher = this._computedWatchers && this._computedWatchers[key];
    if (watcher) {
      if (watcher.dirty) { // dirty第一次為true
        watcher.evaluate(); // 這里是對computed進行求值,對computed watcher執(zhí)行依賴收集
      }
      if (Dep.target) {
        watcher.depend(); // 這里是對渲染W(wǎng)atcher進行依賴收集
      }
      return watcher.value
    }
  }
}

computed中的name其實就是一個computed Watcher,這個Watcher在init階段生成

當App組件render的階段,render函數(shù)會訪問到模版中的{{ name }},則會觸發(fā)computed的求值,也就是執(zhí)行上面代碼computedGetter()。執(zhí)行watcher.evaluate()。也就是執(zhí)行wathcer.get。上文依賴收集的第3點:依賴收集觸發(fā)階段有對get方法進行講解,忘了的可以上去回顧一下執(zhí)行watcher.depend()

Watcher.prototype.depend = function depend () {
  var i = this.deps.length;
  while (i--) {
    // 也就是調(diào)用Dep.depend => Watcher.addDep => dep.addSub
    this.deps[i].depend(); 
  }
}
// this.firstName和this.secondName的dep.subs
dep.subs: [name的computed watcher, App組件的渲染W(wǎng)atcher]

代碼中判斷watcher.dirty標志是什么?有什么用?

只有computed的值發(fā)生改變(也就是其依賴的數(shù)據(jù)改變),watcher.dirty才會被設(shè)為true

只有watcher.dirtytrue才會對computed進行 求值 或 重新求值

總結(jié):也就是組件每次render,如果computed的值沒改變,直接返回value值(是不需要重新計算的),這也是computed的一個特點

  • 首先pushTargetDep.target從App組件的渲染W(wǎng)atcher改為name的computed Watcher
  • 其次執(zhí)行cb:function() { return this.firstName + this.secondName }
  • 執(zhí)行cb的過程中,必然會訪問到firstName、secondName,這時候就是我們熟悉的依賴收集階段了。firstName、secondName都會把name這個computed watcher收集到自己的dep.subs[]
  • 最后popTarget把name的computed Watcher彈出棧,并恢復(fù)Dep.target為當前App組件的渲染W(wǎng)atcher
  • 遍歷computed watcher的deps。其實就是firstName、secondName實例的Dep
  • dep.depend也就是調(diào)用watcher.addDep(把Dep收集進watcher.deps中),再由watcher.appDep調(diào)用dep.addSub(把Watcher收集進dep.subs中)
  • 這樣一來,就完成了firstName、secondName對App組件的渲染watcher進行收集
  • 結(jié)果如下。響應(yīng)式數(shù)據(jù)中會存在兩個Watcher
  • 至于為什么響應(yīng)式數(shù)據(jù)要收集2個watcher?下文computed派發(fā)更新會講解

講到這里,我以自己的理解講解下文章開頭引言的問題:為什么Watcher、Dep多對多且相互收集? 這可能也是大家閱讀Vue源碼中一直存在的一個疑惑(包括我自己剛開始讀也是這樣)

對的,當然是為了computed中的響應(yīng)式數(shù)據(jù)收集渲染W(wǎng)atcher啦?。?!

還有?。?! 還記得前文中依賴收集的第3點——依賴收集觸發(fā)階段的代碼講解中我寫了很多注釋的cleanupDeps嗎?

// 此時flag為true,也就是說msg2沒有渲染在頁面中
<div v-if="flag">{{ msg1 }}</div>
<div v-else>{{ msg2 }}</div>
<button @click=() => { this.msg2 = 'change' }>changeMsg2</button>
function cleanupDeps () {
  var i = this.deps.length;
  while (i--) {
    // 這里對watcher所觀測的響應(yīng)式數(shù)據(jù)的dep進行遍歷
    // 對的,這樣一來,是不是watcher中的deps就發(fā)揮作用了呢?
    var dep = this.deps[i];
    if (!this.newDepIds.has(dep.id)) {
      // 這里對當前渲染中沒有訪問到的響應(yīng)式數(shù)據(jù)進行依賴移除
      dep.removeSub(this); 
    }
  }
  ...
}
  • cleanupDeps的作用就是清除掉當前沒有使用到的響應(yīng)式數(shù)據(jù)。怎么清除?我們往下看
  • 首先看個案例回答個問題,代碼如下。當flag為true時,msg2并沒有渲染在頁面中,那么此時我們點擊按鈕修改msg2的值會不會、或者應(yīng)不應(yīng)該觸發(fā)這個組件的重新渲染呢?
  • 答案肯定是不會、不應(yīng)該。所以:cleanupDeps就是為此而存在的
  • cleanupDeps是怎么工作的呢?接著看下面代碼
  • 到此,你是否已經(jīng)懂得了watcher中為什么要收集自己觀測的響應(yīng)式數(shù)據(jù)對應(yīng)的dep呢?

2. computed派發(fā)更新

派發(fā)相對來說比較簡單了~跟響應(yīng)式的派發(fā)更新基本一致,繼續(xù)以案例來講解吧!

當我們修改firstName會發(fā)生什么?this.firstName = 'change'

首先觸發(fā)firstName的set,最終會調(diào)用dep.notify()。firstName的dep.subs中有2個watcher,分別執(zhí)行對應(yīng)watcher的notify

Watcher.prototype.update = function update () {      
  if (this.lazy) {
    this.dirty = true; // computed會走到這里,然后就結(jié)束了
  } else if (this.sync) {
    this.run();
  } else {
    queueWatcher(this); // 渲染watcher會走到這里
  }
}

computed watcher:將dirty屬性置為true。

渲染watcher會執(zhí)行派發(fā)更新流程(如本文響應(yīng)式流程——2.派發(fā)更新一致)

nextTick階段執(zhí)行flushSchedulerQueue,則會執(zhí)行watcher.run()

watcher.run會執(zhí)行watcher.get方法,也就是重新執(zhí)行render、update的流程

執(zhí)行render又會訪問到name的computed,從而又會執(zhí)行computedGetter

此時的watcher.dirty在本步驟3已經(jīng)置為true,又會執(zhí)行watcher.evaluate()進行computed的求值,執(zhí)行watcher.depend()......后續(xù)的流程就是派發(fā)更新的流程了~

3. user Watcher依賴收集

user Watcher的依賴收集相比computed會簡單一點,這里不會贅述太多,只說核心區(qū)別,還有watch的常用配置immediate、deepsync

user Watcher在init階段會執(zhí)行一次watcher.get(),在這里會訪問我們watch的響應(yīng)式數(shù)據(jù),從而進行依賴收集。回顧下computed,computed在這個階段什么也沒做。

// 沒錯,又是這段熟悉的代碼
this.value = this.lazy
  ? undefined
  : this.get(); // user Watcher和渲染 Watcher都在new Watcher階段執(zhí)行g(shù)et()

如果userWatcher設(shè)置的immediate: true,則會在new Watcher后主動觸發(fā)一次cb的執(zhí)行

Vue.prototype.$watch = function (expOrFn, cb, options) {
  ...
  var watcher = new Watcher(vm, expOrFn, cb, options);
  if (options.immediate) {
    // immediate則會執(zhí)行我們傳入的callback
    try {
      cb.call(vm, watcher.value);
    } catch (error) {
    }
  }
  return function unwatchFn () {
    watcher.teardown();
  }
};

deep邏輯很簡單,大概講下:深度遍歷這個對象,訪問到該對象的所有屬性,以此來觸發(fā)所有屬性的getter。這樣,所有屬性都會把當前的user Watcher收集到自己的dep中。因此,深層的屬性值修改(觸發(fā)set派發(fā)更新能通知到user Watcher),watch自然就能監(jiān)測到數(shù)據(jù)改變~感興趣的同學可以自己去看看源碼中traverse的實現(xiàn)。

sync。當前tick執(zhí)行,以此能先于渲染W(wǎng)athcer執(zhí)行。不設(shè)置同步的watcher都會放到nextTick中執(zhí)行。

Watcher.prototype.update = function update () {
  if (this.lazy) {
    this.dirty = true; // 計算屬性
  } else if (this.sync) {
    this.run(); // 同步的user Wathcer
  } else {
    queueWatcher(this); // 普通user Watcher和渲染W(wǎng)atcher
  }
}

總體來說,Vue的源碼其實是比較好上手的,整體代碼流程非常的清晰。但是想要深入某一塊邏輯,最好結(jié)合流程圖加debugger方式親自上手實踐。畢竟真正搞懂一門框架的源碼并非易事,我也是通過不斷debugger調(diào)試,一遍遍走核心流程,才能較好的學習理解vue的實現(xiàn)原理~

寫在最后,這篇文章也算是自己的一個知識沉淀吧,畢竟很早之前就學習過Vue的源碼了,但是也一直沒做筆記?,F(xiàn)在回顧一下,發(fā)現(xiàn)很多都有點忘了,但是缺乏一個快速記憶、回顧的筆記。如果要直接硬磕源碼重新記憶,還是比較費時費力的~作為知識分享,希望可以幫助到想學習源碼,想要進階的你,大家彼此共勉,一同進步!

以上就是圖解Vue 響應(yīng)式原理的詳細內(nèi)容,更多關(guān)于Vue 響應(yīng)式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue實現(xiàn)簡單的留言板

    Vue實現(xiàn)簡單的留言板

    這篇文章主要為大家詳細介紹了Vue實現(xiàn)簡單的留言板,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • 基于Vue3和element-plus實現(xiàn)登錄功能(最終完整版)

    基于Vue3和element-plus實現(xiàn)登錄功能(最終完整版)

    這篇文章主要介紹了基于Vue3和element-plus實現(xiàn)一個完整的登錄功能,本文結(jié)合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • 使用Vue3和Echarts?5繪制帶有立體感流線中國地圖(推薦收藏!)

    使用Vue3和Echarts?5繪制帶有立體感流線中國地圖(推薦收藏!)

    最近接到一個需求是做一個中國地圖,下面這篇文章主要給大家介紹了關(guān)于如何使用Vue3和Echarts?5繪制帶有立體感流線中國地圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • vue項目運行超詳細圖解

    vue項目運行超詳細圖解

    這篇文章主要給大家介紹了關(guān)于vue項目運行的相關(guān)資料,文中通過圖文介紹的非常詳細,對大家學習或者使用vue具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • Vue之自定義事件內(nèi)容分發(fā)詳解

    Vue之自定義事件內(nèi)容分發(fā)詳解

    這篇文章主要為大家介紹了Vue的自定義事件內(nèi)容分發(fā),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • vue中的按鈕綁定事件小案例

    vue中的按鈕綁定事件小案例

    這篇文章主要介紹了vue中的按鈕綁定事件小案例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • vue中proxy代理的用法(解決跨域問題)

    vue中proxy代理的用法(解決跨域問題)

    這篇文章主要介紹了vue中的proxy代理的用法(解決跨域問題),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • .html頁面引入vue并使用公共組件方式

    .html頁面引入vue并使用公共組件方式

    這篇文章主要介紹了.html頁面引入vue并使用公共組件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Vue組件為什么data必須是一個函數(shù)

    Vue組件為什么data必須是一個函數(shù)

    這篇文章主要介紹了Vue組件為什么data必須是一個函數(shù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-06-06
  • vue在使用element組件出現(xiàn)<el-input>標簽無法輸入的問題

    vue在使用element組件出現(xiàn)<el-input>標簽無法輸入的問題

    這篇文章主要介紹了vue在使用element組件出現(xiàn)<el-input>標簽無法輸入的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04

最新評論