动态组件的基本使用
根据一个属性currentTab来决定当前显示的组件,可以使用template的v-if来完成:
<template v-if="currentTab==='home'">
<div>
<home/>
</div>
</template>
<template v-else-if="currentTab==='about'">
<div>
<about/>
</div>
</template>
<template v-else>
<div>
<category/>
</div>
</template>也可以使用动态组件完成。动态组件是component标签,有一个属性is,用于决定当前动态显示的组件:
<component :is="currentTab"></component>is属性后面的内容必须是:is属性需要的内容:component函数全局注册的组件;或当前app的components局部注册的组件。
动态组件的传递参数
动态组件的传递参数和普通组件类似,同样是在组件内部定义props表明需要使用的参数,定义emits表明需要触发的事件;在动态组件中用同样的方式传入参数与回调的方法。
// Home.vue
<template>
<div @click="divClick">
Home 组件 {{name}} - {{age}}
</div>
</template>
<script>
export default {
props:{
name:{
type:String,
default:""
},
age:{
type:Number,
default:0
}
},
emits:["pageClick"],
methods: {
divClick(){
this.$emit("pageClick");
}
},
}
</script>// App.vue
<component :is="currentTab"
name="sk"
:age="18"
@pageClick="pageClick"></component>keep-alive
在动态组件中切换组件时会将之前的组件销毁,切换回来时组件会被重新创建,因此该组件的状态和数据就会丢失。
在组件外嵌套一个keep-alive标签可以防止组件被摧毁:
<keep-alive>
<component :is="currentTab"
name="sk"
:age="18"
@pageClick="pageClick"></component>
</keep-alive>keep-alive有三个属性可以用:include是指哪些组件需要被keep alive,exclude是指不需要的组件,max指明缓存组件的最大数量,替换策略是LRU。
以include为例:
<keep-alive include="home,about">
<component :is="currentTab"
name="sk"
:age="18"
@pageClick="pageClick"></component>
</keep-alive>include后面可以跟组件名,该组件名必须得在组件中用name属性声明:
// Home.vue
<script>
export default {
name: "home",
}
</script>也可以用v-bind:+正则表达式或数组。
异步组件
webpack的分包方式:在引用一个自己写的文件时,使用import函数而非直接使用import关键字,可以使得webpack打包时将引用的文件单独打包为一个文件:
// 通过import函数导入的模块,后续webpack对其打包时会进行分包的操作
import("./12_异步组件的使用/utils/math").then((res)=>{
console.log(res.sum(20,13));
})定义异步组件:
使用vue3中的defineAsyncComponent方法,
import {defineAsyncComponent} from "vue";该方法的返回值是一个组件,使用方式有两种,一种是传入一个工厂方法:
// 传入工厂函数
// const AsyncCategory = defineAsyncComponent(()=>import("./AsyncCategory.vue"));;
还有一种是传入一个对象,在对象中可以定义其它的属性:
const AsyncCategory = defineAsyncComponent({
loader: ()=>import("./AsyncCategory.vue"),
// 加载之前的占位组件
loadingComponent: Loading,
// 加载错误的组件
// errorComponent:
// 延迟显示:在显示loadingComponent组件之前,等待多长时间
delay: 2000,
/**
* err:错误信息
* retry:函数,调用retry尝试重新加载
* attempts:记录尝试次数
*/
onError: function(err,retry,attempts){
}
})suspense和异步组件结合使用
使用suspense标签,并在其中的template中指定default和fallback,这样也能达到在default中的元素加载失败后去加载fallback中元素的效果。
<template>
<div>
<suspense>
<template #default>
<async-category></async-category>
</template>
<template #fallback>
<loading></loading>
</template>
</suspense>
</div>
</template>
<script>
import {defineAsyncComponent} from "vue";
import Loading from "./Loading.vue";eAsyncComponent(()=>import("./AsyncCategory.vue"));
export default {
components:{
AsyncCategory,
Loading
}
}
</script>$refs
对元素或者组件添加refs属性,可以获取其实例
获取元素时直接获取到的是该元素的实例,并可以使用其Dom方法。
<template>
<div>
<!-- 绑定到一个元素上 -->
<h2 ref="title">哈哈哈</h2>
<button @click="btnClick">获取元素</button>
<!-- 绑定到一个组件实例上 -->
<nav-bar ref="navBar"></nav-bar>
</div>
</template>
<script>
import NavBar from "./Nav.vue";
export default {
components:{
NavBar
},
methods: {
btnClick(){
console.log(this.$refs.title);
console.log(this.$refs.navBar.message);
this.$refs.navBar.sayHello();
}
},
}
</script>获取组件时,得到的是一个代理,通过代理可以获取其定义的data、methods等属性
<template>
<div>
<h2>NavBar</h2>
</div>
</template>
<script>
export default {
data() {
return {
message:"我是nav中的message"
}
},
methods: {
sayHello(){
console.log("hello navBar");
}
},
}
</script>$parent和$root
在子组件中可以通过$parent和$root来获取父组件和根组件。
getParentAndRoot(){
console.log(this.$parent);
console.log(this.$root);
}生命周期
在某一个生命周期的阶段时回调一个方法:
// App.vue
<template>
<div>
<button @click="isShow=!isShow">切换</button>
<template v-if="isShow">
<home></home>
</template>
</div>
</template>
<script>
import Home from "./Home.vue";
export default {
data() {
return {
isShow:true
}
},
components:{
Home
}
}
</script>// Home.vue
<template>
<div>
<h2 ref="title">{{message}}</h2>
<button @click="changeMessage">修改message</button>
</div>
</template>
<script>
export default {
data() {
return {
message:"hello home"
}
},
methods: {
changeMessage(){
this.message="hello change"
}
},
beforeCreate() {
console.log("beforeCreate");
},
created() {
console.log("created");
},
beforeMount() {
console.log("beforeMount");
},
mounted() {
console.log("mounted");
},
beforeUnmount() {
console.log("beforeUnmount");
},
unmounted() {
console.log("unmounted");
},
beforeUpdate() {
console.log(this.$refs.title.innerHTML);
console.log("beforeUpdate");
},
updated() {
console.log(this.$refs.title.innerHTML);
console.log("updated");
},
}
</script>对于keep-alive的缓存组件,可以使用activated和deactivated来回调激活与取消的状态:
<script>
export default {
name:"about",
data() {
return {
counter:0
}
},
created() {
console.log("about created");
},
unmounted() {
console.log("about unmounted");
},
activated() {
console.log("about activated");
},
deactivated() {
console.log("about deactivated");
},
}
</script>
组件的v-model
基本使用:一个组件的v-model实际上是添加了两个属性:modelValue和@update:model-value:
<my-input :modelValue="message" @update:model-value="message=$event"></my-input>在组件中就需要有对应的props和emits:
<template>
<div>
<input type="text" :value="modelValue" @input="btnClick">
</div>
</template>
<script>
export default {
props:{
modelValue: String
},
emits:["update:modelValue"],
methods: {
btnClick(event){
this.$emit("update:modelValue",event.target.value);
}
},
}
</script>也可以通过计算属性来实现:
<template>
<div>
<input type="text" v-model="value">
</div>
</template>
<script>
export default {
props:{
modelValue: String
},
emits:["update:modelValue"],
computed:{
value:{
set(value){
this.$emit("update:modelValue",value);
},
get(){
return this.modelValue;
}
}
},
},
}
</script>绑定多个属性:可以在v-model后面用:增加新的属性,对应的在组件中也会有props和emits,以v-model:title为例:
<my-input-2 v-model="message" v-model:title="title"></my-input-2>props中需要的名称就是title,emits中需要的事件叫@update:title:
<template>
<div>
<input type="text" v-model="value">
<input type="text" v-model="titlec">
</div>
</template>
<script>
export default {
props:{
modelValue: String,
title:String
},
emits:["update:modelValue","update:title"],
computed:{
value:{
set(value){
this.$emit("update:modelValue",value);
},
get(){
return this.modelValue;
}
},
titlec:{
set(value){
this.$emit("update:title",value);
},
get(){
return this.title;
}
}
},
}
</script>