diff --git a/packages/components/table/__tests__/table.test.ts b/packages/components/table/__tests__/table.test.ts index afa9d36ff2..31a34c5728 100644 --- a/packages/components/table/__tests__/table.test.ts +++ b/packages/components/table/__tests__/table.test.ts @@ -1554,4 +1554,53 @@ describe('Table.vue', () => { await doubleWait() expect(wrapper.vm.selected.length).toEqual(3) }) + it('change columns order when use v-for & key to render table', async () => { + const wrapper = mount({ + components: { + ElTable, + ElTableColumn, + }, + template: ` + + + + + `, + data() { + const testData = getTestData() as any + + return { + testData, + columnsData: [ + { label: 'name', prop: 'name' }, + { label: 'release', prop: 'release' }, + { label: 'director', prop: 'director' }, + { label: 'runtime', prop: 'runtime' }, + ], + } + }, + + methods: { + changeColumnData() { + ;[this.columnsData[0], this.columnsData[1]] = [ + this.columnsData[1], + this.columnsData[0], + ] + }, + }, + }) + await doubleWait() + wrapper.find('.change-column').trigger('click') + await doubleWait() + expect(wrapper.find('.el-table__header').findAll('.cell')[0].text()).toBe( + 'release' + ) + expect(wrapper.find('.el-table__header').findAll('.cell')[1].text()).toBe( + 'name' + ) + }) }) diff --git a/packages/components/table/src/store/index.ts b/packages/components/table/src/store/index.ts index 93e8f23453..fe8f2e9c76 100644 --- a/packages/components/table/src/store/index.ts +++ b/packages/components/table/src/store/index.ts @@ -73,7 +73,8 @@ function useStore() { insertColumn( states: StoreStates, column: TableColumnCtx, - parent: TableColumnCtx + parent: TableColumnCtx, + updateColumnOrder: () => void ) { const array = unref(states._columns) let newColumns = [] @@ -89,6 +90,7 @@ function useStore() { } sortColumn(newColumns) states._columns.value = newColumns + states.updateOrderFns.push(updateColumnOrder) if (column.type === 'selection') { states.selectable.value = column.selectable states.reserveSelection.value = column.reserveSelection @@ -99,10 +101,22 @@ function useStore() { } }, + updateColumnOrder(states: StoreStates, column: TableColumnCtx) { + const newColumnIndex = column.getColumnIndex?.() + if (newColumnIndex === column.no) return + + sortColumn(states._columns.value) + + if (instance.$ready) { + instance.store.updateColumns() + } + }, + removeColumn( states: StoreStates, column: TableColumnCtx, - parent: TableColumnCtx + parent: TableColumnCtx, + updateColumnOrder: () => void ) { const array = unref(states._columns) || [] if (parent) { @@ -125,6 +139,9 @@ function useStore() { } } + const updateFnIndex = states.updateOrderFns.indexOf(updateColumnOrder) + updateFnIndex > -1 && states.updateOrderFns.splice(updateFnIndex, 1) + if (instance.$ready) { instance.store.updateColumns() // hack for dynamics remove column instance.store.scheduleLayout() diff --git a/packages/components/table/src/store/watcher.ts b/packages/components/table/src/store/watcher.ts index cf6ffdb3a0..e72a3f37f3 100644 --- a/packages/components/table/src/store/watcher.ts +++ b/packages/components/table/src/store/watcher.ts @@ -60,6 +60,7 @@ function useWatcher() { const leafColumns: Ref[]> = ref([]) const fixedLeafColumns: Ref[]> = ref([]) const rightFixedLeafColumns: Ref[]> = ref([]) + const updateOrderFns: (() => void)[] = [] const leafColumnsLength = ref(0) const fixedLeafColumnsLength = ref(0) const rightFixedLeafColumnsLength = ref(0) @@ -517,6 +518,7 @@ function useWatcher() { leafColumns, fixedLeafColumns, rightFixedLeafColumns, + updateOrderFns, leafColumnsLength, fixedLeafColumnsLength, rightFixedLeafColumnsLength, diff --git a/packages/components/table/src/table-column/index.ts b/packages/components/table/src/table-column/index.ts index e4a5918fe5..d6dcac73d3 100644 --- a/packages/components/table/src/table-column/index.ts +++ b/packages/components/table/src/table-column/index.ts @@ -55,6 +55,7 @@ export default defineComponent({ getPropsData, getColumnElIndex, realAlign, + updateColumnOrder, } = useRender(props as unknown as TableColumnCtx, slots, owner) const parent = columnOrTableParent.value @@ -140,14 +141,16 @@ export default defineComponent({ owner.value.store.commit( 'insertColumn', columnConfig.value, - isSubColumn.value ? parent.columnConfig.value : null + isSubColumn.value ? parent.columnConfig.value : null, + updateColumnOrder ) }) onBeforeUnmount(() => { owner.value.store.commit( 'removeColumn', columnConfig.value, - isSubColumn.value ? parent.columnConfig.value : null + isSubColumn.value ? parent.columnConfig.value : null, + updateColumnOrder ) }) instance.columnId = columnId.value diff --git a/packages/components/table/src/table-column/render-helper.ts b/packages/components/table/src/table-column/render-helper.ts index 17e39459a0..47efa804a3 100644 --- a/packages/components/table/src/table-column/render-helper.ts +++ b/packages/components/table/src/table-column/render-helper.ts @@ -189,6 +189,10 @@ function useRender( return Array.prototype.indexOf.call(children, child) } + const updateColumnOrder = () => { + owner.value.store.commit('updateColumnOrder', instance.columnConfig.value) + } + return { columnId, realAlign, @@ -200,6 +204,7 @@ function useRender( setColumnRenders, getPropsData, getColumnElIndex, + updateColumnOrder, } } diff --git a/packages/components/table/src/table.vue b/packages/components/table/src/table.vue index 08f602d94a..9d2f8a3adf 100644 --- a/packages/components/table/src/table.vue +++ b/packages/components/table/src/table.vue @@ -157,6 +157,7 @@ import TableBody from './table-body' import TableFooter from './table-footer' import useUtils from './table/utils-helper' import useStyle from './table/style-helper' +import useKeyRender from './table/key-render-helper' import defaultProps from './table/defaults' import { TABLE_INJECTION_KEY } from './tokens' import { hColgroup } from './h-helper' @@ -272,6 +273,8 @@ export default defineComponent({ return props.emptyText || t('el.table.emptyText') }) + useKeyRender(table) + return { ns, layout, diff --git a/packages/components/table/src/table/key-render-helper.ts b/packages/components/table/src/table/key-render-helper.ts new file mode 100644 index 0000000000..6d8265091b --- /dev/null +++ b/packages/components/table/src/table/key-render-helper.ts @@ -0,0 +1,27 @@ +import { onMounted, onUnmounted, ref } from 'vue' +import type { Table } from './defaults' + +export default function useKeyRender(table: Table<[]>) { + const observer = ref() + + const initWatchDom = () => { + const el = table.vnode.el + const columnsWrapper = (el as HTMLElement).querySelector('.hidden-columns') + const config = { childList: true, subtree: true } + const updateOrderFns = table.store.states.updateOrderFns + observer.value = new MutationObserver(() => { + updateOrderFns.forEach((fn: () => void) => fn()) + }) + + observer.value.observe(columnsWrapper!, config) + } + + onMounted(() => { + // fix https://github.com/element-plus/element-plus/issues/8528 + initWatchDom() + }) + + onUnmounted(() => { + observer.value?.disconnect() + }) +}