在 Vue 3 中,provide 和 inject 是通過 Vue 的響應式系統和組件實例機制實現的,底層是依賴 Vue 3 中的 Proxy 和 Reactive 來實現跨層級的數據傳遞和響應式綁定。以下是一個簡化版的實現邏輯,幫助理解 Vue 3 中 provide 和 inject 是如何實現的。
- provide 的實現
provide 的核心目的是將數據存儲在當前組件的上下文中,然后將這些數據傳遞給其后代組件。Vue 3 使用 Proxy 來實現對組件上下文的響應式管理。
基本的實現思路:
在父組件中,使用 provide 將數據存儲到一個上下文對象中,父組件上下文數據存儲在當前組件實例的 provides 對象中。
父組件的 provides 會暴露給子組件,子組件可以從父組件的上下文中讀取提供的數據。
簡化版的實現邏輯如下:
class Component {
constructor() {
this.provides = new Map(); // 存儲提供的數據
}
provide(key, value) {
this.provides.set(key, value); // 設置提供的數據
}
inject(key) {
return this.provides.get(key); // 從當前組件的 provides 中獲取
}
}
示例:
const parentComponent = new Component();
parentComponent.provide(‘user’, { name: ‘John’, age: 30 });
const childComponent = new Component();
const user = childComponent.inject(‘user’); // 獲取父組件提供的數據
console.log(user); // 輸出: { name: ‘John’, age: 30 }
- inject 的實現
inject 用來從當前組件的父組件(或祖先組件)中獲取提供的數據。在實際實現中,Vue 會查找組件的父鏈(即組件樹)來查找所需的 provide 數據。
基本的實現思路:
在子組件中,使用 inject 來獲取上層組件通過 provide 提供的數據。Vue 會遍歷組件樹,查找最近的祖先組件。
如果當前組件沒有提供數據,Vue 會繼續向上查找直到根組件。
class Component {
constructor(parent = null) {
this.parent = parent;
this.provides = new Map(); // 存儲提供的數據
}
provide(key, value) {
this.provides.set(key, value);
}
inject(key) {
// 從當前組件開始,逐級向父組件查找數據
let currentComponent = this;
while (currentComponent) {
if (currentComponent.provides.has(key)) {
return currentComponent.provides.get(key);
}
currentComponent = currentComponent.parent;
}
return undefined; // 如果找不到提供的數據,返回 undefined
}
}
示例:
// 父組件提供數據
const parentComponent = new Component();
parentComponent.provide(‘user’, { name: ‘John’, age: 30 });
// 子組件繼承父組件
const childComponent = new Component(parentComponent);
// 孫組件繼承子組件
const grandchildComponent = new Component(childComponent);
// 孫組件注入父組件提供的數據
const user = grandchildComponent.inject(‘user’);
console.log(user); // 輸出: { name: ‘John’, age: 30 }
- 響應式機制
在 Vue 3 中,provide 和 inject 采用的是基于 Proxy 的響應式系統。Vue 3 的響應式系統使用 Proxy 來監聽對象的變化,確保在數據變更時能夠觸發視圖更新。
為了實現響應式傳遞,Vue 會通過 reactive 來包裝提供的數據,然后使用 provide 提供的值會是一個響應式對象,子組件通過 inject 獲取該對象時,數據的變化會自動反應到視圖中。
簡化的響應式實現:
function reactive(obj) {
return new Proxy(obj, {
get(target, prop) {
console.log(Accessing ${prop}
); // 打印屬性訪問的日志
return target[prop];
},
set(target, prop, value) {
console.log(Setting ${prop} to ${value}
); // 打印屬性設置的日志
target[prop] = value;
return true;
}
});
}
class Component {
constructor(parent = null) {
this.parent = parent;
this.provides = new Map();
}
provide(key, value) {
this.provides.set(key, reactive(value)); // 提供響應式數據
}
inject(key) {
let currentComponent = this;
while (currentComponent) {
if (currentComponent.provides.has(key)) {
return currentComponent.provides.get(key); // 返回響應式數據
}
currentComponent = currentComponent.parent;
}
return undefined;
}
}
示例:
// 父組件提供響應式數據
const parentComponent = new Component();
const user = { name: ‘John’, age: 30 };
parentComponent.provide(‘user’, user);
// 子組件繼承父組件
const childComponent = new Component(parentComponent);
// 孫組件繼承子組件
const grandchildComponent = new Component(childComponent);
// 孫組件注入父組件提供的響應式數據
const injectedUser = grandchildComponent.inject(‘user’);
injectedUser.name = ‘Jane’; // 通過代理修改數據
console.log(user.name); // 輸出: Jane,數據變化自動反映
總結
Vue 3 中的 provide 和 inject 實現是基于 Proxy 的響應式系統,組件的 provides 數據是響應式的,當數據變化時,依賴這些數據的組件會自動更新。provide 用來提供數據,inject 用來注入數據,支持跨組件層級的數據共享。通過 Proxy,Vue 3 能夠實現跨層級數據傳遞和數據的自動更新,使得組件間的數據通信更加靈活和高效。