VUE3中setup語法糖解決響應(yīng)式的方案,所有的只要被ref或者reactive包裹的變量,都會(huì)轉(zhuǎn)變成響應(yīng)式。而在VUE2中,要想做成響應(yīng)式,必須將變量定義在data函數(shù)中。
1、ref:將一個(gè)屬性或者對象定義成ref對象,也就是將一個(gè)屬性或者對象變成響應(yīng)式,修改值必須.value才能處理對應(yīng)的值。
- 以下代碼定義了三個(gè)User對象,并且都是使用ref做成了響應(yīng)式,當(dāng)點(diǎn)擊按鈕改變User對象的值的時(shí)候,頁面上的值也會(huì)被改變,這就是響應(yīng)式的作用。
- 使用ref獲取dom元素。
import { ref, onMounted } from 'vue'
import type { Ref } from 'vue' // Ref是一個(gè)類型定義,類型定義導(dǎo)入的時(shí)候必須使用type關(guān)鍵字
// 定義User的各個(gè)屬性的字段類型
type UserType = {
name: string
age: number
}
// 三種不同的User對象的定義
const User = ref<UserType>({ name: '小明', age: 12 })
const User1: Ref<UserType> = ref({ name: '小明', age: 12 })
const User2 = ref({ name: '小明', age: 12 })
const refTest = () => {
User.value.age = 18
User1.value.age = 18
User2.value.age = 18
}
// 使用ref獲取dom元素
const dom = ref<HTMLElement>()
onMounted(() => {
console.log(dom.value?.innerHTML) // onMounted結(jié)束之后,才能獲取到dom元素,所以需要放在onMounted中才能獲取到dom
})
<button @click="refTest" style="height: 100px; width: 100px; background: green">refTest</button>
<div>
<p>User: {{ User }}</p>
<p>User1: {{ User1 }}</p>
<p>User2: {{ User2 }}</p>
</div>
<div ref="dom">通過ref獲取dom</div>
2、isRef:用來判斷一個(gè)屬性或者對象是不是ref對象。
isRef實(shí)際上在項(xiàng)目中很少使用,然而在ref源碼中很多地方都在使用
import { ref, isRef } from 'vue'
const a = ref<number>(1)
const b = 1
console.log('a是ref對象:', isRef(a))
console.log('b是ref對象:', isRef(b))
a是ref對象: true
b是ref對象: false
3、shallowRef:和ref的作用相似,但是shallowRef只能用來做淺層響應(yīng)式
shallowRef只能用來做淺層響應(yīng)式,也就是說他只能做到修改到.value
的這一層,.value
后邊的數(shù)據(jù)他不能響應(yīng)式的修改。
- 當(dāng)我們點(diǎn)擊shallowRefTest按鈕時(shí),UserE2在頁面上的輸出是沒有任何變化的,但是如果我們在控制臺上去看UserE2對象的時(shí)候會(huì)發(fā)現(xiàn),實(shí)際上他的值已經(jīng)改變了,但是不能渲染到頁面上。
- 當(dāng)我們點(diǎn)擊shallowRefTest1按鈕時(shí),UserE2在頁面上的輸出發(fā)生了變化,這是因?yàn)閁serE1的處理是正確的,觸發(fā)了整個(gè)ref的機(jī)制,導(dǎo)致UserE2的值也被改變了,并正確的渲染到了界面上。
- 當(dāng)我們點(diǎn)擊shallowRefTest2按鈕時(shí),UserE2、UserE1在頁面上的輸出發(fā)生了變化,這是因?yàn)閁serE1的處理是正確的,shallowRef的響應(yīng)式處理只能從
.value
后邊修改。 - 當(dāng)我們點(diǎn)擊shallowRefTest3按鈕時(shí),UserE2、UserE1在頁面上的輸出發(fā)生了變化,這是因?yàn)閞ef的改變的會(huì)影響shallowRef的改變,也就是說,shallowRef和ref的處理放一起的時(shí)候會(huì)被ref影響,shallowRef也會(huì)變成深響應(yīng)式,原因是ref底層會(huì)調(diào)用triggerRef,而triggerRef會(huì)強(qiáng)制收集所有的改變,進(jìn)而導(dǎo)致shallowRef深層次的改變。
import { ref, shallowRef, triggerRef } from 'vue'
const a = ref<number>(1)
const UserE1 = shallowRef({ name: "小明", age: 12 });
const UserE2 = shallowRef({ name: "小明", age: 12 });
const shallowRefTest = () => {
UserE2.value.age = 18;
};
const shallowRefTest1 = () => {
UserE2.value.age = 18;
UserE1.value = {
name: "小明1",
age: 121,
};
};
const shallowRefTest2 = () => {
UserE2.value = 18;
UserE1.value = {
name: "小明1",
age: 121,
};
};
const shallowRefTest3 = () => {
a.value = 10;
UserE2.value = 18;
};
<button @click="shallowRefTest" style="height: 100px; width: 100px; background: green">shallowRefTest</button>
<button @click="shallowRefTest1" style="height: 100px; width: 100px; background: green">shallowRefTest1</button>
<button @click="shallowRefTest2" style="height: 100px; width: 100px; background: green">shallowRefTest2</button>
<button @click="shallowRefTest3" style="height: 100px; width: 100px; background: green">shallowRefTest3</button>
<div>
<p>UserE1: {{ UserE1 }}</p>
<p>UserE2: {{ UserE2 }}</p>
</div>
4、triggerRef:強(qiáng)制收集所有的改變,和shallowRef一起使用,將shallowRef也變成深層次相應(yīng),即得到和ref一樣的效果,但是ref和shallowRef不要一起使用,因?yàn)閞ef底層會(huì)調(diào)用triggerRef,會(huì)導(dǎo)致shallowRef的值也會(huì)被強(qiáng)制更新
- 當(dāng)我們點(diǎn)擊shallowRefTest4按鈕時(shí),如果我們不加
triggerRef(UserE2)
,UserE2在頁面上的輸出不會(huì)發(fā)生變化,如果我們加triggerRef(UserE2)
,UserE2在頁面上的輸出會(huì)發(fā)生變化,shallowRef也會(huì)變成深響應(yīng)式,原因是triggerRef會(huì)強(qiáng)制收集所有的改變,進(jìn)而導(dǎo)致shallowRef深層次的改變。
import { shallowRef, triggerRef } from 'vue'
const UserE2 = shallowRef({ name: "小明", age: 12 });
const shallowRefTest4 = () => {
UserE2.value.age = 18
triggerRef(UserE2) // 主動(dòng)調(diào)用,觸發(fā)更新操作
}
<button @click="shallowRefTest4" style="height: 100px; width: 100px; background: green">shallowRefTest4</button>
<div>
<p>UserE2: {{ UserE2 }}</p>
</div>
5、customRef:自己實(shí)現(xiàn)ref的邏輯,在實(shí)現(xiàn)的過程中可以自己增加其他額外的邏輯處理。
customRef允許我們自己實(shí)現(xiàn)ref的邏輯,并增加一些額外的處理,它的實(shí)現(xiàn)邏輯主要依賴于get和set方法。比如我們在set的時(shí)候需要從后臺獲取的,假設(shè)我們一次調(diào)用了一百次后臺,但是獲取的都是同一個(gè)值,那這樣我們可以在set方法中使用setTimeOut進(jìn)行防抖處理,避免服務(wù)器壓力過大。
import { customRef } from 'vue'
const myRefTest = MyRef<string>('myRefTest')
const myRefChange = () => {
myRefTest.value = 'myRefTest:我自己實(shí)現(xiàn)了ref'
}
function MyRef<T>(value: T) {
return customRef((track, triggeer) => {
return {
get() {
track();
return value;
},
set(newValue) {
value = newValue;
triggeer();
},
};
});
}
<button @click="myRefChange" style="height: 100px; width: 100px; background: green">myRefChange</button>
<div>
<p>myRefTest: {{ myRefTest }}</p>
</div>
6、reactive:將一個(gè)對象變成響應(yīng)式,修改值必須.屬性即可處理對應(yīng)的值
- 以下代碼定義了一個(gè)UserE3對象,并且都是使用reactive做成了響應(yīng)式,當(dāng)點(diǎn)擊按鈕改變UserE3對象的值的時(shí)候,頁面上的值也會(huì)被改變,也達(dá)到了響應(yīng)式的作用。
- reactive定義對象,因?yàn)樵趓eactive的定義中,約束了傳入的值只能為Object
import { reactive } from 'vue'
// 定義屬性約束
type UserType = {
name: string;
age: number;
};
// 定義一個(gè)reactive的對象
const UserE3 = reactive<UserType>({ name: "小明", age: 12 });
const shallowRefTest5 = () => {
UserE3.age = 18;
};
<button @click="shallowRefTest5" style="height: 100px; width: 100px; background: green">shallowRefTest5</button>
<div>
<p>UserE3: {{ UserE3 }}</p>
</div>
7、shallowReactive:也是將一個(gè)對象變成淺層響應(yīng)式,即只能處理對象的第二層屬性的值,和shallowRef一樣的特性。
import { shallowReactive } from 'vue'
const shallowReactiveE4 = shallowReactive<any>({
foot: {
bar: {
name: "bar",
},
},
});
const shallowRefTest8 = () => {
// shallowReactiveE4.foot.bar.name = 22 // 這里實(shí)際上不能修改name的值,只能處理對象的第二層屬性的值,即foot這一層
shallowReactiveE4.foot = 22; // 這里實(shí)際上能修改foot的值
};
<button
@click="shallowRefTest8"
style="height: 100px; width: 100px; background: green"
>
shallowRefTest8
</button>
<div>
<p>shallowReactiveE4: {{ shallowReactiveE4 }}</p>
</div>
8、readonly:將reactive對象變成只讀對象,該只讀對象不允許再次被賦值等操作,但是該只讀對象值依舊受原始對象值的影響。
import { reactive, readonly } from 'vue'
const readonlyUserE3 = readonly(UserE3);
const shallowRefTest7 = () => {
readonlyUserE3.age = 22; // 這里直接對readonlyUserE3操作不會(huì)改變r(jià)eadonlyUserE3對象屬性
// UserE3.age = 18 // 如果這里改變的是原始對象,readonlyUserE3也會(huì)受影響
};
<button
@click="shallowRefTest7"
style="height: 100px; width: 100px; background: green"
>
shallowRefTest7
</button>
<div>
<p>readonlyUserE3: {{ readonlyUserE3 }}</p>
</div>
9、reactive和ref的區(qū)別
- reactive只能定義Object類型的值作為響應(yīng)式,比如:Map,List等,而ref可以將任意值變成響應(yīng)式,包括對象,字符串,數(shù)字等。
- reactive在處理值的時(shí)候直接
.屬性
即可處理對應(yīng)的值,而ref需要.value
才能處理 - reactive在異步場景下不能直接賦值,否則會(huì)破壞他的proxy代理對象,從而無法變成響應(yīng)式。解決辦法為:
- 將data解構(gòu)并使用push方法進(jìn)行添加
- 定義類似于list1的對象,對象里面在放arr數(shù)組屬性,然后在使用=將data直接復(fù)制給list1對象里面的arr數(shù)組屬性,使用的時(shí)候也是list1.arr
let list = reactive<string[]>([]);
let list1 = reactive<{
arr: string[];
}>({
arr: [],
});
const shallowRefTest6 = () => {
setTimeout(() => {
const data = ["data1", "data2", "data3", "data4", "data5"];
// list = data // 直接用等號賦值會(huì)發(fā)現(xiàn),list實(shí)際上已經(jīng)有值了,并且在控制太也能看到,但是頁面沒有渲染,這就說明:=會(huì)破壞響應(yīng)式
list.push(...data); // 解決辦法1:就是將data解構(gòu)并使用push方法進(jìn)行添加
list1.arr = data // 解決辦法2:使用對象,將數(shù)組變?yōu)閷ο蟮囊粋€(gè)屬性,并直接賦值。
console.log(list);
}, 1000);
};
<button @click="shallowRefTest6" style="height: 100px; width: 100px; background: green">shallowRefTest6</button>
<div>
<ul>
<li v-for="item in list" :key="item">{{ item }}</li>
<li v-for="item in list1.arr" :key="item">list1 + {{ item }}</li>
</ul>
</div>
10、響應(yīng)式原理
Object.defineProperty和Proxy是VUE實(shí)現(xiàn)響應(yīng)式的關(guān)鍵,而VUE2的響應(yīng)式使用的是Object.defineProperty,而VUE3使用的是Proxy。
10.1 VUE2的響應(yīng)式原理
a、Object.defineProperty解讀:
Object.defineProerty是JS內(nèi)置對象Object的原生的靜態(tài)方法,主要用來在一個(gè)對象上定義或者修改一個(gè)屬性并返回該對象。defineProerty有三個(gè)參數(shù),他的源碼定義如下:
/**
* 將屬性添加到對象,或修改現(xiàn)有屬性的屬性。
*
* @param o 要操作的對象。
* @param p 要操作的對象的屬性
* @param attributes 對這個(gè)要操作的對象的這個(gè)屬性的一些描述,比如該屬性是不是可以被遍歷等。
*/
defineProperty<T>(o: T, p: PropertyKey, attributes: PropertyDescriptor & ThisType<any>): T;
// PropertyDescriptor的定義如下
interface PropertyDescriptor {
configurable?: boolean; // 是否可以被刪除屬性或者再次去修改enumerable、writable這些特性,默認(rèn)為false,即調(diào)用delete時(shí)無法刪除該屬性
enumerable?: boolean; // 該屬性是不是可以被枚舉(使用fo……in或者Object.keys去循環(huán)該對象時(shí),該這個(gè)屬性可否可見,默認(rèn)再循環(huán)時(shí)不允許讀取該屬性),默認(rèn)為false。
value?: any; // 該屬性的值,默認(rèn)為undefined,當(dāng)使用set和get方法的時(shí)候,該屬性不能被使用了,兩者沖突
writable?: boolean; // 該屬性是不是可以重新賦值。即使用=號給該屬性賦值的時(shí)候不生效,當(dāng)使用set和get方法的時(shí)候,該屬性不能被使用了,兩者沖突
get?(): any; // get方法,當(dāng)獲取該屬性的值的時(shí)候觸發(fā)這個(gè)方法。注意:不要在get中再次對屬性進(jìn)行獲取,這樣相當(dāng)于遞歸調(diào)用,會(huì)引發(fā)棧溢出錯(cuò)誤。
set?(v: any): void; // set方法,當(dāng)給這個(gè)屬性設(shè)置值的時(shí)候觸發(fā)這個(gè)方法。注意:不要在get中再次對屬性賦值,這樣相當(dāng)于遞歸調(diào)用,會(huì)引發(fā)棧溢出錯(cuò)誤。
}
簡單是使用Object.defineProerty來實(shí)現(xiàn)一個(gè)數(shù)據(jù)響應(yīng)式的案例,當(dāng)使用User.name獲取name的值的時(shí)候,get方法會(huì)被觸發(fā),當(dāng)使用User.name = nValue給name的賦值的時(shí)候,set方法會(huì)被觸發(fā)。
const User = { name: "zs", age: 19, sex: "男" };
let cache = User.name;
Object.defineProperty(User, "name", {
configurable: true,
enumerable: true,
// value: undefined, // 使用了set和get,該特性不能再使用了,沖突
// writable: true, // 使用了set和get,該特性不能再使用了,沖突
get: function getter() {
console.log("獲取name屬性的值"); // 當(dāng)使用User.name獲取name的值的時(shí)候,get方法會(huì)被觸發(fā),進(jìn)而該語句會(huì)被打印
// return User.name; // 不能再get方法執(zhí)行 User.name取值操作,該操作會(huì)再次觸發(fā)get方法,進(jìn)而形成死循環(huán),引發(fā)棧溢出錯(cuò)誤。
return cache;
},
set: function setter(nValue) {
console.log("設(shè)置name屬性的值,新值為:" + nValue + "舊值為:" + cache); // 當(dāng)使用User.name = nValue給name的賦值的時(shí)候,set方法會(huì)被觸發(fā),進(jìn)而該語句會(huì)被打印
// User.name = nValue; // 不能再set方法執(zhí)行 User.name = nValue賦值操作,該操作會(huì)再次觸發(fā)set方法,進(jìn)而形成死循環(huán),引發(fā)棧溢出錯(cuò)誤。
cache = nValue;
},
});
b、實(shí)現(xiàn)VUE2的響應(yīng)式
VUE2的響應(yīng)式使用的是Object.defineProperty,利用該特性手工實(shí)現(xiàn)VUE2的響應(yīng)式
// 模擬VUE對象,需要使用new關(guān)鍵字初始化MyVue對象的實(shí)例
class MyVue {
constructor(options) {
this._data = options.data; // 將data對象掛載到MyVue對象的實(shí)例上
this._options = options; // 將options對象掛載到MyVue對象的實(shí)例上,備用
this.initData(); // 初始化MyVue對象的實(shí)例的時(shí)候,就去做攔截的實(shí)現(xiàn)
}
// 攔截的實(shí)現(xiàn)
initData() {
let data = this._data;
let keys = Object.keys(data);
for (const index in keys) { // 循環(huán)data中的每一個(gè)屬性,準(zhǔn)備對data中的每一個(gè)屬性進(jìn)行攔截,并將data中的每一個(gè)屬性掛載MyVue對象的實(shí)例上
Object.defineProperty(this, keys[index], {
enumerable: true,
configurable: true,
get: function myGetter() {
console.log("獲取" + keys[index] + "值 :" + data[keys[index]]); // myVue.name獲取name的值的時(shí)候或者myVue.age獲取age的值的時(shí)候,模擬攔截處理,這里做打印
return data[keys[index]]; //在做返回data中該key的值,
},
set: function mySetter(nValue) {
console.log(
"設(shè)置" +
keys[index] +
"值, 新值:" +
nValue +
" 舊值:" +
data[keys[index]]
); // myVue.name = 'lisi'設(shè)置name的值的時(shí)候或者myVue.age = 28設(shè)置age的值的時(shí)候,模擬攔截處理,這里做打印
data[keys[index]] = nValue; // 將設(shè)置的新值保存到data中
document.getElementById("div").innerText = JSON.stringify(data); // 模擬VUE中響應(yīng)式,同步更新dom的值
},
});
}
// 處理data數(shù)據(jù)響應(yīng)式,
observer(data);
}
}
// 將data數(shù)據(jù)響應(yīng)式的入口,封裝成為一個(gè)類調(diào)用
class Observer {
constructor(data) {
this.worker(data);
}
worker(data) {
let keys = Object.keys(data);
// 將data上的key做深層次的響應(yīng)式處理,后邊會(huì)用到遞歸處理,試想:data中的某一個(gè)key的數(shù)據(jù)依舊是一個(gè)復(fù)雜結(jié)構(gòu)的對象
keys.forEach((key) => {
definedReactive(data, key, data[key]);
});
}
}
function observer(data) {
// 如果data是一個(gè)基本數(shù)據(jù)類型,就返回
const type = Object.prototype.toString.call(data); // 這樣獲取數(shù)據(jù)的類型相比于typeOf來說更加精確,
if (type !== "[object Object]" && type !== "[object Array]") {
return;
}
new Observer(data);
}
// data數(shù)據(jù)響應(yīng)式處理的邏輯,實(shí)際上就是將data上的key深層次使用Object.defineProperty進(jìn)行攔截處理
function definedReactive(target, key, value) {
observer(target[key]);
Object.defineProperty(target, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
console.log("獲取" + key + "值 :" + value);
return value;
},
set: function reactiveSetter(nValue) {
if (value === nValue) {
return;[[readme]]
}
console.log("設(shè)置" + key + "值, 新值:" + nValue + " 舊值:" + value);
document.getElementById("div").innerText = JSON.stringify(nValue);
value = nValue;
},
});
}
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Object.defineProperty</Object></title>
</head>
<body>
<div id="div"></div>
<button onclick="change()" style="width: 100px; height: 30px; background: green;">改變值</button>
</body>
<!-- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> -->
<script src="index.js"></script>
<script>
let myVue = new MyVue({
data: {
name: 'zs',
age: 18,
list: [1, 2, 3],
class: {
id: 001,
leave: '一年級',
dep: {
no: 001,
status: '開啟'
}
}
}
}); // 模擬new VUE創(chuàng)建MyVue的實(shí)例
document.getElementById('div').innerText = myVue.name + "----" + myVue.age;
// 這里通過設(shè)置值,模擬VUE雙向綁定的操作。界面上的值也會(huì)改變。同時(shí)保證myVue實(shí)例里面的值也會(huì)改變
function change() {
alert("改變值?");
myVue.age = 28;
myVue.name = 'lisi';
myVue.class.id = 002;
myVue.class.dep.no = 002;
}
</script>
</html>
10.2、VUE3的響應(yīng)式原理
注意:暫時(shí)沒有實(shí)現(xiàn)深層次的響應(yīng)式,也就是當(dāng)Person對象中該有對象時(shí),無法做到響應(yīng)式。
a、Proxy解讀
Proxy是JavaScript中的一個(gè)內(nèi)置對象,用于生成對象的代理對象,用于對對象的操作進(jìn)行攔截,例如:查找、刪除、增加、修改、執(zhí)行等。Proxy中接收兩個(gè)參數(shù)文章來源:http://www.zghlxwxcb.cn/news/detail-473205.html
- target: 要代理的對象。
- handler: 要對target進(jìn)行的操作,通常是target的各種操作,例如:查找、刪除、增加、修改、執(zhí)行等。
- set:增加一個(gè)屬性或者刪除一個(gè)屬性
- deleteProperty: 刪除某一個(gè)屬性
- get: 獲取一個(gè)屬性的值
const p = new Proxy(target, handler)
/**
* 生成一個(gè)對象的代理對象
*
* @param {object} Person 這是一個(gè)對象,包含了一些可選的屬性,即源數(shù)據(jù)
* @param {string} handler 這是一個(gè)handle,通常是一個(gè)對象,或者函數(shù),用于訪問目標(biāo)數(shù)據(jù)的方法
*/
const p = new Proxy(Person, {
get(target, prop) { // 訪問對象上的某一個(gè)屬性
},
set(target, prop, value) { // 修改對象上的屬性的值或者是新增一個(gè)屬性
},
deleteProperty(target, prop) { // 刪除對象上的一個(gè)屬性
}
});
b、Reflect解讀
Reflect是一個(gè)內(nèi)置對象,是不可構(gòu)造的,它方法都是靜態(tài)的,通常和Proxy一起聯(lián)合使用,使用Reflect可以增強(qiáng)代碼的可讀性,使得代碼更具編程式風(fēng)格。目前,Reflect 具有Object的部分功能,某些情況下可以替換Object。以下列舉幾個(gè)常用的方法:文章來源地址http://www.zghlxwxcb.cn/news/detail-473205.html
/**
* 獲取一個(gè)對象的屬性的值
*
* @param {object} target 這是一個(gè)對象,包含了一些可選的屬性,即源數(shù)據(jù)
* @param {string} prop 該對象中的某一個(gè)屬性的名稱
* @param {string} receiver 可選
*/
Reflect.get(target, prop, receiver); // 獲取值交給Reflect處理
/**
* 設(shè)置對象的屬性的值
*
* @param {object} target 這是一個(gè)對象,包含了一些可選的屬性,即源數(shù)據(jù)
* @param {string} prop 該對象中的某一個(gè)屬性的名稱
* @param {string} value 新值
*/
Reflect.set(target, prop, value); // 獲取值交給Reflect處理
/**
* 函數(shù)調(diào)用
*
* @param {object} target 要調(diào)用函數(shù)名
* @param {object} thisArguments this對象,可為空
* @param {object} argumentsList 參數(shù),可為空,多個(gè)參數(shù)是一個(gè)數(shù)組,無參可以傳遞任意空對象
*/
Relfect.apply(target,thisArguments,argumentsList)
c、實(shí)現(xiàn)VUE3中的響應(yīng)式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Proxy</Object></title>
</head>
<body>
<div id="div">
姓名:<h1 id="name"></h1>
年齡:<h1 id="age"></h1>
性別:<h2 id="gender"></h2>
</div>
<button onclick="change()" style="width: 100px; height: 30px; background: green;">改變值</button>
<button onclick="deletePro()" style="width: 100px; height: 30px; background: green;">刪除屬性</button>
</body>
<script>
const Person = {
name: 'Jonah',
age: 39
}
document.getElementById('name').innerHTML = Person.name
document.getElementById('age').innerHTML = Person.age
/**
* 生成一個(gè)對象的代理對象
*
* @param {object} Person 這是一個(gè)對象,包含了一些可選的屬性,即源數(shù)據(jù)
* @param {string} handler 這是一個(gè)handle,通常是一個(gè)對象,或者函數(shù),用于訪問目標(biāo)數(shù)據(jù)的方法
*/
const p = new Proxy(Person, {
get(target, prop, receiver) {
console.log('get', `獲取${target}的${prop}的值`);
return Reflect.get(target, prop, receiver); // 獲取值交給Reflect處理
},
set(target, prop, value) {
console.log('set', `修改${target}的${prop}的值或者新增一個(gè)${prop}屬性`);
document.getElementById(prop).innerHTML = value // 模擬更新dom
return Reflect.set(target, prop, value); // 修改值交給Reflect處理
},
deleteProperty(target, prop) {
console.log('deleteProperty', `刪除${target}的${prop}的${prop}屬性`);
document.getElementById(prop).style.display = 'none' // 模擬更新dom
return Reflect.deleteProperty(target, prop); // 刪除值交給Reflect處理
}
});
const change =
() => {
alert('修改age的值為')
p.age += 1;
console.log('change', p.age);
alert('添加一個(gè)gender屬性')
p.gender = '女'
}
const deletePro =
() => {
alert('刪除gender屬性')
delete p.gender
}
</script>
</html>
到了這里,關(guān)于VUE3淺析---響應(yīng)式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!