主要方法:https://blog.csdn.net/m0_57391092/article/details/119191630
第一天:
父组件:index.vue
搜索组件:SearchBar.vue
表格组件:TableList.vue
表格组件里的数据通过:
defineExpose({showCols,})
暴露出去。
const showCols = computed(() => {return {productShowCols: toRaw(TabMapDataSource[TabsEnum.REGISTER].showColumns), //注册信息batchShowCols: toRaw(TabMapDataSource[TabsEnum.BATCH].showColumns) // 批次信息}})




父组件中通过:
<TableListref="tableListRef" //总的ref/>const tableListRef = ref()
来接收总的ref。
父组件中通过tableListRef.value.showCols拿到数据:
/*** 导出excel*/const exportExcel = (callback) => {// callback()console.log(tableListRef.value.showCols, tableListData) //表头和数据}
//表单总数const tableListData = reactive({[TabsEnum.REGISTER]: {}, //注册表格信息[TabsEnum.BATCH]: {} //批次表格信息})
searchbar组件中通过引入导出excel所需的包:
import ExportJsonExcel from 'js-export-excel'// 导出按钮,通过调用方法发出自定义事件<div class="search-right" @click="exportExcel"><a-button>导出</a-button></div>// 发出自定义事件,将封装的方法给父组件const exportExcel = () => {Emit('exportExcel', exportFunc)}
父组件通过exportExcel自定义事件来触发方法,他接收了封装的方法作为参数:
const exportExcel = (callback) => {// callback()}
第二天:

可以选择字段导出:
父组件拿到searchBar子组件发送的自定义事件,接收了mode(选择当前还是全部字段)和导出excel的回调函数作为参数;通过selectCols添加注册信息和批次信息的数组,通过switch语句选择是当前字段还是全部字段,把注册信息和批次信息数组处理成向后端发送的格式,然后拼接到condition里,通过exportInfo调用接口拿到返回数据,解构出data,放到回调函数里执行。
<template><SearchBar @exportExcel="exportExcel" @handleSearch="handleSearch" :filter="filter" :frameFilters="frameFilters" /><TableListref="tableListRef":loading="refreshTable.loading"@changeTab="changeTab"@changePagination="changePagination":currentTab="currentTab":tableListData="tableListData"/></template><script setup lang="ts">import SearchBar from './components/SearchBar.vue'import TableList from './components/TableList.vue'/*** tab 相关*/const currentTab = reactive({ value: TabsEnum.REGISTER }) //当前tab是注册还是批次// 导入请求接口import {getExportColumnsData,getExportProd} from '@/api/material'// 导入ts类型import {// 当前字段还是全部字段exportExcelModeEnum} from '@/views/register/registration-and-batch-info-query/types'const tableListRef = ref() // 拿到TableList组件导出的内容const globalSearchInfo = ref(initSearchInfo())/*** 导出接口*/const exportInfo = {// 注册的接口[TabsEnum.REGISTER]: {method: getExportProd,prefixName: t('register.registrationAndBatchInfoQuery.queryViewDetail.product')},// 批次的接口[TabsEnum.BATCH]: {method: getExportColumnsData,prefixName: t('register.registrationAndBatchInfoQuery.queryViewDetail.batch')}}/*** 导出*/const exportExcel = async (mode, callback: Function) => {let condition = {}let selectCols = {productShowCols: [],batchShowCols: []}// 判断是当前字段还是所有字段switch (mode) {// 如果是当前字段case exportExcelModeEnum.CURRENT_SHOW: {// 拿到注册和批次表格头const { productShowCols, batchShowCols } = tableListRef.value.showCols// 过滤一下数组然后放到selectCols里面seletCols.productShowCols = deBuildColumns(productShowCols)seletCols.batchShowCols = deBuildColumns(batchShowCols)// 拼接对象condition = Object.assign({}, globalSearchInfo.value, seletCols)break}// 如果是全部字段default: {condition = Object.assign({}, globalSearchInfo.value, tableListRef.value.currentAllCols)break}}// 调用接口const { data } = await exportInfo[currentTab.value].method(condition)// 调用回调callback(data, { fileName: `${exportInfo[currentTab.value].prefixName}_${treeNodeData.value.name}` })}</script>
// 注册信息还是批次信息
export enum TabsEnum {
REGISTER = 1, // 注册
BATCH //批次
}
// 当前字段还是全部字段
export enum exportExcelModeEnum {
ALL,
CURRENT_SHOW
}
export function initSearchInfo(): SearchInfo {
return {
keyword: '',
sortColumn: '',
pageSize: 10,
pageNum: 1,
filter: {
frameId: '',
frameName: '',
productName: '',
batchName: '',
batchParams: [],
productCustomParams: [],
batchCustomParams: []
},
productShowCols: [],
batchShowCols: []
}
}
export const deBuildColumns = (columns) => {
columns = columns || []
return columns.map((column) => ({
name: column.title,
key: column.dataIndex,
type: column.type
}))
}
用户点击按钮触发下拉菜单,触发handleSelectExportExcelMode方法,选择导出全部字段还是当前字段(exportExcelModeEnum),在方法中触发exportExcel(exportExcelMode.value)的调用;exportExcel方法中发送了一个exportExcel自定义事件给父组件,将exportExcelMode,exportFunc作为参数传递。
<template>
<div class="search-right">
<!--用户选择时触发handleSelectExportExcelMode方法-->
<a-dropdown @select="handleSelectExportExcelMode">
<a-button>导出</a-button>
<template #content>
<!--value是选项值-->
<a-doption :value="exportExcelModeEnum.CURRENT_SHOW">导出Excel(当前字段)</a-doption>
<a-doption :value="exportExcelModeEnum.ALL">导出Excel(全部字段)</a-doption>
</template>
</a-dropdown>
</div>
</template>
<script setup lang="ts">
import { exportExcelModeEnum } from '@/views/register/registration-and-batch-info-query/types'
import ExportJsonExcel from 'js-export-excel'
const Emit = defineEmits(['handleSearch', 'exportExcel'])
/**
* 导出excel文件
*/
const exportExcelMode = ref(exportExcelModeEnum.ALL)
const handleSelectExportExcelMode = (value) => {
exportExcelMode.value = value
exportExcel(exportExcelMode.value)
}
const exportFunc = (_data: Array<[]>, option: { [key in string]: any }) => {
let [targetHeader, sheetData]: [[], []] = [[], []]
const { fileName } = option
if (Array.isArray(_data) && _data.length > 0) {
const [firstArr] = _data.splice(0, 1)
targetHeader = firstArr
}
_data.forEach((items) => {
if (Array.isArray(items)) {
const targetRowInfo = {}
items.forEach((innerItem, index) => {
targetRowInfo[targetHeader[index]] = innerItem
})
sheetData.push(targetRowInfo as unknown as never)
}
})
const datas = [
{
sheetData,
sheetName: fileName,
sheetHeader: targetHeader,
sheetFilter: targetHeader
}
]
const toExcel = new ExportJsonExcel({
fileName,
datas
})
// 调用保存方法
toExcel.saveExcel()
}
const exportExcel = (exportExcelMode: exportExcelModeEnum) => {
Emit('exportExcel', exportExcelMode, exportFunc)
}
</script>
//组件内部维护的不同 tab 对应的信息
let TabMapDataSource = reactive({
[TabsEnum.REGISTER]: {
//展示的cols
showColumns: [],
//编辑的cols信息 (dataIndexArr)
selectShowColumns: []
},
[TabsEnum.BATCH]: {
showColumns: [],
selectShowColumns: []
}
})
const showCols = computed(() => {
return {
productShowCols: toRaw(TabMapDataSource[TabsEnum.REGISTER].showColumns),
batchShowCols: toRaw(TabMapDataSource[TabsEnum.BATCH].showColumns)
}
})
defineExpose({
selectedRowKeys,
showCols,
clearCacheData,
currentAllCols
})
defineExpose
我们从父组件获取子组件实例通过ref
<Menu ref="menus"></Menu>
const menus = ref(null)
然后打印menus.value 发现没有任何属性
这时候父组件想要读到子组件的属性可以通过 defineExpose暴露
const list = reactive<number[]>([4, 5, 6])
defineExpose({
list
})
这样父组件就可以读到了。

