动态组件、插槽、自定义指令
学习目标
1.能够了解组件进阶知识。
2.能够掌握自定义指令的创建和使用。
3.能够完成tabbar案例的开发。
1.组件进阶
1.0 动态组件
问题:如何切换2个组件,互斥的显示或者隐藏呢?
动态组件定义: 多个组件使用同一个挂载点,并动态切换。
需求: 完成一个注册功能页面, 2个按钮切换, 一个填写注册信息, 另一个填写用户简介信息。
效果如下:
1.准备被切换的 - UserName.vue / UserInfo.vue 2个组件
2.引入到UseDynamic.vue注册
3.准备变量来承载要显示的"组件名"
4.设置挂载点<component>
, 使用 is属性
来设置要显示哪个组件
5.点击按钮 – 修改comName变量里的"组件名"
- UserName.vue / UserInfo.vue
<template>
<div>
<div>
<span>用户名:</span>
<input type="text">
</div>
<div>
<span>密码:</span>
<input type="password">
</div>
</div>
</template>
- 01_UseDynamic.vue
<template>
<div>
<button @click="comName = 'UserName'">账号密码填写</button>
<button @click="comName = 'UserInfo'">个人信息填写</button>
<p>下面显示注册组件-动态切换:</p>
<div style="border: 1px solid red;">
<!--vue内置的组件component,可以动态的显示组件-->
<component :is="comName"></component>
</div>
</div>
</template>
<script>
// 目标: 动态组件 - 切换组件显示
// 场景: 同一个挂载点要切换 不同组件 显示
// 1. 创建要被切换的组件 - 标签+样式
// 2. 引入到要展示的vue文件内, 注册
// 3. 变量-承载要显示的组件名
// 4. 设置挂载点<component :is="变量"></component>
// 5. 点击按钮-切换comName的值为要显示的组件名
import UserName from '../components/01/UserName'
import UserInfo from '../components/01/UserInfo'
export default {
data(){
return {
comName: "UserName"
}
},
components: {
UserName,
UserInfo
}
}
</script>
- 在App.vue - 引入01_UseDynamic.vue并使用显示:
<template>
... 省略注册
</template>
import UseDynamic from './views/01_UseDynamic'
export default {
components: {
UseDynamic
}
}
总结: 1.如何使用动态组件?vue内置component组件, 配合is属性, 设置要显示的组件名字。
2.如何切换?改变is属性的值为要显示的组件名即可。
1.1 组件缓存
演示1: 可以先给UserName.vue和UserInfo.vue 注册created和destroyed生命周期事件, 观察创建和销毁过程。
注意: 组件切换会导致组件被频繁销毁和重新创建, 所以性能不高。
【解决】使用Vue内置的 keep-alive组件
, 可以让包裹的组件保存在内存中不被销毁。
演示2: 使用keep-alive内置的vue组件, 让动态组件缓存而不是销毁。
- 02_UseDynamic.vue
<div style="border: 1px solid red;">
<!-- Vue内置keep-alive组件, 把包起来的组件缓存起来 -->
<keep-alive>
<component :is="comName"></component>
</keep-alive>
</div>
总结: keep-alive可以提高组件的性能, 内部包裹的标签不会被销毁和重新创建, 而是触发激活和非激活的生命周期方法。
1.2 激活和非激活
目标: 被缓存的组件不再创建和销毁, 而是激活和非激活。
补充2个新的生命周期方法:
- activated – 激活时触发
- deactivated – 失去激活状态触发
1.3 组件插槽
问题1:组件里的数据不确定时可以怎么做? 让组件在props里面定义一个变量,使用这个组件的时候分别传入不同的数据。
问题2:组件里的标签不确定时怎么办呢? vue提供组件插槽能力, 允许开发者在封装组件时,把不确定的部分定义为插槽。
组件插槽: 用于实现组件的内容分发, 通过 slot 标签
, 可以接收到写在组件标签内的内容。
插槽例子:
案例: 以前的折叠面板案例, 想要实现不同内容显示, 我们把折叠面板里的Pannel组件, 添加组件插槽的方式:
语法口诀:
1.组件内不确定的标签处用 <slot></slot>
占位。
2.使用此组件,<组件名>传入具体标签</组件名>
- src/components/03/Pannel.vue - 插槽
<slot></slot>
的使用。
<template>
<div>
<!-- 按钮标题 -->
<div class="title">
<h4>芙蓉楼送辛渐</h4>
<span class="btn" @click="isShow = !isShow">
{
{
isShow ? "收起" : "展开" }}
</span>
</div>
<!-- 下拉内容 -->
<div class="container" v-show="isShow">
<slot>默认显示内容</slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isShow: false,
};
},
};
</script>
<style scoped>
h3 {
text-align: center;
}
.title {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #ccc;
padding: 0 1em;
}
.title h4 {
line-height: 2;
margin: 0;
}
.container {
border: 1px solid #ccc;
padding: 0 1em;
}
.btn {
/* 鼠标改成手的形状 */
cursor: pointer;
}
img {
width: 50%;
}
</style>
- src/views/03_UserSlot.vue - 使用组件(原始代码)
<template>
<div id="container">
<div id="app">
<h3>案例:折叠面板</h3>
</div>
</div>
</template>
<script>
export default {
};
</script>
<style>
#app {
width: 400px;
margin: 20px auto;
background-color: #fff;
border: 4px solid blueviolet;
border-radius: 1em;
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.5);
padding: 1em 2em 2em;
}
</style>
- src/views/03_UseSlot.vue - 组件插槽使用
<template>
<div id="container">
<div id="app">
<h3>案例:折叠面板</h3>
<Pannel>
<img src="../assets/mm.gif" alt="">
<span>我是内容</span>
</Pannel>
<Pannel>
<p>寒雨连江夜入吴,</p>
<p>平明送客楚山孤。</p>
<p>洛阳亲友如相问,</p>
<p>一片冰心在玉壶。</p>
</Pannel>
<Pannel></Pannel>
</div>
</div>
</template>
<script>
import Pannel from "../components/03/Pannel";
export default {
components: {
Pannel,
},
}
</script>
- src/App.vue
<template>
<div>
<UseSlot></UseSlot>
</div>
</template>
<script>
import UseSlot from './views/03_UseSlot'
export default {
components: {
UseSlot
}
}
总结: 1.当组件内某一部分标签不确定时怎么办?用插槽技术。
2.插槽具体如何使用? ①先在组件内用slot占位。②使用组件时,用具体的标签插入。
3.插槽运行效果? 传入的标签会替换掉slot显示。
1.4 插槽默认内容
问题: 使用组件时,如果不给slot传标签怎么办?可否设置默认内容?
口诀: <slot>
内放置内容, 作为默认显示内容。
效果:不给组件传标签,slot内容原地显示。如果给组件内传标签,则slot整体被替换掉。
<slot>默认内容</slot>
1.5 具名插槽
场景: 多个slot需要区分。传入的标签可以分别派发给不同的slot位置。
要求: v-slot一般和template标签
使用 (template是html5新出标签内容模板元素, 不会渲染到页面上, 一般被vue解析的内部标签)
- components/04/Pannel.vue - 留下具名slot
<template>
<div>
<!-- 按钮标题 -->
<div class="title">
<slot name="title"></slot>
<span class="btn" @click="isShow = !isShow">
{
{
isShow ? "收起" : "展开" }}
</span>
</div>
<!-- 下拉内容 -->
<div class="container" v-show="isShow">
<slot name="content"></slot>
</div>
</div>
</template>
- views/04_UseSlot.vue使用
<template>
<div id="container">
<div id="app">
<h3>案例:折叠面板</h3>
<Pannel>
<template v-slot:title>
<h4>芙蓉楼送辛渐</h4>
</template>
<template v-slot:content>
<img src="../assets/mm.gif" alt="">
<span>我是内容</span>
</template>
</Pannel>
<Pannel>
<template #title>
<span style="color: red;">我是标题</span>
</template>
<template #content>
<p>寒雨连江夜入吴,</p>
<p>平明送客楚山孤。</p>
<p>洛阳亲友如相问,</p>
<p>一片冰心在玉壶。</p>
</template>
</Pannel>
</div>
</div>
</template