14、Vue组件进阶
1、动态组件
问题描述:
当我们在使用大多数网站的时候,登录和注册可以在同一个页面实现,就是当点击登录的时候登录的相关信息显示,点击注册的时候,注册的相关信息显示。
针对以上问题我们可以使用v-if和v-show等方式来解决在vue中我们还提供了一种解决方式,就是利用动态组件来实现
1、准备两个需要切换的组件
- UserName.vue
<template> <div> <span>用户名:</span> <input type="text" name="" id="" /> <span>密码:</span> <input type="text" name="" id="" /> </div></template><script>export default {};</script><style></style>
- UserInfo.vue
<template> <div> <div> <span>人生格言:</span> <input type="text" /> </div> <div> <span>个人简介</span> </div> </div></template><script>export default {};</script><style></style>
2、引入到UseTab.vue注册
import UserName from "@/components/Demo01/UserName";import UserInfo from "@/components/Demo01/UserInfo";export default { // 注册组件 components: { UserName, UserInfo, },};
3、准备变量来承载要显示的"组件名"
data() { return { //设置挂载点 comName: "UserName", }; },
4、设置挂载点
, 使用is属性来设置要显示哪个组件
<component :is="comName"></component>
5、点击按钮 – 修改comName变量里的"组件名"
<button @click="comName='UserName'">账号密码填写</button> <button @click="comName='UserInfo'">个人信息填写</button>
6、完整代码
<template> <div> <button @click="comName='UserName'">账号密码填写</button> <button @click="comName='UserInfo'">个人信息填写</button> <p>下面显示注册的组件</p> <div class="contain"> <component :is="comName"></component> </div> </div></template><script>// 导入组件import UserName from "@/components/Demo01/UserName";import UserInfo from "@/components/Demo01/UserInfo";export default { data() { return { //设置挂载点 comName: "UserName", }; }, // 注册组件 components: { UserName, UserInfo, },};</script><style lang="less" scoped>.contain { width: 500px; height: 200px; border: 1px solid red;}</style>
【效果图】:
7、App.vue
<template> <div> <h1>动态组件的使用</h1> <UseTab></UseTab> </div></template><script>// 导入组件import UseTab from "@/components/Demo01/UseTab";export default { components: { UseTab, },};</script><style></style>
总结:动态组件使用步骤
1、准备需要切换的组件
2、将需要切换的组件引入的一个组件中,注册、使用
3、将第二部的组件引入到app.vue中注册、使用
4、在第二步的组件中准备一个变量接收要显示的组件的名称
5、结合组件的内置标签, 使用is属性来设置要显示哪个组件
6、点击按钮,修改要显示组件变量的值
2、组件缓存
问题描述:在上述的动态组件的使用过程中,当我们在频繁切换的过程中,会频繁的创创建、销毁,如果页面中有大量的请求或者业务操作,会导致性能极差。
1、问题演示
【代码修改】:
- UserName.vue
export default { created() { console.log("username组件---创建了"); }, destroyed() { console.log("username组件---销毁了"); },};</script>
- UserInfo.vue
export default { created() { console.log("userInfo组件---创建了"); }, destroyed() { console.log("userInfo组件---销毁了"); },};</script>
【结果图】:
2、问题解决
使用keep-alive内置的vue组件, 让动态组件缓存而不是销毁
【代码修改】:
<keep-alive> <component :is="comName"></component> </keep-alive>
【效果图】:
3、组件插槽
vue提供组件插槽能力, 允许开发者在封装组件时,把不确定的部分定义为插槽
1、基本使用
- 组件内用
占位
- 使用组件时夹着的地方, 传入标签替换slot
2、折叠面板案例重新演示
- 准备折叠面板组件
在内容区域使用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>
- 准备使用面板的组件
导入面板,并且替换面板内部的内容
<template> <div id="container"> <div id="app"> <h3>案例:折叠面板</h3> //使用面板。并替换插槽内部的内容 <Panel> <img src="../../assets/mm.gif" alt="" /> <span>我是文字哦</span> </Panel> <Panel name=""> <p>寒雨连江夜入吴,</p> <p>平明送客楚山孤。</p> <p>洛阳亲友如相问,</p> <p>一片冰心在玉壶。</p> </Panel> </div> </div></template><script>import Panel from "@/components/Demo03/Panel";export default { components: { Panel, },};</script><style lang="less" scoped>#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>
- App.vue
<template> <div> <UserPanel></UserPanel> </div></template><script>import UserPanel from "@/components/Demo03/UserPanel";export default { components: { UserPanel, },};</script><style></style>
【效果图演示】:
3、插槽默认内容设置
夹着内容默认显示内容, 如果不给插槽slot传东西, 则使用
夹着的内容在原地显示
【语法】:
<slot>默认内容</slot>
4、具名插槽
问题描述:
当我们的组件中有多处内容不确定的时候,又需要使用插槽技术的时候,我们传递的不确定内容该如何对号入座呢?
1、具名插槽基本使用
【语法】:
- slot使用name属性区分名字
- template配合v-slot:名字来分发对应标签
2、折叠面板案例修改
途中的#title是一种简写的方式,相当于v-click用@代替
补充:
v-slot一般用跟template标签使用 (template是html5新出标签内容模板元素, 不会渲染到页面上, 一般被vue解析内部标签)
5、作用域插槽
1、使用步骤
- 子组件, 在slot上绑定属性和子组件内的值
- 使用组件, 传入自定义标签, 用template和v-slot=“自定义变量名”
- scope变量名自动绑定slot上所有属性和值
2、折叠面板改造
- 面板组件
- 使用面板组件
3、作用域插槽案例
需求: 封装一个表格组件, 在表格组件内循环产生单元格
- MyTable.vue
<template> <div> <table border="1"> <thead> <tr> <th>序号</th> <th>姓名</th> <th>年龄</th> <th>头像</th> </tr> </thead> <thead> <tr v-for="(item, index) in list" :key="index"> <td>{{ index + 1 }}</td> <td>{{ item.name }}</td> <td>{{ item.age }}</td> <td> <slot :img="item">{{ item.headImgUrl }}</slot> </td> </tr> </thead> </table> </div></template><script>export default { 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>
- UseTable.vue
<template> <div> <MyTable> <template v-slot="imgNew"> <img :src="imgNew.img.headImgUrl" alt="" /> </template> </MyTable> </div></template><script>import MyTable from "@/components/Table/MyTable";export default { components: { MyTable, },};</script><style>img { width: 100px; height: 100px; border: 1px solid #333; border-radius: 50px; margin: 5px;}</style>
- App.vue
<template> <div> <UseTable></UseTable> </div></template><script>import UseTable from "@/components/Table/UseTable";export default { components: { UseTable, },};</script><style></style>