一、Hook函數(shù)
Vue3 的hook函數(shù)相當(dāng)于 vue2 的 mixin鸳址,不同點(diǎn)在于hooks是函數(shù)瘩蚪。Vue3的hook函數(shù)可以幫助我們提高代碼的復(fù)用性,能在不同的組件中都使用hook函數(shù)稿黍。
在src目錄下建立一個(gè) hooks 文件夾疹瘦,文件夾中新建一個(gè)我們要用的方法的名字.js文件(一般情況下use開頭)。
useCar.js
import { ref, computed } from 'vue'
export default function () {
let carName = ref("奔馳")
let carPrice = ref(50000)
// 修改汽車名稱
let updateCarName = (name) => {
carName.value = name
}
// 修改汽車價(jià)格
let updateCarPrice = (price) => {
carPrice.value = price
}
let usaCarPrice = computed(() => {
return '$' + (carPrice.value / (Math.random() + 6)).toFixed(2)
})
return {
carName,
carPrice,
updateCarName,
updateCarPrice,
usaCarPrice
}
}
usePlane.js
// 導(dǎo)入ref,computed
import { ref, computed } from "vue";
export default function () {
// 飛機(jī)名稱
let planeName = ref("波音747");
// 飛機(jī)價(jià)格
let planePrice = ref(20000);
// 修改飛機(jī)名稱的方法
let updatePlaneName = (name) => {
planeName.value = name;
};
// 修改飛機(jī)價(jià)格的方法
let updatePlanePrice = (price) => {
planePrice.value = price;
};
// 飛機(jī)在美國的價(jià)格
let usaPlanePrice = computed(() => {
return "$" + (planePrice.value / (Math.random() + 6)).toFixed(2);
});
return {
planeName,
planePrice,
updatePlaneName,
updatePlanePrice,
usaPlanePrice,
};
}
組件
將文件引入到要使用的組件中巡球。
<div class="child">
<div class="car">
<p>汽車名稱:{{carName}}<button @click="updateCarName('寶馬')">修改汽車名稱</button></p>
<p>汽車價(jià)格:{{'¥'+carPrice}}<button @click="updateCarPrice(10000)">修改汽車價(jià)格</button></p>
<p>美國價(jià)格:{{usaCarPrice}}</p>
</div>
<hr>
<div class="plane">
<p>汽車名稱:{{planeName}}<button @click="updatePlaneName('B2轟炸機(jī)')">修改飛機(jī)名稱</button></p>
<p>汽車價(jià)格:{{'¥'+planePrice}}<button @click="updatePlanePrice(50000)">修改飛機(jī)價(jià)格</button></p>
<p>美國價(jià)格:{{usaPlanePrice}}</p>
</div>
</div>
import {computed, ref} from 'vue'
// 導(dǎo)入hook函數(shù)useCar
import useCar from '../hooks/useCar'
// 導(dǎo)入hook函數(shù)usePlane
import usePlane from '../hooks/usePlane'
export default {
name: "Child",
setup() {
return {
...useCar(),
...usePlane()
}
}
};
二言沐、生命周期
1、Vue3 中酣栈,可以在 setup() 函數(shù)中使用生命周期险胰,定義組合式API生命周期函數(shù)。組合式API生命周期函數(shù)矿筝,會(huì)先與傳統(tǒng)的生命周期函數(shù)執(zhí)行起便。
2、與vue2相比,在vue3中對(duì)beforeDestroy和destroyed這兩個(gè)生命周期函數(shù)榆综,進(jìn)行了重命名妙痹,beforeUnmount 替換了 beforeDestroy;unmounted 替換了 destroyed鼻疮。
3细诸、setup()函數(shù),可以替代beforeCreate 和 created 這兩個(gè)生命周期函數(shù)陋守,因?yàn)関ue2中的beforeCreate和created生命周期的執(zhí)行幾乎與VUE3中的setup在同一時(shí)間執(zhí)行震贵。
<div class="child3">
{{ count }}
<button @click="updateCount">count++</button>
</div>
// 導(dǎo)入生命周期組合式api,除了beforeCreate和created這兩個(gè)生命周期函數(shù)沒有組合式api
// 其他的生命周期函數(shù)水评,都有對(duì)應(yīng)的組合式api猩系,命名方式只是在原有方法名的前面加上on
// setup()函數(shù)在這里充當(dāng)了beforeCreate和created這兩個(gè)生命周期函數(shù)的功能。
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount,onUnmounted } from "vue";
export default {
name: "Child3",
data() {
return {
show:true
}
},
setup() {
//注意:setup是在beforeCreate和created之前運(yùn)行的中燥。
//所以寇甸,在setup里面,無法調(diào)用data和methods里面的數(shù)據(jù)
console.log('setup');
let count = ref(1);
let updateCount = () => {
count.value++;
};
//掛載前疗涉。
onBeforeMount(() => {
console.log('onBeforeMount');
}),
//掛載完成拿霉。在這個(gè)里面發(fā)送異步請(qǐng)求。調(diào)用接口咱扣。
onMounted(()=>{
console.log('onMounted');
})
//修改后绽淘,頁面重新掛載前
onBeforeUpdate(()=>{
console.log('onBeforeUpdate');
})
//修改后,頁面重新掛載完成
onUpdated(()=>{
console.log('onUpdated');
})
//卸載前
onBeforeUnmount(()=>{
console.log('onBeforeUnmount');
})
//卸載完成
onUnmounted(() => {
console.log('onUnmounted');
})
return {
count,
updateCount,
};
},
/* data() {
return {
count: 1,
};
},
methods: {
updateCount() {
this.count++;
},
}, */
// 數(shù)據(jù)初始化前
/*beforeCreate() {
console.log("--beforeCreate--");
},
// 數(shù)據(jù)初始化完成
created() {
console.log("--created--");
},
// 頁面掛載前
beforeMount() {
console.log("--beforeMount--");
},
// 頁面掛載完成
mounted() {
console.log("--mounted--");
},
// 數(shù)據(jù)修改后闹伪,頁面重新掛載前
beforeUpdate() {
console.log(this.count);
console.log("--beforeUpdate--");
},
// 數(shù)據(jù)修改后沪铭,頁面重新掛載完成
updated() {
console.log(this.count);
console.log("--updated--");
},
// 卸載組件之前前
beforeUnmount() {
console.log("--beforeUnmount--");
},
// 卸載組件完成
unmounted() {
console.log("--unmounted--");
}, */
};
三、toRef和toRefs
1偏瓤、toRef()函數(shù):可以用來為一個(gè) reactive 對(duì)象里面的指定屬性創(chuàng)建一個(gè) ref杀怠,這個(gè) ref 可以被傳遞并且能夠保持響應(yīng)性。這樣做的好處是簡化了模板中的表達(dá)式厅克。toRef()函數(shù)赔退,需要傳兩個(gè)參數(shù):reactive 對(duì)象、具體的屬性名证舟。
2硕旗、toRefs()函數(shù):把一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)換成普通對(duì)象,該普通對(duì)象的每個(gè)屬性都是一個(gè) ref褪储。
<div class="child1">
<ul>
<li>姓名:{{ name }}</li>
<li>年齡:{{ age }}</li>
<li>性別:{{ sex }}</li>
<li>地址:{{ address }}</li>
<li>汽車名稱:{{ car.name }}</li>
<li>汽車價(jià)格:{{ car.price }}</li>
<li><button @click="updateStudent">修改學(xué)生信息</button></li>
</ul>
</div>
import { reactive, toRefs } from "vue";
export default {
name: "Child1",
setup() {
// 學(xué)生對(duì)象
let student = reactive({
name: "張三",
age: 20,
sex: "男",
address: "南京",
car: {
name: "寶馬",
price: 1000,
},
});
// 修改學(xué)生的方法
let updateStudent = () => {
student.name = "李四";
student.age = 22;
student.sex = "女";
student.address = "成都";
student.car.name = "奔馳";
student.car.price = 2000;
};
return {
// toRef()方法卵渴,用于將一個(gè)reactive對(duì)象里面的指定屬性以ref形式的對(duì)象返回
// name:toRef(student,'name'),
// age:toRef(student,'age'),
// sex:toRef(student,'sex'),
// address:toRef(student,'address'),
// 假如 reactive 對(duì)象中,有100個(gè)屬性鲤竹,上面的操作要寫100次浪读,所以昔榴,一般都直接用toRefs函數(shù)
// 注意:如果student里面的屬性是一個(gè)對(duì)象,這個(gè)屬性對(duì)象里面的內(nèi)容是不能直接轉(zhuǎn)為ref的
// toRefs只能保證一級(jí)屬性
...toRefs(student),
updateStudent,
};
},
};
四碘橘、其他的組合式API
1互订、readonly
readonly()方法:用于返回一份只讀數(shù)據(jù)。傳入一個(gè)對(duì)象(響應(yīng)式或普通)或 ref痘拆,返回一個(gè)原始對(duì)象的只讀代理仰禽。一個(gè)只讀的代理是“深層的”,對(duì)象內(nèi)部任何嵌套的屬性也都是只讀的纺蛆。
注意:該方法吐葵,不能將一個(gè)普通值類型數(shù)據(jù)轉(zhuǎn)為只讀數(shù)據(jù)
<div>{{ student }} <button @click="updateStudent">修改學(xué)生信息</button></div>
import { reactive, readonly } from "vue";
export default {
name: "Child2",
setup() {
let data = reactive({
name: "張三",
age: 20,
});
let student = readonly(data);
// student是一個(gè)只讀對(duì)象,無法修改數(shù)據(jù)
let updateStudent = () => {
student.name = "李四";
student.age = 22;
};
return {
student,
updateStudent,
};
},
};
2桥氏、isReadonly
檢查一個(gè)對(duì)象是否是由 readonly 創(chuàng)建的只讀代理温峭。
import { reactive, readonly, isReadonly } from "vue";
let data = reactive({
name: "張三",
age: 20,
});
let student = readonly(data);
console.log('student is readonly',isReadonly(student)); //true
3、isRef
isRef():檢查一個(gè)值是否為一個(gè) ref 對(duì)象字支。
import { ref, isRef } from "vue";
let name = ref('你好')
console.log('name is ref',isRef(name)); //true
4凤藏、isProxy
isProxy():檢查一個(gè)對(duì)象是否是由 reactive 或者 readonly 方法創(chuàng)建的代理。
import { reactive, readonly, isProxy } from "vue";
setup() {
let data = reactive({
name: "張三",
age: 20,
});
let student = readonly(data);
console.log('data is proxy',isProxy(data)); //true
console.log('student is proxy',isProxy(student)); //true
5堕伪、isReactive
isReactive():檢查一個(gè)對(duì)象是否是由 reactive 創(chuàng)建的響應(yīng)式代理揖庄。如果這個(gè)代理是由 readonly 創(chuàng)建的,但是又被 reactive 創(chuàng)建的另一個(gè)代理包裹了一層欠雌,那么同樣也會(huì)返回 true蹄梢。
import { reactive, isReactive } from "vue";
setup() {
let data = reactive({
name: "張三",
age: 20,
});
console.log('data is reactive',isReactive(data)); //true
}
6、unref
unref()函數(shù):如果參數(shù)是一個(gè) ref 則返回它的 value桨昙,否則返回參數(shù)本身检号。等同于 val = isRef(val) ? val.value : val 。
import { ref, unref } from "vue";
setup() {
let name = ref('你好')
let age = 20
console.log(unref(name)); // '你好'
console.log(unref(age)); // 20
}
7蛙酪、markRaw
markRaw():使用markRaw()方法返回出來的對(duì)象,再也不能成為響應(yīng)式對(duì)象翘盖,函數(shù)返回這個(gè)對(duì)象本身桂塞。如果被 markRaw 標(biāo)記了,即使在響應(yīng)式對(duì)象中作屬性馍驯,也依然不是響應(yīng)式的阁危。
import { reactive, markRaw } from "vue";
setup() {
// 使用markRaw()方法,返回出來的對(duì)象汰瘫,再也不能成為響應(yīng)式對(duì)象狂打。
let car = markRaw({
name:'奔馳',
price:20
})
let car2 = reactive(car)
// car2只是一個(gè)普通對(duì)象,不是響應(yīng)式對(duì)象
console.log(car2);
}
8混弥、shallowRef
shallowRef():返回的對(duì)象 value 屬性值是 object對(duì)象(普通對(duì)象)趴乡,不再具備任何響應(yīng)式了。
<div>
汽車信息:{{ car3 }}
<button @click="updateCar">修改汽車</button>
</div>
import { shallowRef } from "vue";
setup() {
let car3 = shallowRef({
name: "大眾",
type: {
typeName: "SUV",
},
});
let updateCar = () => {
// 由于value返回的是object對(duì)象,所以晾捏,這里不再具有響應(yīng)式
car3.value.name = "奔馳";
car3.value.type.typeName = "跑車";
};
return {
car3,
updateCar
};
}
9蒿涎、shallowReactive
shallowReactive():用于定義淺響應(yīng)式對(duì)象,只對(duì)第一層屬性設(shè)置響應(yīng)式惦辛。
import { shallowReactive,isReactive } from "vue";
setup() {
let luhan = shallowReactive({
name:'鹿晗',
age:30,
friend:{
name:'關(guān)曉彤',
age:20,
}
})
let updateLuhan = ()=>{
// luhan.name = '張藝興',
// luhan.age = 25
// 如果只是修改對(duì)象的深層屬性劳秋,不會(huì)觸發(fā)頁面更新
luhan.friend.name = '小美'
luhan.friend.age = 22
}
}
10、shallowReadonly
shallowReadonly:淺只讀胖齐,只有第一層屬性是只讀的玻淑。
import { shallowReadonly } from "vue";
setup() {
let luhan = shallowReactive({
name:'鹿晗',
age:30,
friend:{
name:'關(guān)曉彤',
age:20,
}
})
let luhan3 = shallowReadonly(luhan);
// luhan3.name = '小明' // 屬性只讀
luhan3.friend.name = "小美"; // 屬性可修改
}
11、toRaw
toRaw()方法:用于將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)為普通對(duì)象呀伙。
import { toRaw } from "vue";
setup() {
let luhan = shallowReactive({
name:'鹿晗',
age:30,
friend:{
name:'關(guān)曉彤',
age:20,
}
})
let luhan2 = toRaw(luhan);
console.log("luhan2", luhan2); // 普通對(duì)象
}