动态组件与keepAlive+插槽

动态组件与keepAlive+插槽

动态组件(component配合 :is属性)

提出原因:

v-show/ v-if 因为参数形式是boolean属性不能满足动态选择子组件的显示

样例:(实现点击子组件的名字显示子组件内容)

<!--	父组件	-->
<template>
  <!-- 动态组件, is: 需要渲染的组件名称-->
  <!-- 这里的显示相当于v-show和v-if	-->  
  <!-- <component is="tabMonday"></component> -->

	<!-- 实现子组件的切换	定义数组(遍历数组呈现数组名称,通过选择数组中元素的名称作为唯一键显示该子组件的内容)-->
	<!-- 再定义一个点击事件,当选中的标签赋给当前元素item,当遍历的数组元素等于目前的选中的元素就加上一个class属性:active:true|false 显示当前的样式 -->
  <button v-for="item in tabArr" :key="item" @click="currentTab = item" :class="{ active: currentTab === item }">
    {{ item }}
  </button>
</template>

<script>
import tabMonday from "./components/tabMonday.vue";
import tabTuesday from "./components/tabTuesday.vue";
import tabWednesday from "./components/tabWednesday.vue";
export default {
  data() {
    return {
      currentTab: "tabMonday", // 当前需要渲染的组件名称
      tabArr: ["tabMonday", "tabTuesday", "tabWednesday"], // 需要动态切换组件的名称
    };
  },
  components: {
    tabMonday,
    tabTuesday,
    tabWednesday,
  },
};
</script>
<style scoped>
.active {
  background-color: #f00;
}
</style>


<!-- 子组件1 -->
<template>
  <!-- <div>周一:逆天战纪</div> -->
  <div>
    周一
  </div>
</template>
<!-- 子组件2 -->
<template>
  <!-- <div>周二:我是不白吃</div> -->
  <div>
    周二
  </div>
</template>
<template>
  <!-- <div>周三:长剑风云</div> -->
  <div>
    周三
  </div>
</template>  

KeepAlive

运用场景:

当子组件存在复选框等需要被记录的数据,原本component组件不能满足,因为component组件本质上是讲子组件中的标签进行一个注册和删除,当切换时会自动移除上一个被选中的子组件

本质:

缓存原本应该被移除的组件实例, 在组件第一次被创建(渲染)时缓存起来

代码:

<KeepAlive >
    <component :is="currentTab"></component>
</KeepAlive>
拓展:条件性的选择哪些组件被缓存

前提:相关的组件(子组件)必须指定name选项来做区分,不然是没有办法根据组件名字匹配

<!-- 父组件 -->
<!-- 注意直接匹配不用加属性绑定(:)正则和数组需要加 -->
<!-- include: 包含的就缓存 -->
<KeepAlive include="tabMonday,tabTuesday">
    <component :is="currentTab"></component>
</KeepAlive>
<!-- 正则 -->
<KeepAlive :include="/tabMonday|tabTuesday/">
    <component :is="currentTab"></component>
</KeepAlive>
<!-- 数组 -->
<KeepAlive :include="['tabMonday', 'tabTuesday']">
    <component :is="currentTab"></component>
</KeepAlive>

<!-- exclude: 匹配名字的组件都不缓存, 未匹配到名字的组件就缓存 -->
<KeepAlive exclude="tabMonday,tabTuesday">
    <component :is="currentTab"></component>
  </KeepAlive>

<KeepAlive :exclude="/tabMonday|tabTuesday/">
    <component :is="currentTab"></component>
</KeepAlive> 

<KeepAlive :exclude="['tabMonday', 'tabTuesday']">
    <component :is="currentTab"></component>
</KeepAlive>

<!-- max:最大缓存的实例数量。如果超出最大数,会将缓存里最早最久没有被访问的实例销毁掉,为新组件实例腾空间 -->
<KeepAlive :max="10">
    <component :is="currentTab"></component>
</KeepAlive>

<!-- 子组件 -->
<template>
  <!-- <div>周二:我是不白吃</div> -->
  <div>
    周二
  </div>
</template>
<script>
export default{
    name: "tabTuesday" 					 //其他同理需要定义自己的name
}					
</script>

总结:

1.不使用缓存时,组件的切换是: mounted挂载 / unmounted销毁

2.缓存的组件实例的生命周期. 组件的切换是:激活/不活跃的状态变化

****缓存时切换组件状态会自动调用子组件的的两个钩子函数(activated和deactivated)

代码:

