1. 动态组件
动态组件指的是动态切换组件的显示与隐藏。
1.1 如何实现动态组件渲染
vue 提供了一个内置的 <component>
组件,专门用来实现动态组件的渲染。示例代码如下:
1 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
| <template> <div id="app"> <component :is="comName"></component> <button @click="comName = 'LeftCom'">展示 Left 组件</button> <button @click="comName = 'RightCom'">展示 Right 组件</button> </div> </template>
<script> import LeftCom from './components/Left.vue' import RightCom from './components/Right.vue'
export default { name: 'App', components: { LeftCom, RightCom }, data() { return { comName: 'LeftCom' } }, methods: { } } </script>
|
1.2 使用keep-alive保持状态
默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 <keep-alive>
组件保持动态组件的状态。示例代码如下:
1 2 3
| <keep-alive> <component :is="comName"></component> </keep-alive>
|
1.3 keep-alive对应的生命周期函数
当组件被缓存时,会自动触发组件的 deactivated
生命周期函数。
当组件被激活时,会自动触发组件的 activated
生命周期函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| export default { name: 'LeftCom', props: { }, data() { return { } }, methods: { }, created() { console.log('组件被创建了') }, destroyed() { console.log('组件被销毁了') }, activated() { console.log('LeftCom 组件被激活了') }, deactivated() { console.log('LeftCom 组件被缓存了') } }
|
1.4 keep-alive的include属性
include 属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间使用英文的逗号分隔:
1 2 3
| <keep-alive include="LeftCom,RightCom"> <component :is="comName"></component> </keep-alive>
|
2. 插槽
插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。

可以把插槽认为是组件封装期间,为用户预留的内容的占位符。
2.1 体验插槽的基础用法
在封装组件时,可以通过 <slot>
元素定义插槽,从而为用户预留内容占位符。示例代码如下:
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div> <p>这是 MyCom1 组件的第1个p标签</p> <slot></slot> <p>这是 MyCom2 组件最后一个p标签</p> </div> </template>
<script> export default { name: 'TestSlot', props: { }, data() { return { } }, methods: { } } </script>
|
父组件
1 2 3
| <TestSlot> <p>~~~~用户自定义的内容~~~~</p> </TestSlot>
|
如果在封装组件时没有预留任何 <slot>
插槽,则用户提供的任何自定义内容都会被丢弃。
2.2 后备内容
封装组件时,可以为预留的 <slot>
插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何
内容,则后备内容会生效。示例代码如下:
1 2 3 4 5 6 7 8
| <template> <div> <p>这是 MyCom1 组件的第1个p标签</p> <slot>这是后备内容</slot> <p>这是 MyCom2 组件最后一个p标签</p> </div> </template>
|
2.3 具名插槽
如果在封装组件时需要预留多个插槽节点,则需要为每个 插槽指定具体的 name 名称。这种带有具体名称的插槽叫做“具名插槽”。示例代码如下:
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <template> <div> <slot name="header"></slot> <slot>这是后备内容</slot> <slot name="footer"></slot> </div> </template>
<script> export default { name: 'TestSlot', props: { }, data() { return { } }, methods: { } } </script>
|
父组件引用
1 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 33 34 35 36 37 38 39
| <template> <div id="app"> <TestSlot> <template v-slot:header> <div> <h1>滕王阁序</h1> </div> </template> <template v-slot:default> <div> <p>主体内容</p> </div> </template> <template v-slot:footer> <div> <p>落款:王勃</p> </div> </template> </TestSlot> </div> </template>
<script> import TestSlot from './components/TestSlot.vue'
export default { name: 'App', components: { TestSlot }, data() { return { } }, methods: { } } </script>
|
注意:没有指定 name 名称的插槽,会有隐含的名称叫做 default
2.4 具名插槽的简写形式
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot
:) 替换为字符 #
。例如 v-slot:header
可以被重写为 #header
2.5 作用域插槽
在封装组件的过程中,可以为预留的 <slot>
插槽绑定 props
数据,这种带有 props
数据的 <slot>
叫做“作用域插槽”。示例代码如下:
子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <slot name="z" v-for="fruit in fruitList" :fruit="fruit"></slot> </div> </template>
<script> export default { name: 'TestSlot', props: { }, data() { return { fruitList: ["苹果","柠檬","青柠"] } }, methods: { } } </script>
|
父组件
1 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 33
| <template> <div id="app"> <TestSlot> <template #z="scope"> <div> <tr> <td>{{ scope.fruit }}</td> </tr> </div> </template> </TestSlot> </div> </template>
<script> import TestSlot from './components/TestSlot.vue'
export default { name: 'App', components: { TestSlot }, data() { return { } }, methods: { } } </script>
|
3. 自定义指令
vue 官方提供了 v-text
、v-for
、v-model
、v-if
等常用的指令。除此之外 vue 还允许开发者自定义指令。
3.1 自定义指令的分类
vue 中的自定义指令分为两类,分别是:
- 私有自定义指令
- 全局自定义指令
3.2 私有自定义指令
在每个 vue 组件中,可以在 directives
节点下声明私有自定义指令。示例代码如下:
1 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 33
| <template> <div> <h1 v-color>作用域插槽</h1> <slot name="z" v-for="fruit in fruitList" :data="fruit"></slot> </div> </template>
<script> export default { name: 'TestSlot', props: { }, data() { return { fruitList: ["苹果","柠檬","青柠"] } }, methods: { }, directives: { color: { bind(el) { el.style.color = 'red' } } } } </script>
|
3.3 为自定义指令动态绑定参数值
在 template 结构中使用自定义指令时,可以通过等号(=
)的方式,为当前指令动态绑定参数值
通过 binding
获取指令的参数值,在声明自定义指令时,可以通过形参中的第二个参数,来接收指令的参数值
1 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 33 34 35
| <template> <div> <h1 v-color="color">作用域插槽</h1> <slot name="z" v-for="fruit in fruitList" :data="fruit"></slot> </div> </template>
<script> export default { name: 'TestSlot', props: { }, data() { return { fruitList: ["苹果","柠檬","青柠"], color: 'yellow' } }, methods: { }, directives: { color: { bind(el, binding) { el.style.color = binding.value } } } } </script>
|
3.4 update函数
bind 函数只调用 1 次:当指令第一次绑定到元素时调用,当 DOM 更新时 bind 函数不会被触发。 update 函数会在每次 DOM 更新时被调用。示例代码如下:
1 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 33 34 35 36 37 38 39
| <template> <div> <h1 v-color="color">作用域插槽</h1> <slot name="z" v-for="fruit in fruitList" :data="fruit"></slot> </div> </template>
<script> export default { name: 'TestSlot', props: { }, data() { return { fruitList: ["苹果","柠檬","青柠"], color: 'yellow' } }, methods: { }, directives: { color: { bind(el, binding) { el.style.color = binding.value }, update(el, binding) { el.style.color = binding.value } } } } </script>
|
3.5 函数简写
如果 insert
和update
函数中的逻辑完全相同,则对象格式的自定义指令可以简写成函数格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| directives: { color: { bind(el, binding) { el.style.color = binding.value }, update(el, binding) { el.style.color = binding.value } }, color2(el, binding) { el.style.color = binding.value } }
|
3.6 全局自定义指令
全局共享的自定义指令需要通过Vue.directive()
进行声明,示例代码如下:
1 2 3 4 5
|
Vue.directive('color',function(el, binding){ el.style.color = binding.value })
|