Vue3封裝ant-design-vue表格的詳細(xì)代碼
Vue3封裝ant-design-vue表格
說明
該文僅僅用來記錄自己使用Vue3基于ant-design-vue開發(fā)的時(shí)候?qū)able組建的二次封裝,因?yàn)樵趘ue中,組件不能像react中那樣作為一種JS數(shù)據(jù)類型隨意傳遞,需要使用slot,因此個(gè)人認(rèn)為不夠靈活,但是為了解決這個(gè)問題就是用插槽對(duì)ant-design-vue的Table做了二次封裝,封裝后使用非常靈活:
封裝代碼
<template> <Table :row-key="rowKey" :row-selection="rowSelection" :pagination="pagination" :scroll="{ x: 'auto', y: scrollY }" :columns="columns" :loading="loading" :data-source="dataSource" > <template v-slot:headerCell="{ column }"> <span class="title2" :style="{ whiteSpace: 'nowrap', fontWeight: 'normal' }" >{{ $t(column.title as string) }}</span > </template> <template v-slot:bodyCell="{ column, record }"> <template v-for="slotName of slots"> <slot v-if="slotName === column.dataIndex" :name="slotName" :column="column" :record="record" ></slot> </template> <span v-if="!slots.includes(column.dataIndex as string)">{{ parseDefaultValue(record, column.dataIndex as string) }}</span> </template> </Table> </template> <script lang="ts" setup> import { Table, TablePaginationConfig } from "ant-design-vue"; import { TableColumns } from "@/models/base.model"; import { isNull } from "@/util"; import { TableRowSelection } from "ant-design-vue/es/table/interface"; const { columns, dataSource, slots = [], pagination = false, scrollY, rowSelection = undefined, rowKey, loading, } = defineProps<{ columns: TableColumns[]; pagination?: false | TablePaginationConfig; dataSource: any[]; slots?: string[]; scrollY?: number; rowSelection?: TableRowSelection; rowKey?: string; loading?: boolean; }>(); const parseDefaultValue = (record: Record<string, any>, dataIndex: string) => { const dataIndexs = dataIndex.split("."); let result = record; dataIndexs.forEach((element) => { if (result) { result = result[element]; } }); if (isNull(result)) { return "-"; } return result; }; </script>
使用
<script lang="ts" setup> import VlanConfig from "@/views/VlanConfig.vue"; import { Button, Input, InputNumber, message, Modal } from "ant-design-vue"; import { reactive, watch } from "vue"; import vlanonfigController from "@/controllers/vlanConfig.controller"; import useDataFetch from "@/hooks/useDataFetch"; import CommonTable from "../common/CommonTable.vue"; import { NoPaddingTableColumns, TableColumns } from "@/models/base.model"; import Iconfont from "../layouts/Iconfont.vue"; import { TableRowSelection } from "ant-design-vue/es/table/interface"; import { VlanInfo } from "@/models/vlanConfig.model"; import { $deleteConfirm } from "@/util"; import EditButtons from "../common/EditButtons.vue"; import { useI18n } from "vue-i18n"; enum OperationType { EDIT, DELETE, } const { t } = useI18n(); const data = useDataFetch(vlanonfigController.getVlanList, true); const state = reactive({ selectedVlanIds: [], onOperationVlan: undefined as VlanInfo, operationType: null as OperationType, addModalOpen: false, confirmLoading: false, editData: { vlan_id: undefined, vlan_name: undefined, }, }); const handleDelete = (vlan: VlanInfo) => { state.onOperationVlan = vlan; state.operationType = OperationType.DELETE; $deleteConfirm({ title: t("vlan.deleteVlanTitle", { name: vlan.vlan_name }), content: t("deleteContent"), onOk() { return new Promise<void>((resolve) => { setTimeout(() => { resolve(); }, 1000); }); }, }); }; const restoreEditData = () => { state.editData = { vlan_id: undefined, vlan_name: undefined }; }; const handleEdit = (vlan: VlanInfo) => { state.operationType = OperationType.EDIT; restoreEditData(); state.onOperationVlan = vlan; }; const handleSelectChange: TableRowSelection["onSelect"] = (ids: number[]) => { console.log("in"); state.selectedVlanIds = ids; }; const columns = [ new TableColumns("vlan.vlanId", "vlan_id"), new TableColumns("vlan.vlanName", "vlan_name"), new NoPaddingTableColumns("", "operation", undefined, 240), ]; const deleteDisabled = $computed(() => !state.selectedVlanIds.length); const handleMultiDelete = () => { console.log(state.selectedVlanIds); }; const handleEditOk = (vlan: VlanInfo) => { state.onOperationVlan = undefined; data.setEditDataToOriginData(); }; const handleEditCancel = (vlan: VlanInfo) => { state.onOperationVlan = undefined; data.resetData(); console.log("cancel"); }; const checkOperationDisabled = (id: string) => { return ( state.onOperationVlan?.nanoid === id && state.operationType === OperationType.EDIT ); }; const handleAddVlanClick = () => { state.addModalOpen = true; }; const hanldeAddVlanCancel = () => { state.addModalOpen = false; restoreEditData(); }; const hanldeAddVlanOk = () => { const { vlan_id, vlan_name } = state.editData; if (!vlan_id || !vlan_name) { message.error(t("vlan.addError")); return; } state.confirmLoading = true; return new Promise<void>((resolve) => { setTimeout(() => { resolve(); data.refresh(); hanldeAddVlanCancel(); state.confirmLoading = false; }, 1000); }); }; const isEdit = $computed(() => state.operationType === OperationType.EDIT); </script> <template> <VlanConfig> <template #rightExtra> <div style="bottom: 12px" class="flex-start relative-position"> <Button :disabled="deleteDisabled" @click="handleMultiDelete" danger type="primary" >{{ $t("vlan.deleteVlan") }}</Button > <Button @click="handleAddVlanClick" :style="{ marginLeft: '16px' }" type="primary" >{{ $t("vlan.addVlan") }}</Button > </div> </template> <CommonTable :row-key="'nanoid'" :rowSelection="{ selectedRowKeys: state.selectedVlanIds, onChange: handleSelectChange, }" :slots="['operation', 'vlan_id', 'vlan_name']" :dataSource="data.clonedData.value" :columns="columns" > <template #vlan_id="{ record }"> <div v-if="isEdit && record.nanoid === state.onOperationVlan?.nanoid" class="flex-start" > <InputNumber style="margin-right: 8px" v-model:value="record.vlan_id" ></InputNumber> <EditButtons @ok="handleEditOk(record as VlanInfo)" @cancel="handleEditCancel(record as VlanInfo)" /> </div> </template> <template #vlan_name="{ record }"> <div v-if="isEdit && record.nanoid === state.onOperationVlan?.nanoid" class="flex-start" > <Input style="width: 200px; margin-right: 8px" v-model:value="record.vlan_name" ></Input> <EditButtons @ok="handleEditOk(record as VlanInfo)" @cancel="handleEditCancel(record as VlanInfo)" /> </div> </template> <template #operation="{ record }"> <div class="flex-start flex-nowrap"> <Button type="text" :disabled="checkOperationDisabled(record.nanoid)" @click="() => handleEdit(record as VlanInfo)" class="flex" > <Iconfont icon="ic_edit" :disabled="checkOperationDisabled(record.nanoid)" :primary="!checkOperationDisabled(record.nanoid)" ></Iconfont> <span :class="{ 'primary-color': !checkOperationDisabled(record.nanoid), }" >{{ $t("edit") }}</span > </Button> <Button type="text" @click="() => handleDelete(record as VlanInfo)" class="flex" > <Iconfont icon="ic_edit" primary></Iconfont> <span class="primary-color">{{ $t("delete") }}</span> </Button> </div> </template> </CommonTable> </VlanConfig> <!-- 添加vlan對(duì)話框 --> <Modal :width="400" @cancel="hanldeAddVlanCancel" @ok="hanldeAddVlanOk" centered :title="$t('vlan.addVlan')" :confirmLoading="state.confirmLoading" :open="state.addModalOpen" > <div style="padding: 24px 0 16px"> <div class="flex-btw flex-nowrap" :style="{ marginBottom: '24px' }"> <span class="title1 white-s-nowrap">{{ $t("vlan.vlanId") }}</span> <InputNumber :min="1" :max="4093" v-model:value="state.editData.vlan_id" style="width: 264px" ></InputNumber> </div> <div class="flex-btw flex-nowrap"> <span class="title1 white-s-nowrap">{{ $t("vlan.vlanName") }}</span> <Input v-model:value="state.editData.vlan_name" style="width: 264px" ></Input> </div> </div> </Modal> </template> <style scoped lang="scss"></style>
ant-design-vue Table封裝
封裝表格主要功能:
1、表格加載(源數(shù)據(jù)支持?jǐn)?shù)組和接口方法傳遞)
2、表格分頁
3、表格伸縮列
4、支持單擊選中行
5、表格支持列顯示和隱藏(同時(shí)也可以查看AVue,具有相同的功能,AVue 組件已經(jīng)封裝,可直接使用;此處僅供需要情景使用)
第一步
安裝支持vue的可拖動(dòng)控件
npm install vue-draggable-resizable -S
第二步
利用ant和vue-draggable-resizeable封裝自己的表格
Table.js如下
import { Table } from 'ant-design-vue' import Vue from 'vue' // 引入vue-draggable-resizable,用于表格列伸縮 import VueDraggableResizable from 'vue-draggable-resizable' // TableOption用于表格列顯示或隱藏 import TableOption from './TableOption' // 注冊(cè)組件 Vue.component('vue-draggable-resizable', VueDraggableResizable) Vue.component('table-option', TableOption) const componentName = 'drag-table' const DragTable = { name: componentName, props: Object.assign({}, Table.props, { // 返回 Promise<{ currPage, totalCount, list: any[] }> 的獲取數(shù)據(jù)的函數(shù),用于內(nèi)部管理數(shù)據(jù)加載 data: { type: Function }, // 是否開啟:?jiǎn)螕粜袆t選中行 selectOnClick: { type: Boolean, default: true }, // 默認(rèn)翻到第 1 頁 pageNum: { type: Number, default: 1 }, // 默認(rèn)分頁大小 10 行 pageSize: { type: Number, default: 10 }, // 是否顯示分頁大小切換下拉框 showSizeChanger: { type: Boolean, default: true }, // 是否顯示分頁器 showPagination: { type: [String, Boolean], default: 'auto' }, // 指定表格當(dāng)前頁數(shù)的url 例如:/users/2 pageURI: { type: Boolean, default: false }, // 是否展示序號(hào)列 showIndex: { type: Boolean, default: true }, customCell: { type: Function } }), data() { return { localLoading: false, // 加載標(biāo)識(shí) localDataSource: [], // 表格源數(shù)據(jù) localPagination: Object.assign({}, this.pagination), // 分頁對(duì)象,合并ant默認(rèn)分頁數(shù)據(jù) localScroll: {}, // 表格列顯隱 filterValue: [], originColumns: [] } }, computed: { localKeys() { return [...Object.keys(this.$data), ...Object.keys(this._computedWatchers), ...Object.keys(this).filter(k => k.startsWith('local'))] }, // 處理最大顯示長(zhǎng)度后的列 localColumns(){ return this.originColumns.filter(col => !this.filterValue.includes(col.dataIndex || col.key || col.title)) }, // 表格伸縮列(該屬性是ant表格中覆蓋默認(rèn)的 table 元素的屬性components) localComponents(){ const headerComponent = {} headerComponent.header ={} headerComponent.header.cell = (h, props, children) => { const { key, ...restProps } = props const col = this.columns.find(col => { const k = col.dataIndex || col.key return k === key }) if (!col) { return h('th', { ...restProps }, [...children]) } const dragProps = { key: col.dataIndex || col.key, class: 'table-draggable-handle', attrs: { w: 8, x: parseFloat(col.width), z: 1, axis: 'x', draggable: true, resizable: false, onDragStart: (e) => { e.stopPropagation() } }, on: { dragging: (x) => { col.width = Math.max(x, 35) this.computeWidth() } } } const drag = h('vue-draggable-resizable', { ...dragProps }) return <th {...restProps} title={col.title} width={col.width} class="resize-table-th"> {children} { drag } </th> } return headerComponent } }, watch: { loading(val) { this.localLoading = val }, // 表格源數(shù)據(jù) dataSource: { handler(val) { this.localDataSource = val }, immediate: true }, 'localPagination.current'(val) { this.pageURI && this.$router.push({ ...this.$route, params: Object.assign({}, this.$route.params, { pageNo: val }) }) }, pageNum(val) { Object.assign(this.localPagination, { current: val }) }, pageSize(val) { Object.assign(this.localPagination, { pageSize: val }) }, showSizeChanger(val) { Object.assign(this.localPagination, { showSizeChanger: val }) }, scroll() { this.calcLocalScroll() }, columns: { handler(val) { const data = [] // 表格添加序號(hào)列 if (this.showIndex) { data.push({ title: '序號(hào)', dataIndex: 'sort', width: 50, customRender: (text, record, index) => record.total ? record.total : `${(this.localPagination.current - 1) * (this.localPagination.pageSize) + (index + 1) || (index + 1)}` }) } this.originColumns = data.concat(val) // 超出后顯示省略號(hào) 不支持操作列、和排序一并使用 this.originColumns.forEach((col)=>{ if(col.dataIndex || col.key) { col.ellipsis = true } }) }, immediate: true } }, created() { // 判斷格是傳進(jìn)數(shù)據(jù)源還是遠(yuǎn)程數(shù)據(jù)接口方法 if (this.data) { // 合并分頁數(shù)據(jù) const { pageNo } = this.$route.params const localPageNum = this.pageURI ? (pageNo && parseInt(pageNo)) : this.pageNum this.localPagination = ['auto', true].includes(this.showPagination) ? Object.assign({}, this.localPagination, { showQuickJumper: true, current: localPageNum, pageSize: this.pageSize, showSizeChanger: this.showSizeChanger, pageSizeOptions: ['10', '20', '40', '80', '120'] }) : false // 調(diào)用接口獲得數(shù)據(jù) this.loadData() } else { // 源數(shù)據(jù)傳入不支持分頁 this.localPagination = false } window.addEventListener('resize', this.calcLocalScroll) }, mounted() { setTimeout(() => { this.calcLocalScroll() this.resetColumns() }) }, destroyed() { window.removeEventListener('resize', this.calcLocalScroll) }, methods: { /** * 表格限制最大寬度/高度計(jì)算,用于滾動(dòng)顯示 */ calcLocalScroll() { const localScroll = { ...(this.scroll || {}) } // 根據(jù)自己的頁面計(jì)算除表格外其他組件占據(jù)的高度,從而得出表格最大高度,也可自適應(yīng)顯示表格 const extraDis = (this.$store.getters.multiTab ? 40 : 0 ) + 56 + 104 + (this.pagination ? 6 : 0) + (this.$scopedSlots.footer ? 33 : 0) localScroll.x = localScroll.x || this.$el.offsetWidth - 20 localScroll.y = localScroll.y || document.body.clientHeight - ((this.$el || {}).offsetTop || 128) - extraDis this.localScroll = localScroll // 計(jì)算表格列寬度 this.computeWidth() }, /** * 表格重新加載方法 *@param {object} option 對(duì)象屬性: {boolean} isBackToFirstPage 如果參數(shù)為 true, 則強(qiáng)制刷新到第一頁 * 對(duì)象屬性: {boolean} isResetOption 如果參數(shù)為 true, 則重置顯隱配置項(xiàng) * 對(duì)象屬性: {boolean} layoutTag 如果參數(shù)為 true, 則重新計(jì)算表格限制最大寬度/高度 */ refresh({ isBackToFirstPage = false, isResetOption = false, layoutTag = false } = { isBackToFirstPage: false, isResetOption: false, layoutTag: false }) { if(layoutTag) { this.calcLocalScroll() } else { isResetOption && this.resetColumns() isBackToFirstPage && (this.localPagination = Object.assign({}, { current: 1, pageSize: this.pageSize })) this.loadData() } }, /** * 加載數(shù)據(jù)方法 * @param {{ page: number, limit: number }} pagination 分頁選項(xiàng)器 * @param {{ [field: string]: string }} filters 過濾條件 * @param {{ field: string, order: 'asc' | 'desc' }} sorter 排序條件 */ loadData(pagination, filters, sorter = {}) { this.localLoading = true const result = this.data({ page: (pagination && pagination.current) || this.showPagination && this.localPagination.current || this.pageNum, limit: (pagination && pagination.pageSize) || this.showPagination && this.localPagination.pageSize || this.pageSize, sidx: sorter.field, order: sorter.order && sorter.order.slice(0, sorter.order.length - 3), ...filters }) // 對(duì)接自己的通用數(shù)據(jù)接口需要修改下方代碼中的 r.currPage, r.totalCount, r.list if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') { result.then(r => { r = r || { currPage: 1, totalCount: 0, list: [] } this.localPagination = this.showPagination ? Object.assign({}, this.localPagination, { showQuickJumper: true, current: r.currPage, // 返回結(jié)果中的當(dāng)前分頁數(shù) total: r.totalCount, // 返回結(jié)果中的總記錄數(shù) showSizeChanger: this.showSizeChanger, pageSize: (pagination && pagination.pageSize) || this.localPagination.pageSize }) : false // 為防止刪除數(shù)據(jù)后導(dǎo)致頁面當(dāng)前頁面數(shù)據(jù)長(zhǎng)度為 0 ,自動(dòng)翻頁到上一頁 if (r.list.length === 0 && this.showPagination && this.localPagination.current > 1) { this.localPagination.current-- this.loadData() return } // 這里用于判斷接口是否有返回 r.totalCount 且 this.showPagination = true 且 pageNo 和 pageSize 存在 且 totalCount 小于等于 pageNo * pageSize 的大小 // 當(dāng)情況滿足時(shí),表示數(shù)據(jù)不滿足分頁大小,關(guān)閉 table 分頁功能 try { if ((['auto', true].includes(this.showPagination) && r.totalCount <= (r.pageNo * this.localPagination.pageSize))) { this.localPagination.hideOnSinglePage = true } } catch (e) { this.localPagination = false } this.localDataSource = r.list // 返回結(jié)果中的數(shù)組數(shù)據(jù) this.localLoading = false }) } }, /** * 自定義行。可以配置表格行的相關(guān)事件,此處主要定義表格單擊選中行,沒有復(fù)選框或者單選框得表格可以屏蔽該功能 * @param {*} record */ localCustomRow(record) { const rowCustomer = this.customRow ? this.customRow(record) : {} if (!this.selectOnClick || !this.rowSelection) { return rowCustomer } if (!rowCustomer.on) { rowCustomer.on = {} } // 單擊選中行需要判斷是單選框還是多選框,表格多選或單選框得使用會(huì)在后續(xù)發(fā)文章補(bǔ)充。 const selectOnClickHandler = () => { const { type, selectedRowKeys } = this.rowSelection if (selectedRowKeys.includes(record[this.rowKey]) && !type) { this.rowSelection.selections.splice(this.rowSelection.selections.findIndex(r => r === record), 1) selectedRowKeys.splice(selectedRowKeys.findIndex(r => r === record[this.rowKey]), 1) } else if(!type) { this.rowSelection.selections.push(record) selectedRowKeys.push(record[this.rowKey]) } else { this.rowSelection.selectedRow = record selectedRowKeys.splice(0, 1, record[this.rowKey]) } } if (rowCustomer.on.click) { const originalClickHandler = rowCustomer.on.click rowCustomer.on.click = e => { originalClickHandler(e) selectOnClickHandler(e, record) } } else { rowCustomer.on.click = selectOnClickHandler } return rowCustomer }, /** * 對(duì)表格設(shè)置width(來避免表頭和內(nèi)容的錯(cuò)位) */ computeWidth() { const fullWidth = (this.localScroll.x || this.$el?.offsetWidth) - (this.rowSelection ? 60 : 0) if(!isNaN(fullWidth) && fullWidth >= 0) { const remain = this.originColumns.reduce((obj, col) => { if(!this.filterValue.includes(col.dataIndex || col.key)) { if(col.width) { obj.colWidthSum =obj.colWidthSum - (typeof width === 'string' && col.width.endsWith('%') ? parseFloat(col.width) * fullWidth / 100 : parseFloat(col.width)) } else { obj.noWidthColCount += 1 } } return obj }, {colWidthSum: fullWidth, noWidthColCount: 0}) // 平均寬度 const averageWidth = remain.colWidthSum / remain.noWidthColCount const lastIndex = this.originColumns.length - ( this.originColumns[this.originColumns.length-1].fixed ? 2 : 1) // 設(shè)置默認(rèn)列寬,最少顯示為7個(gè)字符 // 最后一列默認(rèn)不設(shè)置寬度,避免列寬改變時(shí)影響其他列 this.originColumns.forEach((col,index) => { if(index !== lastIndex && averageWidth !== Infinity && !col.width) { Vue.set(col, 'width', averageWidth > 150 ? averageWidth : 150) remain.colWidthSum = remain.colWidthSum - (averageWidth > 150 ? averageWidth : 150) } else if(index === lastIndex) { const minWidth = col.width || 150 remain.colWidthSum = (remain.colWidthSum + (col.width || 0)).toFixed() Vue.set(col, 'width', remain.colWidthSum < minWidth ? minWidth : undefined) } }) } }, /** * 表格列重置,主要使用在數(shù)據(jù)使用數(shù)據(jù)數(shù)組的表格 */ resetColumns() { this.filterValue = [] this.filterShow = !this.filterShow } }, // 渲染表格方法 render(h) { const props = {} // 表格屬性 Object.keys(Table.props).forEach(k => { const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}` // if(k === 'columns'){} if (this.localKeys.includes(localKey)) { props[k] = this[localKey] } else if (this[k] != null) { props[k] = this[k] } }) const on = { ...this.$listeners } this.data && (on.change = this.loadData) return ( <div class={`${componentName}-wrapper`} style="position: relative;">{[ props.showHeader && h('table-option', { ref: 'tableOption', style: { float: 'right', marginTop:'-25px', marginRight: '5px' }, props: { columns: this.originColumns, noCheckedValues: this.filterValue }, on: { filter: (noCheckedValues) => this.filterValue = noCheckedValues } }), h('a-table', { props, on, scopedSlots: { ...this.$scopedSlots } }, Object.keys(this.$slots).map(name => ( <template slot={name}>{this.$slots[name]}</template> )) ) ]} </div> ) } } export default DragTable
TableOption.vue組件
<template> <div> <a-tooltip placement="leftTop" title="表格列顯示配置"> <a-button @click="handleClick" class="optionBtn"><a-icon type="table" /></a-button> </a-tooltip> <div v-if="visible" class="table-select"> <a-checkbox :checked="options.length === checkedValues.length" @change="onCheckAllChange" > 全選/反選 </a-checkbox> <a-checkbox-group :options="options" v-model="checkedValues" @change="selectChange" /> </div> </div> </template> <script> const componentName = 'ebig-table-option' const TableOption= { name: componentName, props: { columns: { type: Array, default: ()=>([])}, noCheckedValues: { type:Array, default: ()=>([]) } }, data() { return { checkedValues: [], visible: false } }, watch: { noCheckedValues: { handler(val) { this.checkedValues = this.options.filter(col => !val.includes(col.value)).map(c => c.value) }, immediate: true } }, computed: { options() { return this.columns.map(col => { const key = col.dataIndex || col.key return { label: col.title || col.slots.title, value: key + '' } }) }, allKeys: vm => vm.options.map(o => o.value) }, methods: { handleClick() { this.visible = !this.visible }, onCheckAllChange(e) { this.checkedValues = e.target.checked ? this.allKeys : [] const noCheckedValues = e.target.checked ? [] : this.allKeys this.$emit('filter', noCheckedValues) }, selectChange(checkedValues) { const noCheckedValues = this.allKeys.filter(key => !checkedValues.includes(key)) this.$emit('filter', noCheckedValues) } } } export default TableOption </script> <style lang="less"> .optionBtn { padding: 0 4px !important; height: auto !important; opacity: 0.4; &:hover { opacity: 1; } } .ant-checkbox-group-item + .ant-checkbox-group-item { display: block } .table-select { position: absolute; background:#fff; border:1px solid #ecedef; top: 5px; right: 0; z-index: 100000; padding: 10px 0 10px 10px; width: 180px; max-height: 100%; overflow: auto; &::-webkit-scrollbar { width: 5px; } &::-webkit-scrollbar-thumb { border-radius: 8px; background-color: rgb(177, 175, 175); } &::-webkit-scrollbar-thumb:hover { border-radius: 10px; background-color: #22212177; } } </style>
使用
表格使用案例
<template> <a-card style="paddingTop: 50px"> <drag-table ref="table" size="small" row-key="id" :columns="columns" :data="loadData" /> </a-card> </template> <script> import DragTable from './Table' export default { name: 'drag-table-example', components: { DragTable }, data() { return { columns: [ { dataIndex: 'name', title: '姓名' }, { dataIndex: 'sex', title: '性別' }, { dataIndex: 'age', title: '年齡' }, { dataIndex: 'school', title: '學(xué)校' } ], dataSource: [] } }, methods: { loadData() { return Promise.resolve({ currPage: 1, pageSize: 10, totalCount: 9, totalPage: 1, list: [ { id: 1, name: '張三', sex: '男', age: 18, school: '測(cè)試高級(jí)學(xué)校1'}, { id: 2, name: '李四', sex: '女', age: 16, school: '測(cè)試高級(jí)學(xué)校2'}, { id: 3, name: '王五', sex: '男', age: 15, school: '測(cè)試高級(jí)學(xué)校3'}, { id: 4, name: '張紅', sex: '女', age: 17, school: '測(cè)試高級(jí)學(xué)校4'}, { id: 5, name: '陳平', sex: '男', age: 20, school: '測(cè)試高級(jí)學(xué)校5'}, ] }) } } } </script>
antdv-基礎(chǔ)表格拖拽
到此這篇關(guān)于Vue3封裝ant-design-vue表格的文章就介紹到這了,更多相關(guān)Vue3封裝ant-design-vue內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue車牌號(hào)校驗(yàn)和銀行校驗(yàn)實(shí)戰(zhàn)
這篇文章主要介紹了vue車牌號(hào)校驗(yàn)和銀行校驗(yàn)實(shí)戰(zhàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01如何在 Vue3 中使用 OpenLayers 實(shí)現(xiàn)事件 loadst
在這篇文章中,我將詳細(xì)介紹如何在 Vue3 + OpenLayers 中監(jiān)聽 loadstart 和 loadend 事件,并通過 Vue3 Composition API 進(jìn)行代碼優(yōu)化,使其更加高效、健壯,感興趣的朋友一起看看吧2025-04-04如何使用vue實(shí)現(xiàn)跨域訪問第三方http請(qǐng)求
這篇文章主要介紹了如何使用vue實(shí)現(xiàn)跨域訪問第三方http請(qǐng)求,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03vue如何使用html2canvas和JsPDF導(dǎo)出pdf組件
這篇文章主要介紹了vue如何使用html2canvas和JsPDF導(dǎo)出pdf組件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09