一役耕、父子組件傳值
父組件通過props向子組件傳值,子組件通過emit觸發(fā)自定義事件傳遞新值給父組件里逆。
props:setup函數(shù)中第一個參數(shù)props用于接收父組件傳遞進來的參數(shù)肛根。注意:props參數(shù)中,只會接收props選項中接收的參數(shù) 活鹰。
context參數(shù):setup函數(shù)中的第二個參數(shù)是一個上下文對象context哈恰。context參數(shù)里面有三個對象:attrs,emit志群,slots着绷。
- attrs:用于獲取沒有采用props選項接收的參數(shù)。
- emit:用于觸發(fā)自定義事件锌云。
- slots:返回的是插槽里面的虛擬DOM信息荠医。
虛擬DOM:就是vue實例所能識別的一個DOM信息對象。
父組件
<div class="parent">
<h2>父組件</h2>
<div>姓名:{{ name }}</div>
<div>年齡:{{ age }}</div>
<div>年齡:{{ sex }}</div>
<Son1 :name="name" :age="age" :sex="sex" @updateData="updateData">
<!-- 這里是具名插槽 -->
<template v-slot:top>
<div class="box">這里頂部</div>
<div class="box">
<button>這里頂部</button>
</div>
</template>
<!-- #是v-slot:的簡寫 -->
<template #bottom="scope">
<div class="box">這里底部
<ul>
<li>{{scope.car.name}}</li>
<li>{{scope.car.price}}</li>
</ul>
</div>
</template>
</Son1>
</div>
import {ref} from 'vue'
import Son1 from "./Son1.vue";
export default {
name: "Parent",
setup() {
let name = ref('張三')
let age = ref(20)
let sex = ref('男')
let updateData = (e)=>{
name.value = e.myName
age.value = e.myAge
sex.value = e.mySex
}
return {
name,
age,
sex,
updateData
}
},
/* data() {
return {
name:'張三',
age:20
}
},
methods: {
updateData(e){
this.name = e.myName
this.age = e.myAge
}
}, */
components: {
Son1,
},
};
子組件
<div class="son1">
<!-- 插槽宾抓,定義多個插槽時子漩,需要給插槽定義名稱:具名插槽 -->
<slot name="top"></slot>
<h2>Son1</h2>
<div>姓名:{{ myName }}</div>
<div>年齡:{{ myAge }}</div>
<div>性別:{{ mySex }}</div>
<div><button @click="updateData">修改數(shù)據</button></div>
<!-- 可以通過插槽傳遞一份數(shù)據給插槽的使用者,這樣的插槽稱為作用域插槽 -->
<slot name="bottom" :car="car"></slot>
</div>
import {ref,reactive} from 'vue';
export default {
name: "Son1",
//接收父組件的傳值
props: ["name", "age"],
// setup的第一個參數(shù)石洗,用于獲取父組件的傳值
// 注意:props選項接收了幾個參數(shù)幢泼,setup函數(shù)的第一個參數(shù)就只能獲取幾個參數(shù)。
// setup的第二個參數(shù)讲衫,是一個上下文對象缕棵;它里面一個方法是emit,用于觸發(fā)自定義事件
// props選項沒有接收的傳值涉兽,在setup里面通過上下文對象的attrs屬性接收
setup(props,{emit,attrs,slots}) {
// slots對象返回的是插槽里面的虛擬DOM信息
console.log(slots.top());
// 中轉props里面的數(shù)據招驴,因為props是只讀的
let myName = ref(props.name)
let myAge = ref(props.age)
let mySex = ref(attrs.sex)
let car = reactive({
name:'奔馳',
price:20
})
let updateData = ()=>{
myName.value = '李四'
myAge.value = 30
mySex.value = '女'
// 觸發(fā)自定義事件
emit('updateData',{myName:myName.value,myAge:myAge.value,mySex:mySex.value})
}
return {
myName,
myAge,
mySex,
updateData,
car
}
}
/* data() {
return {
myName:this.name,
myAge:this.age
}
},
methods: {
updateData(){
this.myName = '李四'
this.myAge = 30
this.$emit('updateData',{myName:this.myName,myAge:this.myAge})
}
}, */
};
二、祖孫組件傳值
祖級組件通過provide將指定的數(shù)據添加為依賴數(shù)據枷畏,讓后代組件可以直接使用别厘。孫代組件通過inject注入祖級組件中設置為依賴的數(shù)據。
祖級組件
import {ref,provide} from 'vue'
import Son from './components/Son.vue'
export default {
name: 'App',
setup() {
let name = ref('張三')
let age = ref(20)
// 通過provide()方法拥诡,定義依賴數(shù)據触趴,從此它的子組件氮发,就可以獲取這些數(shù)據了
provide('name',name)
provide('age',age)
return {
name,
age
}
},
components: {
Son
}
/* data() {
return {
name:'張三',
age:20
}
},
methods: {
// 修改數(shù)據的方法
updateData(name,age){
this.name = name
this.age = age
}
},
// 定義依賴數(shù)據
provide(){
return {
name:this.name,
age:this.age,
updateData:this.updateData
}
}, */
}
孫級組件
<div class="subSon">
<h2>SubSon</h2>
<ul>
<li>姓名:{{name}}</li>
<li>年齡:{{age}}</li>
<li>
<button @click="update">修改信息</button>
</li>
</ul>
</div>
import {inject} from 'vue'
export default {
name: "SubSon",
setup() {
// inject()方法,用于注入父級中依賴的數(shù)據
let name = inject('name')
let age = inject('age')
let update = ()=>{
name.value = '李四'
age.value = 30
}
return {
name,
age,
update
}
}
/* inject:['name','age','updateData'],
data() {
return {
myName:this.name,
myAge:this.age
}
},
methods: {
update(){
this.myName = '李四'
this.myAge = 30
this.updateData('李四',30)
}
}, */
};
三冗懦、v-model
在Vue3中爽冕,父組件中可以通過v-model指令實現(xiàn)對多個數(shù)據的雙向綁定。注意:vue3取消了sync修飾符披蕉,它將v-model指令和sync修飾符進行了合并颈畸。
子組件中,自定義事件名稱必須命名為update:屬性名没讲,就可以實現(xiàn)對父組件中指定屬性的雙向綁定眯娱。
父級組件
<div class="app">
<h2>App</h2>
<!-- 在vue3中子定義組件時,v-model可以使用多次食零,實現(xiàn)對多個數(shù)據的雙向綁定-->
<Son3 v-model:planeName="planeName" v-model:planePrice="planePrice" v-model:planeAddress="planeAddress" />
</div>
import {ref,provide} from 'vue'
import Son3 from './components/Son3.vue'
export default {
name: 'App',
setup() {
//定義飛機的相關數(shù)據
let planeName = ref('波音747')
let planePrice = ref(100)
let planeAddress = ref('美國')
return {
// 返回飛機相關信息
planeName,
planePrice,
planeAddress
}
},
components: {
Son3
}
子級組件
<div class="son3">
<h2>Son3</h2>
<ul>
<li>飛機名稱:{{ planeName }}</li>
<li>飛機價格:{{ planePrice }}</li>
<li>飛機產地:{{ planeAddress }}</li>
<li>
<button @click="updatePlaneName">修改飛機名稱</button>
</li>
<li>
<button @click="updatePlanePrice">修改飛機價格</button>
</li>
<li>
<button @click="updatePlaneAddress">修改飛機產地</button>
</li>
</ul>
</div>
export default {
name: "Son3",
//接收父組件傳遞過來的數(shù)據
props: ["planeName", "planePrice", "planeAddress"],
setup(props, { emit }) {
let updatePlaneName = () => {
// 注意:事件方法必須是update:prop困乒,如果父組件中采用的是v-model:prop
// 此時寂屏,父組件就可以實現(xiàn)對prop的雙向數(shù)據綁定贰谣。
emit("update:planeName", "長城1號");
};
let updatePlanePrice = () => {
emit("update:planePrice", 200);
};
let updatePlaneAddress = () => {
emit("update:planeAddress", "中國");
};
return {
updatePlaneName,
updatePlanePrice,
updatePlaneAddress,
};
},
};
四、異步組件
suspense內置組件:用于在渲染異步組件時迁霎,添加Loading效果吱抚。
使用 <suspense></suspense> 包裹所有異步組件相關代碼。
<suspense></suspense> 下 <template #default></template> 插槽包裹異步組件考廉。
<suspense></suspense> 下 <template #fallback></template> 插槽包裹渲染異步組件之前的內容秘豹。
注意:異步加載的組件可以用suspense,也可以不用昌粤。不用suspense組件既绕,會失去異步的作用;但是涮坐,如果組件中setup的返回值是一個Promise對象凄贩,該組件必須要用suspense。
定義組件
<div class="son4">
<h2>Son4</h2>
<ul>
<li>商品名稱:{{ goodsName }}</li>
<li>商品價格:{{ goodsPrice }}</li>
<li>
<input type="text" v-model="goodsName">
</li>
</ul>
</div>
import { ref } from "vue";
export default {
name: "Son4",
setup() {
let goodsName = ref("小米電視");
let goodsPrice = ref(2000);
//setup方法的返回值袱讹,可以是一個Promise對象
return new Promise((resolve,reject)=>{
setTimeout(() => {
resolve({
goodsName,
goodsPrice,
show
})
}, 2000);
})
// return {
// goodsName,
// goodsPrice,
// }
},
};
使用
<div class="app">
<h2>App</h2>
<!-- suspense內置組件疲扎,用于在渲染異步組件時,添加Loading效果 -->
<suspense>
<!-- default插槽里面放置異步組件 -->
<template #default>
<Son4/>
</template>
<!-- fallback插槽里面放置組件沒有加載完成時顯示的內容 -->
<template #fallback>
Loading...
</template>
</suspense>
</div>
// defineAsyncComponent組合式API捷雕,用于定義異步組件
import {defineAsyncComponent} from 'vue'
// 異步導入組件
const Son4 = defineAsyncComponent(()=>import('./components/Son4.vue'))
五椒丧、teleport組件
Vue 3.0 新增了一個內置組件 teleport ,主要是為了解決以下場景:有時組件模板的一部分邏輯上屬于該組件救巷,而從技術角度來看壶熏,最好將模板的這一部分移動到 DOM 中 Vue app 之外的其他位置。
teleport組件:瞬移浦译。通過to屬性確定里面的元素移動到哪棒假。to屬性的屬性值是指定的選擇器俄占。
例如:在下面的案例中,box盒子邏輯上屬于son4盒子淆衷,但是為了使box盒子設置的相對定位缸榄,不受其他父級元素的影響,我們將box盒子瞬移到body下祝拯。
<div class="son4">
<h2>Son4</h2>
<button @click="show=true">顯示</button>
<!-- teleport組件:瞬移甚带。通過to屬性確定里面的元素移動到哪。
to屬性的屬性值是指定的選擇器 -->
<teleport to="body">
<div v-show="show" class="box">
<ul>
<li>商品名稱:{{ goodsName }}</li>
<li>商品價格:{{ goodsPrice }}</li>
</ul>
<button @click="show=false">關閉</button>
</div>
</teleport>
</div>
.box{
width: 200px;
height: 200px;
border: 1px solid black;
padding: 10px;
background: lightblue;
/* 絕對定位 */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
使用teleport瞬移后佳头,box盒子的結構是在body下鹰贵,與#app平級。