slot 平时不常用 今天封装一个卡片列表组件学习一下!
首先写出来一个卡片的样式
<div class="card p-3 mt-3 bg-white">
<div class="card-header pb-3 d-flex ai-center">
<i class="iconfont icon-menu" ></i>
<div class="fs-xl flex-1 ml-2">卡片标题</div>
<i class="iconfont icon-more1"></i>
</div>
<div class="card-body pt-3">
<div class="nav jc-between">
<div class="nav-item active">
<div class="nav-link">分类标题1</div>
< /div>
<div class="nav-item">
<div class="nav-link">分类标题2</div>
< /div>
<div class="nav-item">
<div class="nav-link">分类标题3</div>
< /div>
</div>
</div>
<div class="pt-3">
<swiper>
<!--循环出来3个分类对应的3块slide-->
<swiper-slide v-for="(item,index) in 3 " :key="index">
<!--循环每一个slide的每一条数据-->
<div v-for="(itm,idx) in item.Newslist" :key="idx" class="py-2">
<span>{{itm.name}}</span>
<span>{{itm.title}}</span>
<span>{{itm.date}}</span>
</div>
</swiper-slide>
</swiper>
</div>
</div>
</div>
这样我们就实现了一个卡片列表 我们把上面的封装为组件
// Card.vue
<template>
<div class="card p-3 mt-3 bg-white">
<div class="card-header pb-3 d-flex ai-center">
<i class="iconfont" :class="`icon-${icon}`"></i>
<!--卡片标题-->
<div class="fs-xl flex-1 ml-2">{{title}}</div>
<i class="iconfont icon-more1"></i>
</div>
<div class="card-body pt-3">
<!-- 预留插槽 外部引用组件时可以传递内容 因为每一个卡片内部的排版不一致 -->
<slot></slot>
</div>
</div>
</template>
props: {
title: {
type: String,
required: true
},
icon: {
type: String,
required: true
}
}
// main.js注册为全局组件
// 卡片组件
import Card from './components/Card.vue';
Vue.component('m-card', Card);
home.vue 使用组件
// home.vue 使用组件
<m-card :icon="icon" :title="title">
<!-- 将下面放入card-body的插槽中 -->
<div class="nav jc-between">
<div class="nav-item active">
<div class="nav-link">分类标题1</div>
</div>
<div class="nav-item">
<div class="nav-link">分类标题2</div>
</div>
<div class="nav-item">
<div class="nav-link">分类标题3</div>
</div>
</div>
<div class="pt-3">
<swiper>
<!--循环出来3个分类对应的3块slide-->
<swiper-slide v-for="(item,index) in 3 " :key="index">
<div v-for="(itm,idx) in item.Newslist" :key="idx" class="py-2">
<span>{{itm.name}}</span>
<span>{{itm.title}}</span>
<span>{{itm.date}}</span>
</div>
</swiper-slide>
</swiper>
</div>
</m-card>
这样我们使用card组件传递标题名和字体图标类名即可 但是还不能满足我们深度封装的需求 所以我们继续改造
// ListCard.vue
<template>
<m-card :icon="icon" :title="title">
<!-- 将下面放入card-body的插槽中 -->
<div class="nav jc-between">
<div class="nav-item active">
<div class="nav-link">分类标题1</div>
</div>
<div class="nav-item">
<div class="nav-link">分类标题2</div>
</div>
<div class="nav-item">
<div class="nav-link">分类标题3</div>
</div>
</div>
<div class="pt-3">
<swiper>
<swiper-slide v-for="(item,index) in 3 " :key="index">
<div v-for="(itm,idx) in item.Newslist" :key="idx" class="py-2">
<span>{{itm.name}}</span>
<span>{{itm.title}}</span>
<span>{{itm.date}}</span>
</div>
</swiper-slide>
</swiper>
</div>
</m-card>
</template>
props: {
title: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
categories: {
type: Array,
required: true
}
}
// main.js 封装列表卡片
// 列表卡片组件
import ListCard from './components/ListCard.vue';
Vue.component('m-list-card', ListCard);
这样我们在引用组件时这样使用
// home.js
<m-list-card icon="menu" title="新闻资讯" :categories="NewsData">
</m-list-card>
但是这样又带了一个问题 卡片列表部分的样式不可修改 我们可以利用插槽的 #items 来解决
// ListCard.vue 将swiper-slide 展示列表的部分这样改
<swiper>
<swiper-slide v-for="(item,index) in categories " :key="index">
<!-- <div v-for="(itm,idx) in item.Newslist" :key="idx" class="py-2">
<span>{{itm.name}}</span>
<span>{{itm.title}}</span>
<span>{{itm.date}}</span>
</div>-->
<!-- 由于每个卡片的样式不同 所以这个地方用slot 并且把循环的值传给外层 -->
<slot name="items" :category="item"></slot>
</swiper-slide>
</swiper>
// home.vue
<m-list-card icon="menu" title="新闻资讯" :categories="NewsData">
<!--
<template
<div v-for="(itm,idx) in category.Newslist" :key="idx" class="py-2">
<span>{{itm.name}}</span>
<span>{{itm.title}}</span>
<span>{{itm.date}}</span>
</div>
</template>
</m-list-card>
这个组件的主要难点在于 组件内的循环的数据如何传递给外部 我们定义一个插槽时 可以为其指定name 并且绑定动态数据
当需要接收插槽的数据时 通过#items="{插槽绑定的变量名}" 来接收