> 文档中心 > 14、Vue组件进阶

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、基本使用

  1. 组件内用占位
  2. 使用组件时夹着的地方, 传入标签替换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、具名插槽基本使用

【语法】:

  1. slot使用name属性区分名字
  2. template配合v-slot:名字来分发对应标签

2、折叠面板案例修改

在这里插入图片描述
途中的#title是一种简写的方式,相当于v-click用@代替
在这里插入图片描述

补充:
v-slot一般用跟template标签使用 (template是html5新出标签内容模板元素, 不会渲染到页面上, 一般被vue解析内部标签)

5、作用域插槽

1、使用步骤

  1. 子组件, 在slot上绑定属性和子组件内的值
  2. 使用组件, 传入自定义标签, 用template和v-slot=“自定义变量名”
  3. 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>