image.png
    arcoapi意义:

    1. dataIndex:列信息的标识,对应TableData中的数据,也就是表头。
    2. rowKey:表格行key的取值字段,相当于vue中的key绑定的信息。
    3. columns:表格的列描述信息。
    4. data:表格的数据。
    5. column-resizable:是否允许调整列宽。
    6. select:点击行选择器时触发。
    7. select-all:点击全选时触发。
    8. selected:已选择的行。
    9. selectedRowKeys:已选择的行。
    10. tooltip:是否在显示省略号时显示文字提示。
    11. render:自定义列单元格的渲染。
    12. slotName:设置当前列的渲染插槽的名字。

    笔记:

    1. $attrs号称捡漏王
      当父组件给子组件传值,子组件并没有接收数据时,此时数据在$attrs中可以拿到,并且如果子组件不需要使用数组,而孙组件需要,则可以直接v-bind=”$attrs” 传给孙。
    2. $slots是组件插槽集,是组件所有默认插槽、具名插槽的集合,可以用来获取当前组件的插槽集。
    3. 可编辑表格:可以在使用插槽获得的数据,修改data中的数据,达到编辑表格的作用,可以直接修改插槽传出的record变量。这个变量是传入的data中对应数据的引用,请保证data为Reactive类型。

    image.png

    1. <template>
    2. <div class="main-table-wrapper">
    3. <!--如果需要过滤表头就显示下拉框勾选显示的字段-->
    4. <div class="editor-show-columns-btn" v-if="Props.isShowFliter">
    5. <a-dropdown position="br">
    6. <a-button>
    7. <template #icon>
    8. <icon-settings />
    9. </template>
    10. </a-button>
    11. <template #content>
    12. <a-checkbox-group direction="vertical" v-model="selectShowColumns" class="editor-show-columns-ckb">
    13. <template v-for="item in showCheckboxColumns" :key="item.dataIndex">
    14. <!--展示表格头的title-->
    15. <a-checkbox v-if="item.isShowFliter !== false" :value="item.dataIndex">
    16. {{ item.title }}
    17. </a-checkbox>
    18. </template>
    19. </a-checkbox-group>
    20. </template>
    21. </a-dropdown>
    22. </div>
    23. <!--表格体-->
    24. <a-table
    25. ref="TableRef"
    26. :row-key="Props.rowKey"
    27. :data="showData"
    28. :columns="showColumns"
    29. :column-resizable="true"
    30. @select="handleSelected"
    31. @selectAll="handleSelectedAll"
    32. v-model:selectedKeys="selectedRowKeys"
    33. v-bind="$attrs"
    34. >
    35. <!--$slots是组件插槽集,是组件所有默认插槽、具名插槽的集合,可以用来获取当前组件的插槽集。-->
    36. <template v-for="(s, slot, index) in $slots" :key="index" #[slot]="item">
    37. <template v-if="slot === 'customTitle'">
    38. <div v-if="isShowCustomColumnTitle" class="custom-title">
    39. <slot v-if="isShowCustomColumnTitle" name="customTitle" :item="item"></slot>
    40. </div>
    41. <span v-else>{{ customTitleName }}</span>
    42. </template>
    43. <!--渲染每一个插槽-->
    44. <slot v-else :name="slot" :item="item"></slot>
    45. </template>
    46. </a-table>
    47. </div>
    48. </template>
    49. <script setup lang="ts">
    50. import { useElementSize } from '@vueuse/core'
    51. import { computed, ref, watch } from 'vue'
    52. import type { TableColumnData, TableData } from '@arco-design/web-vue'
    53. import { isEmpty } from 'lodash'
    54. const TableRef = ref(null)
    55. const box = ref<string>('40px')
    56. const { height } = useElementSize(TableRef)
    57. const customTitleName = ref<string>('')
    58. const showColumns = ref<Array<TableColumnData>>([])
    59. const selectedKeysCache = ref<Map<string, any>>(new Map())
    60. const Props = withDefaults(
    61. defineProps<{
    62. rowKey?: string
    63. columns: Array<TableColumnData>
    64. columnsAll?: Array<TableColumnData>
    65. selectedRowKeys?: Array<string>
    66. data?: Array<TableData>
    67. isShowFliter?: boolean
    68. }>(),
    69. {
    70. rowKey: 'key',
    71. columns: () => [] as Array<TableColumnData>,
    72. selectedRowKeys: () => [],
    73. data: () => [],
    74. isShowFliter: false
    75. }
    76. )
    77. // 表格的表头,由父组件传的props.columns或columnsAll传递过来
    78. const showCheckboxColumns = ref<Array<TableColumnData>>(Props.columnsAll ?? Props.columns)
    79. // 过滤之后显示的表头
    80. const selectShowColumns = ref<Array<string>>(showCheckboxColumns.value.map((item) => item.dataIndex) as Array<string>)
    81. watch(
    82. () => Props.columnsAll,
    83. (columnsAll) => {
    84. if (columnsAll) {
    85. showCheckboxColumns.value = columnsAll
    86. selectShowColumns.value = showCheckboxColumns.value.map((item) => item.dataIndex) as Array<string>
    87. }
    88. }
    89. )
    90. /**
    91. * 表格展示数据
    92. */
    93. const showData = computed(() => {
    94. return isEmpty(selectShowColumns.value) ? [] : Props.data
    95. })
    96. interface IEmitType {
    97. (e: 'changeColumns', obj: { columns: Array<TableColumnData>; dataIndexs: Array<string> }): void
    98. (e: 'update:columns', columns: Array<TableColumnData>): void
    99. (e: 'update:selectedRowKeys', selectedRowKeys: Array<string>): void
    100. (e: 'update:selectedRows', selectedRowKeys: Array<TableData>): void
    101. (e: 'select', _1: Array<string>, _2: string, _3: TableData, _4: Array<TableData>): void
    102. (e: 'selectAll', isAll: boolean): void
    103. }
    104. const Emits = defineEmits<IEmitType>()
    105. const isShowCustomColumnTitle = computed(() => {
    106. const targetSelectedRowKeys = Props?.selectedRowKeys
    107. if (targetSelectedRowKeys) {
    108. return targetSelectedRowKeys.length > 0
    109. }
    110. return false
    111. })
    112. /**
    113. * 选择一行
    114. */
    115. const handleSelected = (_1: Array<string>, rowKey: string, _3: TableData) => {
    116. const isExistence = selectedKeysCache.value.has(rowKey)
    117. selectedKeysCache.value[isExistence ? 'delete' : 'set'](rowKey, _3)
    118. Emits('update:selectedRowKeys', Array.from(selectedKeysCache.value.keys()))
    119. Emits('update:selectedRows', Array.from(selectedKeysCache.value.values()))
    120. Emits(
    121. 'select',
    122. Array.from(selectedKeysCache.value.keys()),
    123. rowKey,
    124. _3,
    125. Array.from(selectedKeysCache.value.values())
    126. )
    127. }
    128. /**
    129. * 维护 a-table 自身的 selectedRowKeys
    130. */
    131. const selectedRowKeys = ref<string[]>()
    132. watch(
    133. () => Props.selectedRowKeys,
    134. (newVal) => {
    135. selectedRowKeys.value = newVal
    136. // selectedKeysCache.value.clear()
    137. // newVal.map((v) =>
    138. // selectedKeysCache.value.set(
    139. // v,
    140. // Props.data.find((item) => item[Props.rowKey] === v)
    141. // )
    142. // )
    143. },
    144. { immediate: true }
    145. )
    146. /**
    147. * 全选
    148. */
    149. const handleSelectedAll = (isAll) => {
    150. // isAll
    151. // ? Props.data?.forEach((item) => selectedKeysCache.value.add(item[Props.rowKey as string]))
    152. // : selectedKeysCache.value.clear()
    153. if (!isAll) {
    154. Props.data.map((item) => selectedKeysCache.value.delete(item[Props.rowKey as string]))
    155. } else {
    156. Props.data.map((item) => selectedKeysCache.value.set(item[Props.rowKey as string], item))
    157. }
    158. Emits('update:selectedRowKeys', Array.from(selectedKeysCache.value.keys()))
    159. Emits('update:selectedRows', Array.from(selectedKeysCache.value.values()))
    160. Emits('selectAll', isAll)
    161. }
    162. watch(
    163. () => Props.columns,
    164. (newColumns) => {
    165. const targetIndex = newColumns.findIndex((item) => item.customTitle)
    166. const targetColumns = [...newColumns]
    167. customTitleName.value = (targetColumns[targetIndex]?.title ?? '') as string
    168. targetColumns[targetIndex] = {
    169. ...targetColumns[targetIndex],
    170. titleSlotName: 'customTitle'
    171. }
    172. showColumns.value = targetColumns
    173. if (!Props.isShowFliter) {
    174. showCheckboxColumns.value = newColumns
    175. selectShowColumns.value = showCheckboxColumns.value.map((item) => item.dataIndex) as Array<string>
    176. }
    177. },
    178. {
    179. immediate: true
    180. }
    181. )
    182. /**
    183. * 更新 columns
    184. */
    185. watch(selectShowColumns, (newSelectShowColumns) => {
    186. const targetColumns = showCheckboxColumns.value.filter(
    187. (item) => newSelectShowColumns.includes(item?.dataIndex ?? '') || item.isShowFliter === false
    188. )
    189. Emits('update:columns', targetColumns)
    190. Emits('changeColumns', { columns: targetColumns, dataIndexs: newSelectShowColumns })
    191. })
    192. /**
    193. * 列设置动态大小
    194. */
    195. watch(height, () => {
    196. const TABLE_TR = document.querySelector('.main-table-wrapper thead .arco-table-tr') as HTMLElement
    197. box.value = TABLE_TR?.offsetHeight ? TABLE_TR?.offsetHeight - 1 + 'px' : box.value
    198. })
    199. /**
    200. * 暴露给外部的state
    201. */
    202. const clearSelectedKeysCache = () => selectedKeysCache.value.clear()
    203. defineExpose({
    204. clearSelectedKeysCache
    205. })
    206. </script>
    207. <style lang="scss" scoped>
    208. .main-table-wrapper {
    209. position: relative;
    210. .editor-show-columns-btn {
    211. position: absolute;
    212. top: 0px;
    213. right: 0px;
    214. z-index: 1;
    215. display: flex;
    216. justify-content: center;
    217. align-items: center;
    218. width: v-bind(box);
    219. height: v-bind(box);
    220. font-size: 15px;
    221. border: 1px solid #e5e6eb;
    222. background-color: #f2f3f5;
    223. }
    224. .custom-title {
    225. display: flex;
    226. position: absolute;
    227. top: 4px;
    228. min-height: 24px;
    229. z-index: 1;
    230. border-radius: 2px;
    231. width: max-content;
    232. background: #fff;
    233. padding: 2px 4px;
    234. box-shadow: 0 0 2px 0 rgb(31 31 31 / 5%), 0 4px 6px 0 rgb(31 31 31 / 20%);
    235. .forbidden {
    236. cursor: not-allowed;
    237. }
    238. }
    239. }
    240. .editor-show-columns-ckb {
    241. margin: 0 4px;
    242. }
    243. </style>