1.Hook函數(shù)
hooks是一種開發(fā)思想悠咱,我們可以利用hooks把相關(guān)代碼剝離出去蒸辆。hook有個(gè)編碼習(xí)慣是用use開頭征炼。
// 導(dǎo)入ref,computed
import {ref,computed} from 'vue'
let carName = ref("奔馳");
let carPrice = ref(5000);
// 修改汽車名稱的方法
let updateCarName = (name) => {
carName.value = name;
};
// 修改汽車價(jià)格的方法
let updateCarPrice = (price) => {
carPrice.value = price;
};
// 汽車的美國(guó)價(jià)格
let usaCarPrice = computed(() => {
return '$'+(carPrice.value / (Math.random() + 6)).toFixed(2);
});
return {
carName,
carPrice,
updateCarName,
updateCarPrice,
usaCarPrice
}
同理酸些,再搞一份飛機(jī)的hook函數(shù),hooks文件下usePlane.js
// 導(dǎo)入ref,computed
import {ref,computed} from 'vue'
export default function(){
let planeName = ref('波音747')
let planePrice = ref(20000)
let updatePlaneName = (name) => {
planeName.value = name;
};
let updatePlanePrice = (price) => {
planePrice.value = price;
};
// 飛機(jī)的美國(guó)價(jià)格
let usaPlanePrice = computed(() => {
return '$'+ (planePrice.value / (Math.random() + 6)).toFixed(2);
});
return {
planeName,
planePrice,
updatePlaneName,
updatePlanePrice,
usaPlanePrice
}
}
components下Child.vue組件:
在組件里導(dǎo)入所需的hook函數(shù)useCar檐蚜,
import useCar from'../hooks/useCar'
魄懂,然后在setup(){ } 里 return{ } 里 ...useCar()
(三個(gè)點(diǎn)是展開運(yùn)算符)
<div class="child">
<div class="car">
<p>汽車名稱:{{ carName }}<button @click="updateCarName('寶馬')">修改汽車名稱</button></p>
<p>汽車價(jià)格:{{ '¥'+carPrice }}<button @click="updateCarPrice(10000)">修改汽車價(jià)格</button></p>
<p>美國(guó)價(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>美國(guó)價(jià)格:{{usaPlanePrice}}</p>
</div>
</div>
<script>
import { computed, ref } from "vue";
// 導(dǎo)入hook函數(shù)useCar
import useCar from'../hooks/useCar'
// 導(dǎo)入hook函數(shù)userPlane
import usePlane from'../hooks/usePlane'
export default {
name: "Child",
setup() {
return {
...useCar(),
...usePlane()
};
},
};
</script>
頁面效果:hooks下每個(gè)xx.js文件就是一個(gè)業(yè)務(wù),這里面的業(yè)務(wù)可以在多個(gè)xx.vue組件中使用闯第。分別在組件中導(dǎo)入所需的hook函數(shù)useCar市栗,然后在setup(){ } 里 return{ } 里 ...useCar()
,就可以惹咳短。
2.生命周期
vue3是上來就掛載填帽。vue2是先走一半再掛載。
App.vue組件:
<template>
<div class="app">
<div>
{{count}}
<button @click="updateCount">count++</button>
</div>
<Child></Child>
<Child2></Child2>
</div>
</template>
<script>
import Child from './components/Child.vue'
import Child2 from './components/Child2.vue'
export default {
name: 'App',
components:{
Child,
Child2
},
data() {
return {
count:1
}
},
methods: {
updateCount(){
this.count++
}
},
beforeCreate() {
// console.log(this.count);
console.log('--beforeCreate--');
},
created() {
// console.log(this.count);
console.log('--created--');
},
beforeMount() {
console.log('--beforeMount--');
},
mounted() {
console.log('--mounted--');
},
beforeUpdate() {
console.log(this.count);
// debugger;
console.log('--beforeUpdate--');
},
updated() {
console.log(this.count);
// debugger
console.log('--updated--');
},
}
</script>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
.app{
border: 1px solid #ccc;
margin: 10px;
padding: 10px;
}
</style>
后臺(tái)打印效果:
點(diǎn)擊count++之后:
beforeUpdate和updated會(huì)在什么場(chǎng)景下使用咙好?
顧sensei答盲赊,這會(huì)是一個(gè)補(bǔ)救措施,或是修改后的跟蹤措施敷扫;或有點(diǎn)像監(jiān)視器哀蘑,能夠監(jiān)測(cè)到頁面是否在更新,watch是針對(duì)某一個(gè)變量去監(jiān)視葵第,但它是監(jiān)測(cè)到整個(gè)頁面绘迁。
在vue3中,beforeDestroy和destroyed這兩個(gè)生命周期函數(shù)卒密,進(jìn)行了重命名缀台,替換成了 beforeUnmount 和 unmounted 。
在vue3中哮奇,除了beforeCreate和created這兩個(gè)生命周期函數(shù)沒有組合式api膛腐,其他的生命周期函數(shù)都有對(duì)應(yīng)的組合式api,命名方式只是在原有方法名的前面加上on鼎俘。
setup()函數(shù)在這里充當(dāng)了beforeCreate和created這兩個(gè)生命周期函數(shù)的功能哲身。
注意:setup是在beforeCreate和created之前運(yùn)行的。所以贸伐,在setup里面勘天,無法調(diào)用data和methods里面的數(shù)據(jù)。
Child3.vue組件:
<template>
<div class="child3">
{{ count }}
<button @click="updateCount">count++</button>
</div>
</template>
<script>
// 導(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",
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");
})
// 掛載完成
onMounted(() => {
console.log("onMounted");
})
// 修改后,頁面重新掛載前
onBeforeUpdate(() => {
console.log("onBeforeUpdate");
})
// 修改后赚导,頁面重新掛載完成
onUpdated(() => {
console.log("onUpdated");
})
// 卸載前
onBeforeUnmount(() => {
console.log("onBeforeUnmount");
})
// 卸載完成
onUnmounted(() => {
console.log("onUnmounted");
})
return {
count,
updateCount,
};
}
};
</script>
<style scoped>
.child3 {
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
}
</style>
App.vue組件:
<template>
<div class="app">
<button @click="unMount">卸載Child3組件</button>
<Child3 v-if="isShow"></Child3>
</div>
</template>
<script>
import Child3 from './components/Child3.vue'
export default {
name: 'App',
components:{
Child3
},
data() {
return {
isShow:true
}
},
methods: {
unMount(){
this.isShow=false
}
},
}
</script>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
.app{
border: 1px solid #ccc;
margin: 10px;
padding: 10px;
}
</style>
3.toRef 和 toRefs
toRef() 方法茬缩,用于將一個(gè)響應(yīng)式對(duì)象里面的指定屬性以ref形式的對(duì)象返回,這樣寫的好處是吼旧,可以簡(jiǎn)化模板里面的語法凰锡。
toRefs() 方法,用于將一個(gè)reactive對(duì)象返回一個(gè)新對(duì)象圈暗,該對(duì)象里面的所有屬性都是一個(gè)ref對(duì)象掂为。
<template>
<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>
</template>
<script>
import {ref,reactive, toRef,toRefs} from 'vue'
export default {
name: "Child1",
setup() {
let student = reactive({
name:'張三',
age:20,
sex:'男',
address:'南京',
car:{
name:'邁巴赫',
price:200
}
})
// 修改學(xué)生的方法
let updateStudent =()=>{
student.name = '李四'
student.age = 22
student.sex = '女'
student.address = '杭州',
student.car.name = '布加迪威龍',
student.car.price = 100
}
return{
// toRef()方法,用于將一個(gè)響應(yīng)式對(duì)象里面的指定屬性以ref形式的對(duì)象返回员串,
// 這樣寫的好處是勇哗,可以簡(jiǎn)化模板里面的語法。
// name:toRef(student,'name'),
// age:toRef(student,'age'),
// sex:toRef(student,'sex'),
// address:toRef(student,'address'),
// toRefs()方法寸齐,用于將一個(gè)reactive對(duì)象返回一個(gè)新對(duì)象欲诺,
// 該對(duì)象里面的所有屬性都是一個(gè)ref對(duì)象。
...toRefs(student),
updateStudent
}
}
};
</script>
4.其他的組合式API
readonly() 方法渺鹦,用于返回一份只讀數(shù)據(jù)扰法。注意:該方法,不能將一個(gè)普通值類型數(shù)據(jù)轉(zhuǎn)為只讀數(shù)據(jù)毅厚。
markRaw() 方法塞颁,返回出來的對(duì)象,再也不能成為響應(yīng)式對(duì)象吸耿。應(yīng)該用的也不多奧祠锣。
unref() 方法,用于判斷對(duì)象如果是ref咽安,就返回ref的value值伴网;如果不是ref,直接返回值板乙。
shallowReactive() / shallowRef() 方法是偷,用于定義淺響應(yīng)式對(duì)象拳氢。只對(duì)第一層屬性設(shè)置響應(yīng)式募逞。
shallowReadonly() 是淺只讀蛋铆,只有第一層屬性是只讀的。
toRaw() 方法放接,用于將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)為普通對(duì)象刺啦。
<template>
<div class="child2">
<div>{{ student }}</div>
<button @click="updateStudent">修改學(xué)生</button>
<hr>
<div>{{luhan}}</div>
<button @click="updateLuhan">修改鹿晗</button>
</div>
</template>
<script>
import { unref,isProxy,isRef,isReactive, isReadonly, markRaw,
onMounted,ref,reactive, readonly, shallowReactive, toRaw } from "vue";
export default {
name: "Child2",
setup() {
let name =ref('你好')
let age=20
let data = reactive({
name: "張三",
age: 20,
});
// readonly()方法,用于返回一份只讀數(shù)據(jù)
// 注意:該方法纠脾,不能將一個(gè)普通值類型數(shù)據(jù)轉(zhuǎn)為只讀數(shù)據(jù)
let student = readonly(data);
let updateStudent = () => {
// student.name += "!";
data.name +="!"
// 此處玛瘸,student是返回出去的數(shù)據(jù),改不了苟蹈,data是原數(shù)據(jù)所以改得了糊渊。
// student本質(zhì)上是個(gè)代理對(duì)象proxy,但不能改奧慧脱,一改就報(bào)錯(cuò)渺绒,使用場(chǎng)景并不多。
};
// 使用markRaw()方法菱鸥,返回出來的對(duì)象宗兼,再也不能成為響應(yīng)式對(duì)象。應(yīng)該用的也不多奧氮采。
let car = markRaw({
name: "奔馳",
price: 20,
});
// console.log(car);
let car2 = reactive(car);
console.log(car2);
// shallowReactive() shallowRef() 用于定義淺響應(yīng)式對(duì)象殷绍。
// 只對(duì)第一層屬性設(shè)置響應(yīng)式。
// shallowReadonly()是淺只讀鹊漠,只有第一層屬性是只讀的主到。
let luhan = shallowReactive({
name: "鹿晗",
age: 30,
friend: {
name: '關(guān)曉彤',
age: 20
},
});
console.log('luhan',luhan); //luhan是個(gè)響應(yīng)式對(duì)象Proxy
// toRaw()方法,用于將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)為普通對(duì)象躯概。
let luhan2 = toRaw(luhan)
console.log('luhan2',luhan2);
let updateLuhan = () => {
// luhan.name = "張藝興",
// luhan.age = 25
// 如果只是修改對(duì)象的深層屬性登钥,不會(huì)觸發(fā)頁面更新。
luhan.friend.name='小美'
luhan.friend.age=22
};
onMounted(() => {
console.log('name is ref',isRef(name));
console.log('data is reactive',isReactive(data));
console.log('data is proxy',isProxy(data));
console.log('student is readonly',isReadonly(student));
console.log('student is proxy',isProxy(student));
// unref()方法楞陷,用于判斷對(duì)象如果是ref怔鳖,就返回ref的value值;如果不是ref固蛾,直接返回值结执。
// 等同于: val = isRef(val) ? val.value : val
console.log(unref(name));
console.log(unref(age));
})
return {
student,
updateStudent,
luhan,
updateLuhan
};
},
};
</script>