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

Vue3和Vue2的響應式原理

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

什么是響應式?

簡單來說,響應式就是頁面的模版內容能隨著數據變化而重新渲染。我們來看一個案例:

<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 官方提供的響應式 API,count 就是通過響應式 API 聲明的響應式數據。count 這個數據可以直接在模板里使用,例如上述代碼中我們使用了count 數據進行顯示。

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

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

那響應式原理是如何實現的呢?接下來我們就一起來看下。

響應式原理

我們以一個經常被拿來當作典型例子的用例即是 Excel 表格:

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

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

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

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

Vue2響應式方案

Vue2的實現方案主要是借助于Object.defineProperty。

這里來看下如下通過Object.defineProperty ,來實現我們的目標:

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

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

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

非原始值的響應式方案

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

非原始值的響應式數據是基于Proxy實現的,它允許我們攔截并重新定義一個對象的基本操作,具體API 我們可以訪問MDN 文檔

這里來看下如下通過Proxy ,來實現我們的目標:

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

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

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

原始值的響應式方案

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

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

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

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

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

響應式原理注意事項

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

Vue 2注意事項

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

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

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

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

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

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

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

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

舉個例子:

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

為了解決第一類問題,以下方式都可以實現和 vm.items[indexOfItem] = newValue 相同的效果,同時也將在響應式系統(tǒng)內觸發(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 的響應式開發(fā)有什么需要注意的?

第一個注意事項是響應式數據解構,這可能會丟失響應式聯系,例如:

<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 的響應式聯系并不會生效,修改 text 內容后,不會觸發(fā)頁面的展示文本 text 的視圖更新渲染。這是為什么呢?

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

那如果我們就想用解構的方法來使用text變量怎么辦?可以借助toRefs 來實現:

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

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

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

異步更新隊列

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

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

nextTick() 可以在狀態(tài)改變后立即使用,以等待 DOM 更新完成。你可以傳遞一個回調函數作為參數,或者 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 此時已經更新
  console.log(document.getElementById('counter').textContent) // 1
}
</script>
<template>
  <button id="counter" @click="increment">{{ count }}</button>
</template>

總結

今天的知識點我們來做個總結:

1、我們認識了什么是響應式,其實就是頁面的模版內容能隨著數據變化而重新渲染。

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

以上就是Vue3和Vue2的響應式原理的詳細內容,更多關于Vue3和Vue2 響應式原理的資料請關注腳本之家其它相關文章!

相關文章

  • 分享vue里swiper的一些坑

    分享vue里swiper的一些坑

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

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

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

    elementui?Select選擇器嵌套tree實現TreeSelect方式

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

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

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

    vant steps流程圖的圖標使用slot自定義方式

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

    Vue3中props傳參方式詳解

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

    Vue的過濾器你真了解嗎

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

    vue中使用refs定位dom出現undefined的解決方法

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

    vue.js在標簽屬性中插入變量參數的方法

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

    django+vue實現注冊登錄的示例代碼

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

最新評論