Vue3封裝ant-design-vue表格的詳細(xì)代碼
Vue3封裝ant-design-vue表格
說明
該文僅僅用來記錄自己使用Vue3基于ant-design-vue開發(fā)的時候?qū)able組建的二次封裝,因?yàn)樵趘ue中,組件不能像react中那樣作為一種JS數(shù)據(jù)類型隨意傳遞,需要使用slot,因此個人認(rèn)為不夠靈活,但是為了解決這個問題就是用插槽對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對話框 -->
<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、表格支持列顯示和隱藏(同時也可以查看AVue,具有相同的功能,AVue 組件已經(jīng)封裝,可直接使用;此處僅供需要情景使用)
第一步
安裝支持vue的可拖動控件
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'
// 注冊組件
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 },
// 是否開啟:單擊行則選中行
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 },
// 是否展示序號列
showIndex: { type: Boolean, default: true },
customCell: { type: Function }
}),
data() {
return {
localLoading: false, // 加載標(biāo)識
localDataSource: [], // 表格源數(shù)據(jù)
localPagination: Object.assign({}, this.pagination), // 分頁對象,合并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'))]
},
// 處理最大顯示長度后的列
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 = []
// 表格添加序號列
if (this.showIndex) {
data.push({
title: '序號',
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)
// 超出后顯示省略號 不支持操作列、和排序一并使用
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ì)算,用于滾動顯示
*/
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 對象屬性: {boolean} isBackToFirstPage 如果參數(shù)為 true, 則強(qiáng)制刷新到第一頁
* 對象屬性: {boolean} isResetOption 如果參數(shù)為 true, 則重置顯隱配置項(xiàng)
* 對象屬性: {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
})
// 對接自己的通用數(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ù)長度為 0 ,自動翻頁到上一頁
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ù)據(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
})
}
},
/**
* 自定義行??梢耘渲帽砀裥械南嚓P(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 = {}
}
// 單擊選中行需要判斷是單選框還是多選框,表格多選或單選框得使用會在后續(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
},
/**
* 對表格設(shè)置width(來避免表頭和內(nèi)容的錯位)
*/
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個字符
// 最后一列默認(rèn)不設(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 DragTableTableOption.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: '測試高級學(xué)校1'},
{ id: 2, name: '李四', sex: '女', age: 16, school: '測試高級學(xué)校2'},
{ id: 3, name: '王五', sex: '男', age: 15, school: '測試高級學(xué)校3'},
{ id: 4, name: '張紅', sex: '女', age: 17, school: '測試高級學(xué)校4'},
{ id: 5, name: '陳平', sex: '男', age: 20, school: '測試高級學(xué)校5'},
]
})
}
}
}
</script>
antdv-基礎(chǔ)表格拖拽
到此這篇關(guān)于Vue3封裝ant-design-vue表格的文章就介紹到這了,更多相關(guān)Vue3封裝ant-design-vue內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue車牌號校驗(yàn)和銀行校驗(yàn)實(shí)戰(zhàn)
這篇文章主要介紹了vue車牌號校驗(yàn)和銀行校驗(yàn)實(shí)戰(zhàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧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請求
這篇文章主要介紹了如何使用vue實(shí)現(xiàn)跨域訪問第三方http請求,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-03-03
vue如何使用html2canvas和JsPDF導(dǎo)出pdf組件
這篇文章主要介紹了vue如何使用html2canvas和JsPDF導(dǎo)出pdf組件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-09-09

