国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

VUE3淺析---響應(yīng)式

這篇具有很好參考價(jià)值的文章主要介紹了VUE3淺析---響應(yīng)式。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

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ù)

  • 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)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • vue3自定義dialog createApp setup語法組件使用element

    vue3自定義dialog createApp setup語法組件使用element

    目錄 ?index.vue mapDialog.js

    2024年02月14日
    瀏覽(21)
  • Vue3通透教程【六】setup語法糖、computed函數(shù)、watch函數(shù)

    專欄介紹: 涼哥作為 Vue 的忠實(shí) 粉絲輸出過大量的 Vue 文章,應(yīng)粉絲要求開始更新 Vue3 的相關(guān)技術(shù)文章,Vue 框架目前的地位大家應(yīng)該都曉得,所謂三大框架使用人數(shù)最多,公司選型最多的框架,涼哥之前在文章中也提到過就是 Vue 框架之所以火起來的原因,和 Vue 框架相比其

    2024年01月20日
    瀏覽(23)
  • 最新 Vue3、TypeScript、組合式API、setup語法糖 學(xué)習(xí)筆記

    最新 Vue3、TypeScript、組合式API、setup語法糖 學(xué)習(xí)筆記

    備注:目前 vue-cli 已處于維護(hù)模式,官方推薦基于 Vite 創(chuàng)建項(xiàng)目。 vite 是新一代前端構(gòu)建工具,官網(wǎng)地址:https://vitejs.cn vite 的優(yōu)勢如下: 輕量快速的熱重載(HMR),能實(shí)現(xiàn)極速的服務(wù)啟動(dòng)。 對 TypeScript 、 JSX 、 CSS 等支持開箱即用。 真正的按需編譯,不再等待整個(gè)應(yīng)用編譯

    2024年02月20日
    瀏覽(34)
  • 【Vue技巧】vue3中不支持.sync語法糖的解決方案

    海鯨AI-ChatGPT4.0國內(nèi)站點(diǎn),支持設(shè)計(jì)稿轉(zhuǎn)代碼:https://www.atalk-ai.com 在 Vue 3 中, .sync 修飾符已經(jīng)被移除。在 Vue 2 中, .sync 修飾符是一個(gè)語法糖,用于簡化子組件和父組件之間的雙向數(shù)據(jù)綁定。在 Vue 3 中,推薦使用 v-model 或是自定義事件來實(shí)現(xiàn)類似的功能。 以下是如何在 Vue

    2024年01月20日
    瀏覽(25)
  • vue3 script setup 語法糖用了才知道有多爽 (一)

    vue3 script setup 語法糖用了才知道有多爽 (一)

    這里是完整的目錄圖片,由于整篇文章篇幅太長,拆分成了幾篇來展示 vue3 使用的越來越廣泛, 公司項(xiàng)目開始使用 vue3 ,在 vue 3.2 之后新加入了 script setup 語法糖,上手開始看項(xiàng)目發(fā)現(xiàn)對于語法糖的使用有一些迷惑,特此整理,在整理這些內(nèi)容的同時(shí)查閱了大量的資料,自己在這個(gè)過程

    2024年02月16日
    瀏覽(20)
  • vue3的setup 語法糖中獲取slot 插槽的dom對象

    最近使用vue3開發(fā)項(xiàng)目,需要封裝一個(gè)無限滾動(dòng)的組件,使用scroll組件內(nèi)置插槽接受模板的方式,所以需要在scroll組件內(nèi)獲取到模板渲染后dom元素的寬高。 但是setup語法糖是組件生命周期的beforeCreate和created中,而且經(jīng)過測試,在mounted函數(shù)中的el屬性也是null,所以得出結(jié)論模板

    2024年02月15日
    瀏覽(26)
  • vue3 setup語法糖 使用組件內(nèi)的路由守衛(wèi)beforeRouteEnter使用方法

    由于beforeRouteEnter在setup語法糖中是無法使用的,所以需要再起一個(gè)script標(biāo)簽 使用defineComponent方式來使用就可以了

    2024年02月11日
    瀏覽(24)
  • Vue3 setup語法糖銷毀一個(gè)或多個(gè)定時(shí)器(setTimeout或setInterval)

    如果在頁面/組件增加了定時(shí)器,就算跳轉(zhuǎn)到其他頁面,定時(shí)器也不會(huì)被清理,這時(shí)候就需要手動(dòng)清理,不然會(huì)有意想不到的bug,也會(huì)影響性能。 setTimeout是只執(zhí)行一次,setInterval是循環(huán)執(zhí)行,以下是用setTimeout舉例子,如果想要用setInterval,替換一次方法就行。 setTimeout替換成

    2024年02月13日
    瀏覽(47)
  • 在uniapp vue3 setup語法糖中調(diào)用onLoad、onShow等生命周期

    在uniapp vue3 setup語法糖中調(diào)用onLoad、onShow等生命周期

    從 @dcloudio/uni-app 導(dǎo)出 可導(dǎo)出項(xiàng):

    2024年02月16日
    瀏覽(30)
  • vue3 - 使用reactive定義響應(yīng)式數(shù)據(jù)進(jìn)行列表賦值時(shí),視圖沒有更新的解決方案

    vue3 - 使用reactive定義響應(yīng)式數(shù)據(jù)進(jìn)行列表賦值時(shí),視圖沒有更新的解決方案

    在Vue 3.0 中我們使用 reactive() 定義的響應(yīng)式數(shù)據(jù)的時(shí)候,當(dāng)是一個(gè)數(shù)組或?qū)ο髸r(shí),我們直接進(jìn)行賦值,發(fā)現(xiàn)數(shù)據(jù)已經(jīng)修改成功,但是頁?并沒有自動(dòng)渲染成最新的數(shù)據(jù);這是為什么呢? 就如同官網(wǎng)所說的reactive存在一些 局限性 :(官方的描述) 原因就是reactive函數(shù)會(huì)返回一個(gè)

    2024年02月13日
    瀏覽(34)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包