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

Vue3和Vue2的響應(yīng)式原理

 更新時間:2023年05月31日 11:39:04   作者:書源  
這篇文章我們將探討Vue3框架的優(yōu)秀特性、使用原理、周邊生態(tài)和實戰(zhàn)應(yīng)用,系統(tǒng)的學(xué)習(xí)Vue生態(tài)體系,希望和大家共同成長,我們一起探討下Vue3和Vue2的響應(yīng)式原理,那究竟什么是“響應(yīng)式”,接下來跟著小編一起來學(xué)習(xí)吧

什么是響應(yīng)式?

簡單來說,響應(yīng)式就是頁面的模版內(nèi)容能隨著數(shù)據(jù)變化而重新渲染。我們來看一個案例:

<template>
  <div id="app">
    <div>Count: {{ count }}</div>
    <button class="btn" @click="onAdd">Add</button>
  </div>
</template>
<script setup>
import { ref } from "vue";
const count = ref(1);
const onAdd = () => {
  count.value++;
};
</script>

在這段代碼中,ref 是 Vue3 官方提供的響應(yīng)式 API,count 就是通過響應(yīng)式 API 聲明的響應(yīng)式數(shù)據(jù)。count 這個數(shù)據(jù)可以直接在模板里使用,例如上述代碼中我們使用了count 數(shù)據(jù)進(jìn)行顯示。

那么響應(yīng)式體現(xiàn)在哪呢?上述代碼有一個點擊事件的函數(shù) onAdd,這個函數(shù)實現(xiàn)了對 count 數(shù)值的自增操作。每當(dāng)點擊這個 onAdd 事件,count 就會自動加 1,對應(yīng)使用到 count 的模板也會隨之重新渲染最新的數(shù)據(jù)。

上述功能代碼里的這種視圖隨著數(shù)據(jù)的變化,就是響應(yīng)式的特征?;?Vue的響應(yīng)式 API 生成的數(shù)據(jù),就是響應(yīng)式數(shù)據(jù),如果響應(yīng)式數(shù)據(jù)發(fā)生了變化,那么依賴了數(shù)據(jù)的視圖也會跟著變化。

那響應(yīng)式原理是如何實現(xiàn)的呢?接下來我們就一起來看下。

響應(yīng)式原理

我們以一個經(jīng)常被拿來當(dāng)作典型例子的用例即是 Excel 表格:

這里單元格 A2 中的值是通過公式 = 5 * A1 來定義的 ,我們期望更改 A1, A2 也隨即自動更新。

而 JavaScript 默認(rèn)并不是這樣的。如果我們用 JavaScript 寫類似的邏輯:

let A1 = 1;
let A2 = 5 * A1;
console.log(A2); // 5A1 = 2;console.log(A2); // 仍然是 5

我們現(xiàn)在的目標(biāo)是,在 A1 變化時會調(diào)用 effect() (產(chǎn)生作用)。在具體實現(xiàn)時,Vue2和Vue3采取了不同的實現(xiàn)方案,我們一一看下【備注:更完善的響應(yīng)式原理會在專欄后續(xù)補充】。

Vue2響應(yīng)式方案

Vue2的實現(xiàn)方案主要是借助于Object.defineProperty。

這里來看下如下通過Object.defineProperty ,來實現(xiàn)我們的目標(biāo):

let obj = {};
let A1;
let A2;
function effect() {
  A2 = 5 * A1;
}
Object.defineProperty(obj, "A1", {
  get() {
    return A1;
  },
  set(val) {
    A1 = val;
    effect();
  },
});
obj.A1 = 1;
console.log(A2); // 打印5obj.A1 = 2;console.log(A2); // 打印10

在上面的實現(xiàn)中,我們定義個一個對象 obj,使用 Object.defineProperty 代理 A1  屬性,進(jìn)而對 obj 對象的 value 屬性實現(xiàn)了攔截,讀取 A1 屬性的時候執(zhí)行 get 函數(shù),修改 A1 屬性的時候執(zhí)行 set 函數(shù),在 set 函數(shù)內(nèi)部調(diào)用 effect() 函數(shù),從而實現(xiàn)響應(yīng)式。

接下來我們來看下Vue3的響應(yīng)式方案,不過它分非原始值的響應(yīng)式和原始值的響應(yīng)式。

非原始值的響應(yīng)式方案

什么是非原始值呢?其實就是對象,而并非數(shù)字、字符串。

非原始值的響應(yīng)式數(shù)據(jù)是基于Proxy實現(xiàn)的,它允許我們攔截并重新定義一個對象的基本操作,具體API 我們可以訪問MDN 文檔。

這里來看下如下通過Proxy ,來實現(xiàn)我們的目標(biāo):

let obj = {};
let A1;
let A2;
function effect(val) {
  A2 = 5 * val;
}
let proxy = new Proxy(obj, {
  get: function (target, prop) {
    return target[prop];
  },
  set: function (target, prop, value) {
    target[prop] = value;
    effect(value);
  },
});
proxy.A1 = 1;
console.log(A2); // 打印5proxy.A1 = 2;console.log(A2); // 打印10