<script>
export default{
    name: "tabMonday", // 选项式API要加, 组合式API不用加
    activated(){
        // 激活时
        console.log("%c 激活时---activated", "color: #f00");
    },
    deactivated(){
        // 不活跃时
        console.log("%c 不活跃时---deactivated", "color: #f00");
    }
}
</script>

插槽

作用:

​ 设计封装时, 可以接收外部传入的内容

构成:

​ 1.入口:父组件运用子组件双标签中间的内容(内容包含父组件data数据[插值函数]、其他组件)

​ 2.出口:子组件添加组件显示【预留的内容占位符(内容指的是写在组件标签之间的 内容)】

代码:

<!-- 父组件 -->
<template>
    <p>App.vue根组件</p>
    {{ age }}
    <hr>
	<Child>
        这里是父组件向插槽提供的内容					 <!-- 普通元素 -->
        <p>这是父组件传过来的内容--{{ name }}</p>		<!-- 父元素插值函数 -->
        <p>这是父组件传过来的内容--{{ age }}</p>		
        <tabMonday/>							   <!-- 导入的其他组件 -->
    </Child>
</template>
<script>
import Child from "./components/Child.vue";
import tabMonday from "./components/tabMonday.vue";
export default {
  data() {
    return {
        name: "丸子",
        age: 16
    };
  },
  components: {
    Child,
    tabMonday
  },
};
</script>

<!-- 子组件 -->
<template>
    <div>Child</div>
	<slot>  
        <p>插槽的默认内容</p>
        ...					<!-- <slot>标签中可以定义插值的默认内容(当父元素没有给值显示) -->
    </slot>
</template>

上述代码是子组件只有一个插槽函数时例子,当子组件有多个插槽怎么办呢?

子类多插槽:

针对多个插槽出口时,v-slot属性搭配template元素(v-slot:子组件name属性)

代码:

<!-- 父组件 -->
<Child>
    22222-----这里的内容是没有指定给哪个name插槽的		<!-- 会传递给默认插槽 -->
    <template v-slot:wanzi>		
		<p>这里写的都是给wanzi的</p>				<!-- 会传递给名为wanzi插槽 -->
    </template>
    <template v-slot:cherry>
		<p>这里写的都是给cherry的</p>
    </template>
    <template v-slot:afei>
		<p>这里写的都是给afei的</p>
    </template>
    1111-----这里的内容是没有指定给哪个name插槽的		<!-- 会传递给默认插槽 -->
</Child>
<!-- v-slot 简化写法 #-->
    <!-- <Child>
        22222-----这里的内容是没有指定给哪个name插槽的
        <template #wanzi>
            <p>这里写的都是给wanzi的</p>
        </template>
        <template #cherry>
            <p>这里写的都是给cherry的</p>
        </template>
        <template #afei>
            <p>这里写的都是给afei的</p>
        </template>
        1111-----这里的内容是没有指定给哪个name插槽的
    </Child> -->
<!-- 子组件 -->
 <!-- 默认插槽。 它的name名为default 。接收的是没人要的内容(默认内容)-->
<slot name="default"></slot>	<!-- 这里的name="default"可以不加 -->
<header>
    <slot name="wanzi"></slot>
</header>
<main>
    <slot name="cherry"></slot>
</main>
<footer>
    <slot name="afei"></slot>
</footer>
子类向父类传递数据

v-slot属性点子类传向父类属性别名

代码

<!-- 父组件 -->
<Child v-slot="slotProps">
    <p>这是父组件传过来的内容--{{ name }}</p>
    <p>这是父组件传过来的内容--{{ age }}</p>
    <!-- 在书写内容的位置,访问当前Child组件的数据 -->
    <p>{{ slotProps.username }}---{{ slotProps.usertag }}</p>
</Child> 

<!-- 子组件 -->
<!-- 作为props传递时, 书写名不能与当前组件的data数据同名 -->
<template>
	<slot :username="name" :usertag="tag"></slot>
</template>
<script>
export default{
    data(){
        return {
            name: "周四",
            tag: "再坚持1天~"
        }
    }
}
</script>

插槽赋值也可以使用结构

代码:

<!-- 父组件 -->
<Child>
    <template #wanzi="{username, usertag}">					
		<p>{{ username }}---{{ usertag }}</p>
    </template>
    <template v-slot="slotProps2">
		<p>{{ slotProps2.xxname }}</p>
    </template>
</Child>

<!-- 子组件 -->
<template>
    <div>Child</div>
    <!-- 作用域插槽 -->
    <!-- 作为props传递时, 书写名不能与当前组件的data数据同名 -->
    <slot name="wanzi" :username="name" :usertag="tag"></slot>
    <slot :xxname="name"></slot>
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值