封装el-card和表格
项目要求在一个弹窗中显示一个个card模块,并且在里面加入表格,因为card比较多,字段也比较多,所以还是需要进行封装
封装card核心代码
- IndexDialogInfo
vue
<template>
<dialog-info ref="refIndexDialogInfo" class="dialog_info_wrap" :isShowFotter="true">
<!-- 标题 -->
<template #DialogTitle>
<span>{{ currentData.networkType }} xxx - {{ currentData.cellName }}</span>
</template>
<!-- 内容 -->
<template #DialogContainer>
<div class="dialog_wrap">
<div class="index4g_wrap index_wrap" v-if="currentData.networkType === '4G'">
<index-card v-for='(item, index) in cardColumnData.card4GColumnList' :key="index"
:indexCardTitle="cardColumnTitle.card4GColumnTitle[index.split('List')[1] - 1]"
:indexCardColumns="item" :indexCardTableData="getCardItemData(4, index)" />
<!-- 不进行遍历写法
<index-card :indexCardTitle="'card1title'"
:indexCardTableData="indexCardList.card4GDataList.card4GDataList1"
:indexCardColumns="cardColumnData.card4GColumnList.card4GColumnList1" />
<index-card :indexCardTitle="'card2title'"
:indexCardTableData="indexCardList.card4GDataList.card4GDataList2"
:indexCardColumns="cardColumnData.card4GColumnList.card4GColumnList2" /> -->
</div>
<div class="index5g_wrap index_wrap" v-if="currentData.networkType === '5G'">
<index-card v-for='(item, index) in cardColumnData.card5GColumnList' :key="index"
:indexCardTitle="cardColumnTitle.card5GColumnTitle[index.split('List')[1] - 1]"
:indexCardColumns="item" :indexCardTableData="getCardItemData(5, index)" />
</div>
</div>
</template>
</dialog-info>
</template>
<script setup>
import { ref, nextTick } from "vue";
// 组件
import IndexCard from "./IndexCard.vue";
// api相关 - 工具
import { apiCommon } from "@/utils/index.js";
// import * as xxxApi from "@/api/xxx/xxx";
// 数据
import { cardColumnData, cardColumnTitle } from './data/cardColumnData'
import { cardTableData } from './data/cardTableData' // mock数据
const router = useRouter();
const { proxy } = getCurrentInstance();
const refIndexDialogInfo = ref(null);
const currentData = ref({});
const indexCardList = ref({});
// 遍历获取表格数据
const getCardItemData = (type, index) => {
return eval(`cardTableData.card${type}GDataList.card${type}GDataList${index.split('List')[1]}`)
}
const getIndexData = async () => {
console.log("获取数据", cardTableData, cardColumnData)
let params = {
...currentData.value
}
console.log(params);
// let resData = await apiCommon(xxxApi.xxx, params);
// console.log(resData);
// 处理数据
indexCardList.value = cardTableData
};
/**
* 业务
*/
const show = (val) => {
currentData.value = val
getIndexData();
refIndexDialogInfo.value.show();
// refIndexDialogInfo.value.setDialogWidth('30%');
};
defineExpose({
show,
});
</script>
<style lang="scss" scoped>
.dialog_info_wrap {
.dialog_wrap {
.index_wrap {
.el-card {
cursor: pointer;
&:not(:last-child) {
margin-bottom: 20px;
}
}
.index_cont {}
}
}
}
</style>
<template>
<dialog-info ref="refIndexDialogInfo" class="dialog_info_wrap" :isShowFotter="true">
<!-- 标题 -->
<template #DialogTitle>
<span>{{ currentData.networkType }} xxx - {{ currentData.cellName }}</span>
</template>
<!-- 内容 -->
<template #DialogContainer>
<div class="dialog_wrap">
<div class="index4g_wrap index_wrap" v-if="currentData.networkType === '4G'">
<index-card v-for='(item, index) in cardColumnData.card4GColumnList' :key="index"
:indexCardTitle="cardColumnTitle.card4GColumnTitle[index.split('List')[1] - 1]"
:indexCardColumns="item" :indexCardTableData="getCardItemData(4, index)" />
<!-- 不进行遍历写法
<index-card :indexCardTitle="'card1title'"
:indexCardTableData="indexCardList.card4GDataList.card4GDataList1"
:indexCardColumns="cardColumnData.card4GColumnList.card4GColumnList1" />
<index-card :indexCardTitle="'card2title'"
:indexCardTableData="indexCardList.card4GDataList.card4GDataList2"
:indexCardColumns="cardColumnData.card4GColumnList.card4GColumnList2" /> -->
</div>
<div class="index5g_wrap index_wrap" v-if="currentData.networkType === '5G'">
<index-card v-for='(item, index) in cardColumnData.card5GColumnList' :key="index"
:indexCardTitle="cardColumnTitle.card5GColumnTitle[index.split('List')[1] - 1]"
:indexCardColumns="item" :indexCardTableData="getCardItemData(5, index)" />
</div>
</div>
</template>
</dialog-info>
</template>
<script setup>
import { ref, nextTick } from "vue";
// 组件
import IndexCard from "./IndexCard.vue";
// api相关 - 工具
import { apiCommon } from "@/utils/index.js";
// import * as xxxApi from "@/api/xxx/xxx";
// 数据
import { cardColumnData, cardColumnTitle } from './data/cardColumnData'
import { cardTableData } from './data/cardTableData' // mock数据
const router = useRouter();
const { proxy } = getCurrentInstance();
const refIndexDialogInfo = ref(null);
const currentData = ref({});
const indexCardList = ref({});
// 遍历获取表格数据
const getCardItemData = (type, index) => {
return eval(`cardTableData.card${type}GDataList.card${type}GDataList${index.split('List')[1]}`)
}
const getIndexData = async () => {
console.log("获取数据", cardTableData, cardColumnData)
let params = {
...currentData.value
}
console.log(params);
// let resData = await apiCommon(xxxApi.xxx, params);
// console.log(resData);
// 处理数据
indexCardList.value = cardTableData
};
/**
* 业务
*/
const show = (val) => {
currentData.value = val
getIndexData();
refIndexDialogInfo.value.show();
// refIndexDialogInfo.value.setDialogWidth('30%');
};
defineExpose({
show,
});
</script>
<style lang="scss" scoped>
.dialog_info_wrap {
.dialog_wrap {
.index_wrap {
.el-card {
cursor: pointer;
&:not(:last-child) {
margin-bottom: 20px;
}
}
.index_cont {}
}
}
}
</style>
- IndexCard.vue
vue
<template>
<el-card shadow="hover">
<template #header>
<div class="card-header">
<span>{{ indexCardTitle }}</span>
</div>
</template>
<div class="index_cont">
<el-table :data="indexCardTableData" style="width: 100%">
<el-table-column v-for="(item, index) in indexCardColumns" :key="index" :prop="item.prop" :width="item.width" :label="item.label" />
</el-table>
</div>
</el-card>
</template>
<script setup>
import { ref } from "vue";
const props = defineProps({
indexCardTitle: {
type: String,
default: '',
},
indexCardColumns: {
type: Array,
default: () => []
},
indexCardTableData: {
type: Array,
default: () => []
},
});
</script>
<template>
<el-card shadow="hover">
<template #header>
<div class="card-header">
<span>{{ indexCardTitle }}</span>
</div>
</template>
<div class="index_cont">
<el-table :data="indexCardTableData" style="width: 100%">
<el-table-column v-for="(item, index) in indexCardColumns" :key="index" :prop="item.prop" :width="item.width" :label="item.label" />
</el-table>
</div>
</el-card>
</template>
<script setup>
import { ref } from "vue";
const props = defineProps({
indexCardTitle: {
type: String,
default: '',
},
indexCardColumns: {
type: Array,
default: () => []
},
indexCardTableData: {
type: Array,
default: () => []
},
});
</script>
使用组件
vue
<index-dialog-info ref="refIndexDialogInfo" />
<el-button link type="primary" size="small" @click="refIndexDialogInfo.value.show(scope.row)">xxx</el-button>
<index-dialog-info ref="refIndexDialogInfo" />
<el-button link type="primary" size="small" @click="refIndexDialogInfo.value.show(scope.row)">xxx</el-button>
数据格式
- cardColumnData.js ➡️ 表格字段,不可删
js
/**
* 字段数据,不可删
*/
export const cardColumnData = {
// 4gxxx
card4GColumnList: {
// list1
card4GColumnList1: [
{ prop: 'date1', label: '日期', width: 'auto' },
{ prop: 'name1', label: 'Name', width: 'auto' },
{ prop: 'address1', label: 'address', width: 'auto' }
],
// list2
card4GColumnList2: [
{ prop: 'date2', label: '日期', width: 'auto' },
{ prop: 'name2', label: 'Name', width: 'auto' },
{ prop: 'address2', label: 'address', width: 'auto' }
],
// list3
card4GColumnList3: [
{ prop: 'date3', label: '日期', width: 'auto' },
{ prop: 'name3', label: 'Name', width: 'auto' },
{ prop: 'address3', label: 'address', width: 'auto' }
],
},
// 5gxxx
card5GColumnList: {
// list1
card5GColumnList1: [
{ prop: 'date', label: '日期', width: 'auto' },
{ prop: 'name', label: 'Name', width: 'auto' },
{ prop: 'address', label: 'address', width: 'auto' }
],
// list2
card5GColumnList2: [
{ prop: 'date', label: '日期', width: 'auto' },
{ prop: 'name', label: 'Name', width: 'auto' },
{ prop: 'address', label: 'address', width: 'auto' }
],
},
};
export const cardColumnTitle = {
// 4g指标标题
card4GColumnTitle: [
'card1title',
'card2title',
'card3title',
],
// 5g指标标题
card5GColumnTitle: [
'card1title',
'card2title',
]
}
/**
* 字段数据,不可删
*/
export const cardColumnData = {
// 4gxxx
card4GColumnList: {
// list1
card4GColumnList1: [
{ prop: 'date1', label: '日期', width: 'auto' },
{ prop: 'name1', label: 'Name', width: 'auto' },
{ prop: 'address1', label: 'address', width: 'auto' }
],
// list2
card4GColumnList2: [
{ prop: 'date2', label: '日期', width: 'auto' },
{ prop: 'name2', label: 'Name', width: 'auto' },
{ prop: 'address2', label: 'address', width: 'auto' }
],
// list3
card4GColumnList3: [
{ prop: 'date3', label: '日期', width: 'auto' },
{ prop: 'name3', label: 'Name', width: 'auto' },
{ prop: 'address3', label: 'address', width: 'auto' }
],
},
// 5gxxx
card5GColumnList: {
// list1
card5GColumnList1: [
{ prop: 'date', label: '日期', width: 'auto' },
{ prop: 'name', label: 'Name', width: 'auto' },
{ prop: 'address', label: 'address', width: 'auto' }
],
// list2
card5GColumnList2: [
{ prop: 'date', label: '日期', width: 'auto' },
{ prop: 'name', label: 'Name', width: 'auto' },
{ prop: 'address', label: 'address', width: 'auto' }
],
},
};
export const cardColumnTitle = {
// 4g指标标题
card4GColumnTitle: [
'card1title',
'card2title',
'card3title',
],
// 5g指标标题
card5GColumnTitle: [
'card1title',
'card2title',
]
}
- cardTableData.js ➡️ 模拟表格数据
js
/**
* mock数据
*/
export const cardTableData = {
// 4gxxx
card4GDataList: {
// list1
card4GDataList1: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
// list2
card4GDataList2: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
// list3
card4GDataList3: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
},
// 5gxxx
card5GDataList: {
// list1
card5GDataList1: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
// list2
card5GDataList2: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
},
};
/**
* mock数据
*/
export const cardTableData = {
// 4gxxx
card4GDataList: {
// list1
card4GDataList1: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
// list2
card4GDataList2: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
// list3
card4GDataList3: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
},
// 5gxxx
card5GDataList: {
// list1
card5GDataList1: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
// list2
card5GDataList2: [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
],
},
};
公共DialogInfo代码
具体使用方法可以移步前文 -> 封装一个公共的dialog组件 查阅
在侧边栏新增锚点
在弹出框中,因为数据量很多,所以需要新增锚点,方便用户快速定位到指定位置
vue
<template>
<div class="anchor_wrap">
<ul>
<li v-for="(item, index) in cardColumnTitle.card4GColumnTitle" :key="index">
<span ref="spans" @click="jump(index, $event)">
{{ item }}
</span>
</li>
</ul>
</div>
<div class="index_cont" @scroll="onScroll">
<index-card class="scroll-item" v-for='(item, index) in cardColumnData.card4GColumnList'
:key="index" :indexCardTitle="cardColumnTitle.card4GColumnTitle[getListNum(index)]"
:indexCardColumns="item" :indexCardTableData="getCardItemData(4, index)" />
</div>
</template>
<script>
// 数据
import { cardColumnData, cardColumnTitle } from './data/cardColumnData'
import { cardTableData } from './data/cardTableData' // mock数据
const getListNum = (name) => {
return name.split('List')[1]
}
// 遍历获取表格数据
const getCardItemData = (type, index) => {
return eval(`cardTableData.card${type}GDataList.card${type}GDataList${getListNum(index)}`)
}
const jump = (index, e) => {
// 侧边栏样式
let titleDom = document.querySelectorAll(".anchor_wrap ul li")
titleDom.forEach((item, i) => {
item.classList.remove('selected')
})
if (index && e) {
e.target.parentNode.classList.add('selected')
} else {
titleDom[0].classList.add('selected')
}
// 滚动
let items = document.querySelectorAll(".scroll-item");
if (!index) {
items[0].scrollIntoView({
block: "start", // 默认跳转到顶部
behavior: "smooth" // 滚动的速度
});
return
}
for (var i = 0; i < items.length; i++) {
if (index === i) {
items[i].scrollIntoView({
block: "start", // 默认跳转到顶部
behavior: "smooth" // 滚动的速度
});
}
}
}
const onScroll = (e) => {
let scrollItems = document.querySelectorAll(".scroll-item");
for (let i = scrollItems.length - 1; i >= 0; i--) {
// 判断滚动条滚动距离是否大于当前滚动项可滚动距离
let judge =
e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop;
if (judge) {
activeStep = i;
break;
}
}
}
nextTick(() => {
setTimeout(() => {
jump()
}, 300);
})
</script>
<style lang="scss" scoped>
.dialog_info_wrap {
.dialog_wrap {
.index_wrap {
display: flex;
justify-content: space-between;
.anchor_wrap {
width: 19%;
height: 100%;
overflow: auto;
ul {
width: 95%;
li {
margin-bottom: 3px;
padding: 0 10px;
min-height: 30px;
font-size: 13px;
line-height: 30px;
cursor: pointer;
transition: .3s linear;
span {
display: block;
width: 100%;
height: 100%;
transition: .5s;
}
&:hover,
&.selected {
background: #409eff;
border-radius: 5px;
span {
// background: #f00;
color: #fff;
transition: .3s linear;
}
}
&:hover {
span {
padding-left: 10px;
}
}
}
}
}
.index_cont {
flex: 1;
height: 74vh;
overflow: auto;
scrollbar-width: none;
.el-card {
cursor: pointer;
&:not(:last-child) {
margin-bottom: 20px;
}
}
}
}
}
}
</style>
<template>
<div class="anchor_wrap">
<ul>
<li v-for="(item, index) in cardColumnTitle.card4GColumnTitle" :key="index">
<span ref="spans" @click="jump(index, $event)">
{{ item }}
</span>
</li>
</ul>
</div>
<div class="index_cont" @scroll="onScroll">
<index-card class="scroll-item" v-for='(item, index) in cardColumnData.card4GColumnList'
:key="index" :indexCardTitle="cardColumnTitle.card4GColumnTitle[getListNum(index)]"
:indexCardColumns="item" :indexCardTableData="getCardItemData(4, index)" />
</div>
</template>
<script>
// 数据
import { cardColumnData, cardColumnTitle } from './data/cardColumnData'
import { cardTableData } from './data/cardTableData' // mock数据
const getListNum = (name) => {
return name.split('List')[1]
}
// 遍历获取表格数据
const getCardItemData = (type, index) => {
return eval(`cardTableData.card${type}GDataList.card${type}GDataList${getListNum(index)}`)
}
const jump = (index, e) => {
// 侧边栏样式
let titleDom = document.querySelectorAll(".anchor_wrap ul li")
titleDom.forEach((item, i) => {
item.classList.remove('selected')
})
if (index && e) {
e.target.parentNode.classList.add('selected')
} else {
titleDom[0].classList.add('selected')
}
// 滚动
let items = document.querySelectorAll(".scroll-item");
if (!index) {
items[0].scrollIntoView({
block: "start", // 默认跳转到顶部
behavior: "smooth" // 滚动的速度
});
return
}
for (var i = 0; i < items.length; i++) {
if (index === i) {
items[i].scrollIntoView({
block: "start", // 默认跳转到顶部
behavior: "smooth" // 滚动的速度
});
}
}
}
const onScroll = (e) => {
let scrollItems = document.querySelectorAll(".scroll-item");
for (let i = scrollItems.length - 1; i >= 0; i--) {
// 判断滚动条滚动距离是否大于当前滚动项可滚动距离
let judge =
e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop;
if (judge) {
activeStep = i;
break;
}
}
}
nextTick(() => {
setTimeout(() => {
jump()
}, 300);
})
</script>
<style lang="scss" scoped>
.dialog_info_wrap {
.dialog_wrap {
.index_wrap {
display: flex;
justify-content: space-between;
.anchor_wrap {
width: 19%;
height: 100%;
overflow: auto;
ul {
width: 95%;
li {
margin-bottom: 3px;
padding: 0 10px;
min-height: 30px;
font-size: 13px;
line-height: 30px;
cursor: pointer;
transition: .3s linear;
span {
display: block;
width: 100%;
height: 100%;
transition: .5s;
}
&:hover,
&.selected {
background: #409eff;
border-radius: 5px;
span {
// background: #f00;
color: #fff;
transition: .3s linear;
}
}
&:hover {
span {
padding-left: 10px;
}
}
}
}
}
.index_cont {
flex: 1;
height: 74vh;
overflow: auto;
scrollbar-width: none;
.el-card {
cursor: pointer;
&:not(:last-child) {
margin-bottom: 20px;
}
}
}
}
}
}
</style>