一、动态组件
如何切换2个组件 互斥的显示或者隐藏呢 除了v-if
什么是动态组件?
多个组件使用同一个挂载点,并动态切换。这就是动态组件
完成一个注册功能页面, 2个按钮切换, 一个填写注册信息, 一个填写用户简介信息
- 准备变量来承载要显示的"组件名"
- 设置挂载点, 使用is属性来设置要显示哪个组件
<template>
<div>
<button @click="comName = 'UserName'">账号密码填写</button>
<button @click="comName = 'UserInfo'">个人信息填写</button>
<p>下面显示注册组件-动态切换:</p>
<div style="border: 1px solid red;">
<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>
vue内置component组件, 配合is属性, 设置要显示的组件名字
- 什么是动态组件?
在同一个挂载点, 可以切换显示不同组件 - 如何使用动态组件?
vue内置的component组件, 配合is属性 <component :is="组件名"></component> - 如何切换?
改变is属性的值, 为要显示的组件名即可
二、组件缓存
在频繁的切换动态组件 会导致 组件的频发创建和销毁,导致效率不高
可以通过vue 内置的Keep-alive 组件包裹 component 组件 来解决
<div style="border: 1px solid red;">
<!-- Vue内置keep-alive组件, 把包起来的组件缓存起来 -->
<keep-alive>
<component :is="comName"></component>
</keep-alive>
</div>
keep-alive 组件有两个生命周期
activated - 激活 deactivated 失去激活状态
三、组件的激活和非激活状态
如何知道组件被切走了还是切回来?
通过 激活状态的生命周期 中的钩子函数
activated 激活 deactivated 失去激活状态来判断
如果 不想给某个 组件设置 缓存怎么操作?
可以通过
include="组件Aname" 组件A会缓存,其他的不会被缓存
exclude=“组件Aname” 组件a 不会被换缓存 其他的组件缓存
<!-- <keep-alive exclude="comTwoName">
<components :is="comname"></components>
</keep-alive> -->
<keep-alive exclude="ComOnes">
<components :is="comname"></components>
</keep-alive>
四、组件插槽
组件里的数据不确定可以怎么做?
通过 slot 标签
以前折叠面板案例, 想要实现不同内容显示, 我们把折叠面板里的Pannel组件, 添加组件插槽方式
语法:
组件内使用<slot></slot> 站位
使用组件时 <Pannel></Pannel> 夹着的地方 传入标签替换slot
①当组件内某一部分标签不确定怎么办?
用插槽技术
②插槽具体如何使用?
先在组件内使用slot 站位
③插槽运行效果?
传入的标签会替换掉slot 显示 如果没有传入会显示默认插槽里面的内容
④ 如何给插槽设置默认显示内容?
<slot>默认显示内容</slot>
⑤什么时候插槽默认内容会显示?
当组件不传入具体标签或者内容时
五、具名插槽
如果组件内2处以上不确定标签怎么办,可以通过给插槽起名解决!
v-slot一般用跟template标签使用 (template是html5新出标签内容模板元素, 不会渲染到页面上, 一般被vue解析内部标签)
语法?
①slot 使用name属性 区分名字
②template 配合v-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>
使用名字
<Pannel>
//通过 v-slot:插槽名字
<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>
</template>
</Pannel>
使用插槽 名字 语法:
v-sloat:插槽名字 #插槽名字
- 组件内多处不确定的标签如何做?
slot占位, 给name属性起名字来区分
template配合v-slot:name分发要替换的标签 - v-slot: 可以简化成什么?
#
六、作用域插槽
使用插槽时,想要使用组件内的变量?
子组件里面的值, 在插槽赋值时 在 父组件环境下使用?
语法:
①子组件,在slot 上绑定属性和子组件内的值
②使用组件,传入自定义标签,用template 和 v-slot = “ 自定义变量名”
③scope变量自动绑定 slot上所有的属性和值
<template>
<div>
<!-- 按钮标题 -->
<div class="title">
<h4>芙蓉楼送辛渐</h4>
<span class="btn" @click="isShow = !isShow">
{{ isShow ? "收起" : "展开" }}
</span>
</div>
<!-- 下拉内容 -->
<div class="container" v-show="isShow">
<slot :row="defaultObj">{{ defaultObj.defaultOne }}</slot>
</div>
</div>
</template>
<script>
// 目标: 作用域插槽
// 场景: 使用插槽, 使用组件内的变量
// 1. slot标签, 自定义属性和内变量关联
// 2. 使用组件, template配合v-slot="变量名"
// 变量名会收集slot身上属性和值形成对象
export default {
data() {
return {
isShow: false,
defaultObj: {
defaultOne: "无名氏",
defaultTwo: "小传同学"
}
};
},
};
</script>
<Pannel>
<!-- 需求: 插槽时, 使用组件内变量 -->
<!-- scope变量: {row: defaultObj} -->
<template v-slot="scope">
<p>{{ scope.row.defaultTwo }}</p>
</template>
</Pannel>
子组件内 设置 :row=“变量”
父组件
在 template 标签设置 v-slot = "scope" 来接收 slot 插槽的所有变量(scope变量: {row: defaultObj} - )这种情况 在使用的时候 需要 scope.row.想要调用的变量名
或者 通过 v-slot = "row" row是自定义变量名
总结:
① 作用域插槽什么时候使用?
父组件 想要用子组件的变量
②口诀?
子组件在slot 上添加属性 和 子组件的值
使用组件出的template 配合 v-slot="变量名 " 收集 slot 身上所有的属性和值
作用域插槽使用场景?
了解作用域插槽使用场景, 自定义组件内标签+内容
案例: 封装一个表格组件, 在表格组件内循环产生单元格
准备MyTable.vue组件 – 内置表格, 传入数组循环铺设页面, 把对象每个内容显示在单元格里
准备UseTable.vue – 准备数据传入给MyTable.vue使用
components/06/MyTable.vue - 模板(直接复制)
<template>
<div>
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>头像</th>
</tr>
</thead>
<thead>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</thead>
</table>
</div>
</template>
<script>
export default {
}
</script>
views/06_UseTable.vue - 准备数据, 传入给MyTable.vue组件里循环使用
list: [
{
name: "小传同学",
age: 18,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",
},
{
name: "小黑同学",
age: 25,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",
},
{
name: "智慧同学",
age: 21,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",
},
],
正确做法:
在MyTable.vue的td中准备占位, 但是外面需要把图片地址赋予给src属性,所以在slot上把obj数据绑定
components/06/MyTable.vue
<template>
<div>
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>头像</th>
</tr>
</thead>
<tbody>
<tr v-for="(obj, index) in arr" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.age }}</td>
<td>
<slot :row="obj">
<!-- 默认值给上,如果使用组件不自定义标签显示默认文字 -->
{{ obj.headImgUrl}}
</slot>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: {
arr: Array
}
}
</script>
在UseTable使用MyTable的时候, template上v-slot绑定变量, 传入img组件设置图片地址
<template>
<div>
<MyTable :arr="list"></MyTable>
<MyTable :arr="list">
<!-- scope: {row: obj} -->
<template v-slot="scope">
<a :href="scope.row.headImgUrl">{{ scope.row.headImgUrl }}</a>
</template>
</MyTable>
<MyTable :arr="list">
<template v-slot="scope">
<img style="width: 100px;" :src="scope.row.headImgUrl" alt="">
</template>
</MyTable>
</div>
</template>
<script>
import MyTable from "../components/06/MyTable";
export default {
components: {
MyTable,
},
data() {
return {
list: [
{
name: "小传同学",
age: 18,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",
},
{
name: "小黑同学",
age: 25,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",
},
{
name: "智慧同学",
age: 21,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",
},
],
};
},
};
</script>
<style>
</style>
小结
我们为什么要使用作用域插槽?
可以让组件更加灵活的适用于不同的场景和项目
插槽可以自定义标签, 作用域插槽可以把组件内的值取出来自定义内容
七、组件name
name的作用
1、递归组件的(组件调用自身组件)
这个时候被递归的组件name必写
<template>
<div>
<childVue :list="arr" />
</div>
</template>
<script>
import childVue from "./child.vue";
export default {
components: {
childVue,
},
data() {
return {
//无限极的数据
arr: [
{
name: "一级",
childArr: [
{
name: "二级",
},
{
name: "二级",
childArr: [
{ name: "三级" },
{
name: "三级",
childArr: [{ name: "四级" }],
},
],
},
],
},
{
name: "一级",
},
{
name: "一级",
},
],
};
},
methods: {},
};
</script>
<style scoped></style>
<template>
<!-- <div> -->
<ul>
<li v-for="(item, index) in list" :key="index">
{{ item.name }}
<!-- 用 v-if 判断 item 里面是不是还有孩子 如果有 通过组件 name 输出出里面的孩子 -->
<template v-if="item.childArr">
<ChildTree :list="item.childArr" />
</template>
</li>
</ul>
<!-- </div> -->
</template>
<script>
//场景:后台管理系统的左侧手风琴菜单
//作用:处理、展示无限极的数据
export default {
name: "ChildTree",
props: ["list"],
data() {
return {};
},
methods: {},
};
</script>
<style scoped></style>
2、组件的缓存keep-alive
一个组件需不需要被缓存,也是需要通过name属性来控制。
3、vue调试插件DevTools
显示组件的name,语义化