在上面的實現(xiàn)中,我們定義了一個對象 obj,使用 Proxy 代理 obj,實現(xiàn)了和Vue2相同的功能 ,讀取 A1 屬性的時候執(zhí)行 get 函數(shù),修改 A1 屬性的時候執(zhí)行 set 函數(shù),在 set 函數(shù)內(nèi)部調(diào)用 effect() 函數(shù),從而實現(xiàn)響應(yīng)式。

Object.defineProperty所不同的是Proxy 是針對對象來監(jiān)聽,而不是針對某個具體屬性,所以不僅可以代理那些定義時不存在的屬性,還可以代理更豐富的數(shù)據(jù)結(jié)構(gòu),比如 Map、Set 等等。

原始值的響應(yīng)式方案

什么是原始值?原始值指的是Boolean、Number、String、null等類型的值。

在JavaScript中,原始值是按值傳遞的,而非按引用傳遞。如果一個函數(shù)接收原始值作為參數(shù),那么形參和實參之間沒有引用關(guān)系,是兩個完全獨立的值。此外,JavaScript中的proxy無法提供對原始值的代理,想要將原始值變成響應(yīng)式數(shù)據(jù),就必須對其做一層包裹,借助對象的 get 和 set 函數(shù)來實現(xiàn):

let A1 = 1;
let A2;
function effect(val) {
  A2 = 5 * val;
}
let obj = {
  get value() {
    return A1;
  },
  set value(val) {
    A1 = val;
    effect(val);
  },
};
obj.value = 1;
console.log(A2); // 打印5obj.value = 2;console.log(A2); // 打印10

在上面的實現(xiàn)中,我們利用對象的 get 和 set 函數(shù)來進(jìn)行監(jiān)聽,這種響應(yīng)式的實現(xiàn)方式,只能攔截某一個屬性,這也是 Vue 3 中 ref 這個 API 的實現(xiàn)。

以上我們了解了響應(yīng)式原理,不過我們想在工作中更好地運用響應(yīng)式API,我們還需要知道在響應(yīng)式開發(fā)中可能會遇到什么“坑”。

響應(yīng)式原理注意事項

我們先來了解一下 Vue 2的注意事項,由于 JavaScript 的限制,Vue 不能檢測數(shù)組和對象的變化。盡管如此我們還是有一些辦法來回避這些限制并保證它們的響應(yīng)性。

Vue 2注意事項

對于對象,Vue2 無法檢測 property 的添加或移除。由于 Vue 會在初始化實例時對 property 執(zhí)行 getter/setter 轉(zhuǎn)化,所以 property 必須在 data 對象上存在才能讓 Vue 將它轉(zhuǎn)換為響應(yīng)式的。例如:

var vm = new Vue({ data: { a: 1 } }); // `vm.a` 是響應(yīng)式的vm.b = 2// `vm.b` 是非響應(yīng)式的

對于已經(jīng)創(chuàng)建的實例,Vue 不允許動態(tài)添加根級別的響應(yīng)式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套對象添加響應(yīng)式 property。例如:

Vue.set(vm.someObject, "b", 2);

您還可以使用 vm.$set 實例方法,這也是全局 Vue.set 方法的別名:

this.$set(this.someObject, "b", 2);

對于數(shù)組,Vue2 不能檢測以下數(shù)組的變動:

  • 當(dāng)你利用索引直接設(shè)置一個數(shù)組項時,例如:vm.items[index] = newValue
  • 當(dāng)你修改數(shù)組的長度時,例如:vm.items.length = newLength

舉個例子:

var vm = new Vue({ 
	data: {
		items: ["a", "b", "c"]
	} 
});
vm.items[1] = "x"; // 不是響應(yīng)性的vm.items.length = 2 // 不是響應(yīng)性的

為了解決第一類問題,以下方式都可以實現(xiàn)和 vm.items[indexOfItem] = newValue 相同的效果,同時也將在響應(yīng)式系統(tǒng)內(nèi)觸發(fā)狀態(tài)更新:

// Vue.setVue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue)
// 該方法是全局方法 Vue.set 的一個別名
vm.$set(vm.items, indexOfItem, newValue);

為了解決第二類問題,你可以使用 splice

vm.items.splice(newLength);

Vue 3注意事項

Vue.js 3 的響應(yīng)式開發(fā)有什么需要注意的?

第一個注意事項是響應(yīng)式數(shù)據(jù)解構(gòu),這可能會丟失響應(yīng)式聯(lián)系,例如:

<template>
  <div id="app">
    <input v-model="text" placeholder="文本信息" /> 文本信息:{{ text }}
  </div>
</template>
<script setup>
import { reactive } from "vue";
const state = reactive({ text: "hello world" });
const { text } = state;
</script>

在上述代碼中,text 的響應(yīng)式聯(lián)系并不會生效,修改 text 內(nèi)容后,不會觸發(fā)頁面的展示文本 text 的視圖更新渲染。這是為什么呢?

