# 一.动态组件
# 1.什么是动态组件
动态组件指的是动态切换组件的显示与隐藏。
# 2.如何实现动态组件
在 Vue 中,<component>
是一个特殊的组件,它用于渲染动态组件。动态组件是指在运行时根据数据或条件动态地选择要渲染的组件。
<component>
组件可以通过is
属性来指定要渲染的组件。这个属性的值可以是一个组件的名称,也可以是一个组件对象。当is
的值发生变化时,<component>
会销毁当前渲染的组件实例,并创建和渲染新的组件实例。
以下是一个使用<component>
动态组件的示例:
<template>
<div>
<button @click="changeComponent('ComponentA')">组件A</button>
<button @click="changeComponent('ComponentB')">组件B</button>
<component :is="currentComponent"></component>
</div>
</template>
<script>
import ComponentA from "./ComponentA.vue";
import ComponentB from "./ComponentB.vue";
export default {
data() {
return {
currentComponent: null,
};
},
methods: {
changeComponent(componentName) {
if (componentName === "ComponentA") {
this.currentComponent = ComponentA;
} else if (componentName === "ComponentB") {
this.currentComponent = ComponentB;
}
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
在上面的示例中,当点击"组件 A"按钮时,currentComponent
会被设置为ComponentA
组件;当点击"组件 B"按钮时,currentComponent
会被设置为ComponentB
组件。<component>
会根据currentComponent
的值动态渲染相应的组件。
需要注意的是,被动态渲染的组件必须在父组件的作用域内注册或导入。在示例中,ComponentA
和ComponentB
被导入并通过按钮点击事件来切换。
# 3.keep-alive
默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 <keep-alive>
组件保持动态组
件的状态。示例代码如下:
<template>
<div>
<button @click="changeComponent('ComponentA')">组件A</button>
<button @click="changeComponent('ComponentB')">组件B</button>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
<script>
import ComponentA from "./ComponentA.vue";
import ComponentB from "./ComponentB.vue";
export default {
data() {
return {
currentComponent: null,
};
},
methods: {
changeComponent(componentName) {
if (componentName === "ComponentA") {
this.currentComponent = ComponentA;
} else if (componentName === "ComponentB") {
this.currentComponent = ComponentB;
}
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 4.keep-alive 对应的生命周期函数
当组件被缓存时,会自动触发组件的 deactivated 生命周期函数。
当组件被激活时,会自动触发组件的 activated 生命周期函数。
activated
:当组件被激活(从缓存中取出并重新渲染)时,会调用activated
钩子函数。你可以在这个钩子函数中执行一些特定于组件激活时需要的操作。deactivated
:当组件被离开(被缓存)时,会调用deactivated
钩子函数。你可以在这个钩子函数中执行一些特定于组件离开时需要的操作。
需要注意的是,被缓存的组件不会被销毁和重新创建,而是被保留在内存中。因此,如果你希望在组件每次激活时都执行某些操作,可以使用 activated
钩子函数;如果你希望在组件离开时执行某些操作,可以使用 deactivated
钩子函数。
export default {
created(){console.log('组件被创建了')},
destroyed(){console.log('组件被销毁了')},
activated(){console.log('Left 组件被激活了!')},
deactivated(){console.log('Left组件被缓存了!')}
}
2
3
4
5
6
# 5.include 属性
在 Vue 的 <keep-alive>
组件中,你可以使用 include
和 exclude
属性来进一步控制哪些组件应该被缓存或排除在缓存之外。
include
属性用于指定要缓存的组件名称或组件名称的数组。只有在include
中列出的组件才会被缓存。exclude
属性用于指定不应被缓存的组件名称或组件名称的数组。列出的组件将被排除在缓存之外。
<template>
<div>
<button @click="toggleCache">切换缓存</button>
<keep-alive :include="includeComponents" :exclude="excludeComponents">
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
<script>
import ComponentA from "./ComponentA.vue";
import ComponentB from "./ComponentB.vue";
import ComponentC from "./ComponentC.vue";
export default {
data() {
return {
currentComponent: ComponentA,
includeComponents: ["ComponentA", "ComponentB"],
excludeComponents: ["ComponentC"],
useCache: true,
};
},
methods: {
toggleCache() {
this.useCache = !this.useCache;
this.currentComponent = this.useCache ? ComponentA : ComponentC;
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
在上述示例中,includeComponents
数组中包含了要缓存的组件名称,即 'ComponentA'
和 'ComponentB'
。而 excludeComponents
数组中包含了要排除在缓存之外的组件名称,即 'ComponentC'
。
初始状态下,currentComponent
被设置为 ComponentA
,因此 ComponentA
会被缓存,而 ComponentB
和 ComponentC
则不会被缓存。
点击 "切换缓存" 按钮会在 ComponentA
和 ComponentC
之间切换。当 useCache
为 true
时,currentComponent
被设置为 ComponentA
,从而将 ComponentA
缓存起来。当 useCache
为 false
时,currentComponent
被设置为 ComponentC
,从而将 ComponentA
从缓存中移除,并不会缓存 ComponentC
。
通过使用 include
和 exclude
属性,你可以灵活地控制缓存的组件,并排除不需要缓存的组件,以满足你的具体需求。
# 二.插槽
# 1.什么是插槽
插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的
部分定义为插槽。
可以把插槽认为是组件封装期间,为用户预留的内容的占位符。
# 2.体验插槽的基础用法
在 Vue 中,<slot>
元素是用于插入组件内容的插槽。它允许在组件的模板中定义一个或多个占位符,以便在组件的使用者提供内容。
以下是一个示例,展示了如何使用 <slot>
:
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<slot></slot>
</div>
</template>
2
3
4
5
6
7
在上述示例中,<slot>
标签被放置在父组件的模板中。这表示在组件使用的地方,任何内容都可以被插入到这个插槽中。
<!-- App.vue -->
<template>
<div>
<ParentComponent>
<h2>子组件插入的内容</h2>
<p>更多子组件内容</p>
</ParentComponent>
</div>
</template>
<script>
import ParentComponent from "./ParentComponent.vue";
export default {
components: {
ParentComponent,
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在上述示例中,我们在 <ParentComponent>
标签中插入了一些内容,包括一个 <h2>
元素和一个 <p>
元素。这些内容将被插入到 <slot>
标签所在的位置。
当渲染父组件时,插入的内容将替换 <slot>
元素。在这个例子中,最终渲染的结果将包含父组件中的 <h1>
标题和子组件中插入的内容。
你还可以在 <slot>
标签中定义默认内容,以便在没有提供插入内容时显示。例如:
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<slot> 默认内容 </slot>
</div>
</template>
2
3
4
5
6
7
在这种情况下,如果在 <ParentComponent>
标签中没有提供插入的内容,那么默认内容 "默认内容" 将被渲染。
使用 <slot>
元素允许你以灵活的方式定义组件的结构,并允许使用者在使用组件时提供自定义的内容。这对于构建可重用的组件非常有用。
# 3.后备内容
封装组件时,可以为预留的 <slot>
插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何
内容,则后备内容会生效。示例代码如下:
<template>
<p>这是MyCom1组件的第1个p标签</p>
<slot>这是后备内容</slot>
<p>这是MyCom1组件最后一个 p标签</p>
</template>
2
3
4
5
# 4.具名插槽
如果在封装组件时需要预留多个插槽节点,则需要为每个<slot>
插槽指定具体的 name 名称。这种带有具体
名称的插槽叫做“具名插槽”。示例代码如下:
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<slot name="header"></slot>
<div>
<slot></slot>
</div>
<slot name="footer"></slot>
</div>
</template>
2
3
4
5
6
7
8
9
10
11
注意:没有指定 name 名称的插槽,会有隐含的名称叫做 “default”。
<!-- App.vue -->
<template>
<div>
<parent-component>
<template v-slot:header>
<h2>头部插槽的内容</h2>
</template>
<p>默认插槽的内容</p>
<template v-slot:footer>
<footer>底部插槽的内容</footer>
</template>
</parent-component>
</div>
</template>
<script>
import ParentComponent from "./ParentComponent.vue";
export default {
components: {
ParentComponent,
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在上述示例中,我们使用 v-slot
指令来为具名插槽指定内容。v-slot
后面的参数指定了要插入的具名插槽的名称。
在这个例子中,我们在父组件中插入了三个具名插槽的内容:头部插槽、默认插槽和底部插槽。这些内容将被插入到父组件的相应位置。
注意,在 Vue 2.6.0 版本之前,我们使用 slot
元素的 name
属性来定义具名插槽,而在 Vue 2.6.0 版本及更高版本中,可以使用 v-slot
指令来定义具名插槽。
# 5.具名插槽的简写形式
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header
可以被重写为 #header:
<my-com-2>
<template #header>
<h1>滕王阁序</h1>
</template>
<template #default>
<p>豫章故郡,洪都新府。</p>
<p>星分翼轸,地接衡庐。</p>
<p>襟三江而带五湖,控蛮荆而引瓯越。</p>
</template>
<template #footer>
<p>落款:王勃</p>
</template>
</my-com-2>
2
3
4
5
6
7
8
9
10
11
12
13
# 6.作用域插槽
作用域插槽(Scoped Slots)是 Vue 中一种特殊的插槽类型,允许组件向使用者暴露数据,使得使用者可以在插槽中访问该数据并进行自定义渲染。
以下是一个示例,展示了如何使用作用域插槽:
<!-- ParentComponent.vue -->
<template>
<div>
<h1>父组件</h1>
<slot :data="message"></slot>
</div>
</template>
<script>
export default {
data() {
return {
message: "Hello, World!",
};
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在上述示例中,<slot>
元素的 :data
属性绑定了组件的 message
数据。这样就创建了一个作用域插槽,将 message
数据传递给插槽内容的使用者。
<!-- App.vue -->
<template>
<div>
<parent-component>
<template v-slot:default="slotProps">
<p>{{ slotProps.data }}</p>
</template>
</parent-component>
</div>
</template>
<script>
import ParentComponent from "./ParentComponent.vue";
export default {
components: {
ParentComponent,
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在上述示例中,我们使用 v-slot
指令来定义作用域插槽。v-slot
后面的参数指定了要插入的插槽的名称,并通过参数 slotProps
访问作用域插槽的数据。
在这个例子中,我们在父组件中定义了一个作用域插槽,并将 message
数据传递给插槽的使用者。插槽内容中的 slotProps.data
将渲染出父组件传递的数据。
通过作用域插槽,组件可以向使用者提供更多的灵活性,使得使用者可以自定义渲染插槽内容,并且可以访问到组件的数据。这在一些需要自定义逻辑和样式的情况下非常有用,同时也提升了组件的可复用性和扩展性。
# 7.解构插槽 Prop
作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。示例代码如下:
<my-com-3>
<!--v-slot:可以简写成#-->
<!--作用域插槽对外提供的数据对象,可以通过“解构赋值”简化接收的过程--
<template #default="{user}">
<tr>
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.state}}</td>
</tr>
</template>
</my-com-3>
2
3
4
5
6
7
8
9
10
11
# 三.自定义指令
# 1.什么是自定义指令?
vue 官方提供了 v-text、v-for、v-model、v-if 等常用的指令。除此之外 vue 还允许开发者自定义指令。
# 2.自定义指令的分类
vue 中的自定义指令分为两类,分别是:
- 私有自定义指令
- 全局自定义指令
# 3.私有自定义指令
在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。示例代码如下:
directives: {
color: {
//为绑定到的HTML元素设置红色的文字
bind(el){
//形参中的el是绑定了此指令的、原生的DOM对象
el.style.color = 'red'
}
}
}
2
3
4
5
6
7
8
9
# 4.使用自定义指令
在使用自定义指令时,需要加上 v- 前缀。示例代码如下:
<!--声明自定义指令时,指令的名字是 color -->
<!--使用自定义指令时,需要加上v-指令前缀-->
<h1 v-color>App 组件</h1>
2
3
# 5.动态绑定参数值
为自定义指令动态绑定参数值
在 template 结构中使用自定义指令时,可以通过等号(=)的方式,为当前指令动态绑定参数值:
data() { return { color:'red'//定义 color颜色值 } }
<!--在使用指令时,动态为当前指令绑定参数值color-->
<h1 v-color="color">App 组件</h1>
2
3
通过 binding 获取指令的参数值
在声明自定义指令时,可以通过形参中的第二个参数,来接收指令的参数值:
directives: {
color: {
bind(el,binding){
//通过 binding 对象的.value 属性,获取动态的参数值
el.style.color = binding.value
}
}
}
2
3
4
5
6
7
8
# 6.update 函数
bind 函数只调用 1 次:当指令第一次绑定到元素时调用,当 DOM 更新时 bind 函数不会被触发。 update 函
数会在每次 DOM 更新时被调用。示例代码如下:
directives: {
color: {
//当指令第一次被绑定到元素时被调用
bind(el,binding){
el.style.color = binding.value
},
//每次 DOM 更新时被调用
update(el, binding) {
el.style.color = binding.value
}
}
}
2
3
4
5
6
7
8
9
10
11
12
# 7.函数简写
如果 insert 和 update 函数中的逻辑完全相同,则对象格式的自定义指令可以简写成函数格式:
directives: {
//在 insert 和 update 时,会触发相同的业务逻辑
color(el,binding){
el.style.color = binding.value
}
}
2
3
4
5
6
# 8.全局自定义指令
全局共享的自定义指令需要通过“Vue.directive()”进行声明,示例代码如下:
//参数1:字符串,表示全局自定义指令的名字
//参数2:对象,用来接收指令的参数值
Vue.directive('color', function(el, binding){
el.style.color = binding.value
})
2
3
4
5
← 04-组件的生命周期 06-路由 →