1、需求: 几乎每个页面的每一个表格都使用到自定义表头字段,点击表格最后一列的图标,弹出表头所有可展示的字段:
2、父组件只需传全部可展示的表头数据即可(数组格式),具体代码:
<template>
<div class="common-box">
<div class="content-box">
<div class="assetManagement" v-show="!showDetail">
<div class="table-box">
<a-table
:columns="state.columns"
:row-key="(record) => record.id"
:data-source="state.dataSource"
:loading="loading"
:pagination="false"
>
<template #setTableTitle>
<a-tooltip>
<template #title>设置</template>
<span @click="handleTableHead" class="table-head-btn"><SettingOutlined /></span>
</a-tooltip>
</template>
<template #action="{ text }">
<a-tooltip>
<template #title>操作</template>
<a-popover title="" trigger="click" :visible="showBtn == text.region" @visibleChange="handleShowBtn(text)">
<template #content>
<div class="action-box" style="display: flex; flex-direction: column;">
<a @click="handleDetail(text)">查看详情</a>
</div>
</template>
<MenuOutlined />
</a-popover>
</a-tooltip>
</template>
</a-table>
</div>
</div>
<a-modal
class="table-head-modal"
:visible="tableHeadPop"
title="列表视图设置"
:confirmLoading="tableHeadLoading"
:width="750"
@cancel="handleCancel"
>
<table-head-content
ref="tableHeadRef"
:columns="state.setColumns"
></table-head-content>
<template #footer>
<div class="pop-btn-box">
<div class="btn-left">
<a-button @click="checkAll">全选</a-button>
<a-button @click="checkNoAll">全不选</a-button>
</div>
<div class="btn-right">
<a-button @click="handleCancel">返回</a-button>
<a-button type="primary" @click="handleOk" class="ok-btn">确定</a-button>
</div>
</div>
</template>
</a-modal>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, toRaw, getCurrentInstance, reactive, nextTick, computed } from "vue";
import { request } from "@/utils/request.js";
import {
ExclamationCircleOutlined,
SettingOutlined,
MenuOutlined
} from "@ant-design/icons-vue";
import { useStore } from 'vuex';
const store = useStore();
const globalProperties =
getCurrentInstance().appContext.config.globalProperties; // 获取全局挂载
const http = globalProperties.$http;
const loading = ref(false);
const showDetail = ref(false);
const tableHeadPop = ref(false);
const tableHeadLoading = ref(false);
const showBtn = ref("");
const tableHeadRef = ref(null);
const state = reactive({
dataSource: [],
manufactorList: [],
siteTypeList: [],
regionList: [],
columns: [
{
title: "区域",
dataIndex: "region",
},
{
title: "数量",
dataIndex: "assetsNum",
sorter: (a, b) => {
return a.assetsNum - b.assetsNum
},
},
{
title: "已安装",
dataIndex: "installNum",
sorter: (a, b) => {
return a.installNum - b.installNum
},
},
],
columnsAll: [
{
title: "区域",
dataIndex: "region",
ellipsis: true,
},
{
title: "数量",
dataIndex: "assetsNum",
sorter: (a, b) => {
return a.assetsNum - b.assetsNum
},
ellipsis: true,
},
{
title: "已安装",
dataIndex: "installNum",
sorter: (a, b) => {
return a.installNum - b.installNum
},
ellipsis: true,
},
{
title: "未安装",
dataIndex: "notInstall",
sorter: (a, b) => {
return a.notInstall - b.notInstall
},
ellipsis: true,
},
],
setColumns: []
});
const detailRef = ref(null);
state.siteTypeList = computed( () => store.state.siteTypeList);
state.regionList = computed( () => store.state.regionList);
state.manufactorList = computed( () => store.state.manufactorList);
// 获取表格数据
const getTableData = () => {
loading.value = true;
if(state.columns.length && (state.columns[state.columns.length -1].key != "setItem")) {
state.columns.push({
key: "setItem", // 不可使用dataIndex, 会导致操作拿不到当前行的数据
width: 60,
slots: {
title: "setTableTitle",
customRender: "action",
},
})
}
request(http.GET_DEVICE_ASSET_MANAGE_LIST, "get")
.then((res) => {
loading.value = false;
state.dataSource = res;
if(state.dataSource.length > 0) {
state.dataSource.map((item, index) => {
item.id = index;
})
}
})
.catch(() => {
loading.value = false;
});
};
const handleShowBtn = (text) => {
showBtn.value = text.region;
}
// 点击查看详情
const handleDetail = (text) => {
showDetail.value = true;
showBtn.value = ""; // 隐藏按钮小弹窗
// 触发子组件请求数据的方法
nextTick(() => {
detailRef.value.setValue(text.region);
})
};
// 点击动态设置表头
const handleTableHead = () => {
tableHeadPop.value = true;
nextTick(() => {
tableHeadRef.value.setValues(state.columnsAll);
});
state.setColumns = state.columns;
let num = state.setColumns.length - 1;
state.setColumns = toRaw(state.setColumns).slice(0, num); // 把设置那行去掉
};
// 全选
const checkAll = () => {
nextTick(() => {
tableHeadRef.value.checkAllSon();
})
};
// 全不选
const checkNoAll = () => {
nextTick(() => {
tableHeadRef.value.checkNoAllSon();
})
};
const handleCancel = () => {
tableHeadPop.value = false;
};
const handleOk = async() => {
let arr = await tableHeadRef.value.getValues();
if(arr.length) {
tableHeadPop.value = false;
state.columns = arr;
getTableData();
}
};
onMounted(() => {
getTableData();
});
</script>
<style lang="less" scoped>
.assetManagement {
height: 100%;
padding: 0.1rem;
}
</style>
3、主要代码在这块:
nextTick(() => {
tableHeadRef.value.setValues(state.columnsAll);
});
4、开始封装, 因为设计到选中样式,所以自己添加了checked属性,在子组件中定义一个变量,接收父组件通过参数传过来的数组
<template>
<div class="table-head-content">
<a-checkbox-group
v-model:value="state.checkedList"
name="checkboxgroup"
@change="onChange"
>
<ul class="check-ul">
<li v-for="(item, index) in state.columnsAll" :key="index" class="check-li" :class="{'isChecked': item.checked}">
<a-checkbox :value="item.title" @change="getCheckOne">
<span class="commonCode checkCode">{{ item.title }}</span>
</a-checkbox>
</li>
</ul>
</a-checkbox-group>
</div>
</template>
<script setup>
import { reactive, toRaw, getCurrentInstance } from "vue";
import { getJsonArrEqual } from "@/utils/common";
const globalProperties = getCurrentInstance().appContext.config.globalProperties; // 获取全局挂载
const toast = globalProperties.$toast;
const props = defineProps({
columns: Array,
});
const state = reactive({
checkedList: [],
columnsAll: []
});
// 初始化
const setValues = (columnsAll) => {
state.checkedList = [];
state.columnsAll = columnsAll
let newArr = getJsonArrEqual(toRaw(props.columns), state.columnsAll); // 获取相同项
state.columnsAll.forEach(i => { // 初始化checked属性
i.checked = false;
})
state.columnsAll.forEach(item => {
newArr.map(i => {
if(item.title == i.title) {
item.checked = true; // 初始化选中的checked值
state.checkedList.push(i.title);
}
})
});
};
// 选中
const onChange = (check) => {
state.checkedList = check;
};
// 单个选中
const getCheckOne = (e) => {
state.columnsAll.forEach((item, index) => {
if(item.title == e.target.value) {
state.columnsAll[index].checked = e.target.checked; // 根据选中与否赋值
}
})
};
// 获取选中
const getValues = () => {
return new Promise((resolve, reject) => {
if(state.checkedList.length >= 3) { // 必须选择三项或者三项以上
let arr = [];
state.checkedList.forEach(item => {
state.columnsAll.map(i => {
if(i.title == item) {
arr.push(i);
}
})
})
resolve(arr);
} else {
toast('必须选中三项或者三项以上喔!')
reject([]);
}
})
};
// 全选
const checkAllSon = () => {
if(state.columnsAll.length) {
state.checkedList = []; // 防止叠加
state.columnsAll.map(i => {
state.checkedList.push(i.title);
return i.checked = true;
})
}
};
// 全不选
const checkNoAllSon = () => {
state.checkedList = [];
state.columnsAll.map(i => {
return i.checked = false;
})
};
defineExpose({
setValues,
getValues,
checkAllSon,
checkNoAllSon
})
</script>
<style lang="less" scoped>
.table-head-content {
.check-ul {
display: flex;
flex-wrap: wrap;
.check-li {
padding: 2px 8px;
border-radius: 4px;
margin-right: .1rem;
margin-bottom: .1rem;
white-space: nowrap;
::v-deep(.ant-checkbox-wrapper) {
width: 200px;
}
&:hover {
background: @table-head-set-bg;
}
}
.isChecked {
background: @table-head-set-bg;
}
}
};
</style>
6、把公用组件放到src/components/common
7、在main.js中注册成全局组件
import tableHeadContent from './components/common/tableHeadContent.vue'
const app = createApp(App)
app.component('table-head-content', tableHeadContent);
app.use(antd).use(router).use(store).mount('#app')
<table-head-content />
面朝大海,春暖花开。
|