這里我們用 reactive 定義了 state 響應(yīng)式數(shù)據(jù),但是在之后又把其中的 state.text 解構(gòu)賦值給了變量 text,這就會斷掉響應(yīng)式聯(lián)系,導(dǎo)致再怎么更新 text 都不會觸發(fā)視圖重新更新渲染。

那如果我們就想用解構(gòu)的方法來使用text變量怎么辦?可以借助toRefs 來實現(xiàn):

<script setup>
import { reactive, toRefs } from "vue";
const state = reactive({ text: "hello world" });
const { text } = toRefs(state);
</script>

第二個注意事項是Vue3官方指明謹(jǐn)慎使用的API,例如 shallowReactive 、 shallowReadonly等等,示例:

const state = shallowReactive({
  foo: 1,
  nested: {
    bar: 2
  }
})
// 更改狀態(tài)自身的屬性是響應(yīng)式的
state.foo++
// ...但下層嵌套對象不會被轉(zhuǎn)為響應(yīng)式
isReactive(state.nested) // false
// 不是響應(yīng)式的
state.nested.bar++

異步更新隊列

異步隊列更新,這是Vue2和Vue3都共存的注意事項,當(dāng)你在 Vue 中更改響應(yīng)式狀態(tài)時,最終的 DOM 更新并不是同步生效的,而是由 Vue 將它們緩存在一個隊列中,直到下一個“tick”才一起執(zhí)行。這樣是為了確保每個組件無論發(fā)生多少狀態(tài)改變,都僅執(zhí)行一次更新。

多數(shù)情況我們不需要關(guān)心這個過程,但是如果你想基于更新后的 DOM 狀態(tài)來做點什么,這就可能會有些棘手。雖然 Vue.js 通常鼓勵開發(fā)人員使用數(shù)據(jù)驅(qū)動的方式思考,避免直接接觸 DOM,但是有時我們必須要這么做。

nextTick() 可以在狀態(tài)改變后立即使用,以等待 DOM 更新完成。你可以傳遞一個回調(diào)函數(shù)作為參數(shù),或者 await 返回的 Promise。示例:

<script setup>
import { ref, nextTick } from 'vue'
const count = ref(0)
async function increment() {
  count.value++
  // DOM 還未更新
  console.log(document.getElementById('counter').textContent) // 0
  await nextTick()
  // DOM 此時已經(jīng)更新
  console.log(document.getElementById('counter').textContent) // 1
}
</script>
<template>
  <button id="counter" @click="increment">{{ count }}</button>
</template>

總結(jié)

今天的知識點我們來做個總結(jié):

1、我們認(rèn)識了什么是響應(yīng)式,其實就是頁面的模版內(nèi)容能隨著數(shù)據(jù)變化而重新渲染。

2、我們總結(jié)了Vue2和Vue3各自的響應(yīng)式實現(xiàn)原理以及開發(fā)需要注意的事項。

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

相關(guān)文章

  • 分享vue里swiper的一些坑

    分享vue里swiper的一些坑

    這篇文章主要介紹了vue里swiper的一些坑及swiper在vue中的使用,本文分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-08-08
  • Vue監(jiān)聽器簡單使用及注意事項說明

    Vue監(jiān)聽器簡單使用及注意事項說明

    這篇文章主要介紹了Vue監(jiān)聽器簡單使用及注意事項說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • elementui?Select選擇器嵌套tree實現(xiàn)TreeSelect方式

    elementui?Select選擇器嵌套tree實現(xiàn)TreeSelect方式

    這篇文章主要介紹了elementui?Select選擇器嵌套tree實現(xiàn)TreeSelect方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue-cli開發(fā)環(huán)境實現(xiàn)跨域請求的方法

    vue-cli開發(fā)環(huán)境實現(xiàn)跨域請求的方法

    本篇文章主要介紹了vue-cli開發(fā)環(huán)境實現(xiàn)跨域請求的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • vant steps流程圖的圖標(biāo)使用slot自定義方式

    vant steps流程圖的圖標(biāo)使用slot自定義方式

    這篇文章主要介紹了vant steps流程圖的圖標(biāo)使用slot自定義方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Vue3中props傳參方式詳解

    Vue3中props傳參方式詳解

    這篇文章主要為大家詳細(xì)介紹了Vue3中props傳參方式(多種數(shù)據(jù)類型傳參方式)的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11
  • Vue的過濾器你真了解嗎

    Vue的過濾器你真了解嗎

    這篇文章主要為大家詳細(xì)介紹了Vue的過濾器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • vue中使用refs定位dom出現(xiàn)undefined的解決方法

    vue中使用refs定位dom出現(xiàn)undefined的解決方法

    本篇文章主要介紹了vue中使用refs定位dom出現(xiàn)undefined的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • vue.js在標(biāo)簽屬性中插入變量參數(shù)的方法

    vue.js在標(biāo)簽屬性中插入變量參數(shù)的方法

    這篇文章主要介紹了vue.js在標(biāo)簽屬性中插入變量參數(shù)的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-03-03
  • django+vue實現(xiàn)注冊登錄的示例代碼

    django+vue實現(xiàn)注冊登錄的示例代碼

    這篇文章主要介紹了django+vue實現(xiàn)注冊登錄的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05

最新評論