arcoapi意义:
- dataIndex:列信息的标识,对应TableData中的数据,也就是表头。
- rowKey:表格行key的取值字段,相当于vue中的key绑定的信息。
- columns:表格的列描述信息。
- data:表格的数据。
- column-resizable:是否允许调整列宽。
- select:点击行选择器时触发。
- select-all:点击全选时触发。
- selected:已选择的行。
- selectedRowKeys:已选择的行。
- tooltip:是否在显示省略号时显示文字提示。
- render:自定义列单元格的渲染。
- slotName:设置当前列的渲染插槽的名字。
笔记:
- $attrs号称捡漏王
当父组件给子组件传值,子组件并没有接收数据时,此时数据在$attrs中可以拿到,并且如果子组件不需要使用数组,而孙组件需要,则可以直接v-bind=”$attrs” 传给孙。 - $slots是组件插槽集,是组件所有默认插槽、具名插槽的集合,可以用来获取当前组件的插槽集。
- 可编辑表格:可以在使用插槽获得的数据,修改data中的数据,达到编辑表格的作用,可以直接修改插槽传出的record变量。这个变量是传入的data中对应数据的引用,请保证data为Reactive类型。
<template>
<div class="main-table-wrapper">
<!--如果需要过滤表头就显示下拉框勾选显示的字段-->
<div class="editor-show-columns-btn" v-if="Props.isShowFliter">
<a-dropdown position="br">
<a-button>
<template #icon>
<icon-settings />
</template>
</a-button>
<template #content>
<a-checkbox-group direction="vertical" v-model="selectShowColumns" class="editor-show-columns-ckb">
<template v-for="item in showCheckboxColumns" :key="item.dataIndex">
<!--展示表格头的title-->
<a-checkbox v-if="item.isShowFliter !== false" :value="item.dataIndex">
{{ item.title }}
</a-checkbox>
</template>
</a-checkbox-group>
</template>
</a-dropdown>
</div>
<!--表格体-->
<a-table
ref="TableRef"
:row-key="Props.rowKey"
:data="showData"
:columns="showColumns"
:column-resizable="true"
@select="handleSelected"
@selectAll="handleSelectedAll"
v-model:selectedKeys="selectedRowKeys"
v-bind="$attrs"
>
<!--$slots是组件插槽集,是组件所有默认插槽、具名插槽的集合,可以用来获取当前组件的插槽集。-->
<template v-for="(s, slot, index) in $slots" :key="index" #[slot]="item">
<template v-if="slot === 'customTitle'">
<div v-if="isShowCustomColumnTitle" class="custom-title">
<slot v-if="isShowCustomColumnTitle" name="customTitle" :item="item"></slot>
</div>
<span v-else>{{ customTitleName }}</span>
</template>
<!--渲染每一个插槽-->
<slot v-else :name="slot" :item="item"></slot>
</template>
</a-table>
</div>
</template>
<script setup lang="ts">
import { useElementSize } from '@vueuse/core'
import { computed, ref, watch } from 'vue'
import type { TableColumnData, TableData } from '@arco-design/web-vue'
import { isEmpty } from 'lodash'
const TableRef = ref(null)
const box = ref<string>('40px')
const { height } = useElementSize(TableRef)
const customTitleName = ref<string>('')
const showColumns = ref<Array<TableColumnData>>([])
const selectedKeysCache = ref<Map<string, any>>(new Map())
const Props = withDefaults(
defineProps<{
rowKey?: string
columns: Array<TableColumnData>
columnsAll?: Array<TableColumnData>
selectedRowKeys?: Array<string>
data?: Array<TableData>
isShowFliter?: boolean
}>(),
{
rowKey: 'key',
columns: () => [] as Array<TableColumnData>,
selectedRowKeys: () => [],
data: () => [],
isShowFliter: false
}
)
// 表格的表头,由父组件传的props.columns或columnsAll传递过来
const showCheckboxColumns = ref<Array<TableColumnData>>(Props.columnsAll ?? Props.columns)
// 过滤之后显示的表头
const selectShowColumns = ref<Array<string>>(showCheckboxColumns.value.map((item) => item.dataIndex) as Array<string>)
watch(
() => Props.columnsAll,
(columnsAll) => {
if (columnsAll) {
showCheckboxColumns.value = columnsAll
selectShowColumns.value = showCheckboxColumns.value.map((item) => item.dataIndex) as Array<string>
}
}
)
/**
* 表格展示数据
*/
const showData = computed(() => {
return isEmpty(selectShowColumns.value) ? [] : Props.data
})
interface IEmitType {
(e: 'changeColumns', obj: { columns: Array<TableColumnData>; dataIndexs: Array<string> }): void
(e: 'update:columns', columns: Array<TableColumnData>): void
(e: 'update:selectedRowKeys', selectedRowKeys: Array<string>): void
(e: 'update:selectedRows', selectedRowKeys: Array<TableData>): void
(e: 'select', _1: Array<string>, _2: string, _3: TableData, _4: Array<TableData>): void
(e: 'selectAll', isAll: boolean): void
}
const Emits = defineEmits<IEmitType>()
const isShowCustomColumnTitle = computed(() => {
const targetSelectedRowKeys = Props?.selectedRowKeys
if (targetSelectedRowKeys) {
return targetSelectedRowKeys.length > 0
}
return false
})
/**
* 选择一行
*/
const handleSelected = (_1: Array<string>, rowKey: string, _3: TableData) => {
const isExistence = selectedKeysCache.value.has(rowKey)
selectedKeysCache.value[isExistence ? 'delete' : 'set'](rowKey, _3)
Emits('update:selectedRowKeys', Array.from(selectedKeysCache.value.keys()))
Emits('update:selectedRows', Array.from(selectedKeysCache.value.values()))
Emits(
'select',
Array.from(selectedKeysCache.value.keys()),
rowKey,
_3,
Array.from(selectedKeysCache.value.values())
)
}
/**
* 维护 a-table 自身的 selectedRowKeys
*/
const selectedRowKeys = ref<string[]>()
watch(
() => Props.selectedRowKeys,
(newVal) => {
selectedRowKeys.value = newVal
// selectedKeysCache.value.clear()
// newVal.map((v) =>
// selectedKeysCache.value.set(
// v,
// Props.data.find((item) => item[Props.rowKey] === v)
// )
// )
},
{ immediate: true }
)
/**
* 全选
*/
const handleSelectedAll = (isAll) => {
// isAll
// ? Props.data?.forEach((item) => selectedKeysCache.value.add(item[Props.rowKey as string]))
// : selectedKeysCache.value.clear()
if (!isAll) {
Props.data.map((item) => selectedKeysCache.value.delete(item[Props.rowKey as string]))
} else {
Props.data.map((item) => selectedKeysCache.value.set(item[Props.rowKey as string], item))
}
Emits('update:selectedRowKeys', Array.from(selectedKeysCache.value.keys()))
Emits('update:selectedRows', Array.from(selectedKeysCache.value.values()))
Emits('selectAll', isAll)
}
watch(
() => Props.columns,
(newColumns) => {
const targetIndex = newColumns.findIndex((item) => item.customTitle)
const targetColumns = [...newColumns]
customTitleName.value = (targetColumns[targetIndex]?.title ?? '') as string
targetColumns[targetIndex] = {
...targetColumns[targetIndex],
titleSlotName: 'customTitle'
}
showColumns.value = targetColumns
if (!Props.isShowFliter) {
showCheckboxColumns.value = newColumns
selectShowColumns.value = showCheckboxColumns.value.map((item) => item.dataIndex) as Array<string>
}
},
{
immediate: true
}
)
/**
* 更新 columns
*/
watch(selectShowColumns, (newSelectShowColumns) => {
const targetColumns = showCheckboxColumns.value.filter(
(item) => newSelectShowColumns.includes(item?.dataIndex ?? '') || item.isShowFliter === false
)
Emits('update:columns', targetColumns)
Emits('changeColumns', { columns: targetColumns, dataIndexs: newSelectShowColumns })
})
/**
* 列设置动态大小
*/
watch(height, () => {
const TABLE_TR = document.querySelector('.main-table-wrapper thead .arco-table-tr') as HTMLElement
box.value = TABLE_TR?.offsetHeight ? TABLE_TR?.offsetHeight - 1 + 'px' : box.value
})
/**
* 暴露给外部的state
*/
const clearSelectedKeysCache = () => selectedKeysCache.value.clear()
defineExpose({
clearSelectedKeysCache
})
</script>
<style lang="scss" scoped>
.main-table-wrapper {
position: relative;
.editor-show-columns-btn {
position: absolute;
top: 0px;
right: 0px;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
width: v-bind(box);
height: v-bind(box);
font-size: 15px;
border: 1px solid #e5e6eb;
background-color: #f2f3f5;
}
.custom-title {
display: flex;
position: absolute;
top: 4px;
min-height: 24px;
z-index: 1;
border-radius: 2px;
width: max-content;
background: #fff;
padding: 2px 4px;
box-shadow: 0 0 2px 0 rgb(31 31 31 / 5%), 0 4px 6px 0 rgb(31 31 31 / 20%);
.forbidden {
cursor: not-allowed;
}
}
}
.editor-show-columns-ckb {
margin: 0 4px;
}
</style>