hello world欢迎来到前端的新世界
当前文章系列专栏:前端系列文章
博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错误,感谢大家指出)
感谢大家支持!您的观看就是作者创作的动力
一款专门用来对Vue3表格进行复杂操作的ui组件库,虚拟滚动,普通表格的行拖拽,表格的全屏展示,表格的全键盘操作,禁用编辑等。
官网地址
下载
npm install xe-utils vxe-table
配置在main.js或者main.ts里面
import { App, createApp } from 'vue'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
function useTable (app: App) {
app.use(VXETable)
}
createApp(App).use(useTable).mount('#app')
直接复制
<template>
<div>
<vxe-grid v-bind="gridOptions">
<template #toolbar_buttons>
<vxe-button @click="gridOptions.align = 'left'">居左</vxe-button>
<vxe-button @click="gridOptions.align = 'center'">居中</vxe-button>
<vxe-button @click="gridOptions.align = 'right'">居右</vxe-button>
</template>
</vxe-grid>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { VxeGridProps } from 'vxe-table'
interface RowVO {
id: number
name: string
nickname: string
role: string
sex: string
age: number
address: string
}
const gridOptions = reactive<VxeGridProps<RowVO>>({
border: true,
height: 300,
align: null,
columnConfig: {
resizable: true
},
columns: [
{ type: 'seq', width: 50 },
{ field: 'name', title: 'name' },
{ field: 'sex', title: 'sex' },
{ field: 'address', title: 'Address' }
],
toolbarConfig: {
slots: {
buttons: 'toolbar_buttons'
}
},
data: [
{ id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
{ id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
{ id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
{ id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, address: 'Shenzhen' },
{ id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
{ id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, address: 'Shenzhen' },
{ id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, address: 'Shenzhen' },
{ id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, address: 'Shenzhen' }
]
})
</script>
<template>
<div>
<vxe-toolbar>
<template #buttons>
<vxe-button @click="expandAllEvent">展开所有</vxe-button>
<vxe-button @click="claseExpandEvent">收起所有</vxe-button>
</template>
</vxe-toolbar>
<vxe-table
show-overflow
height="400"
ref="tableRef"
:loading="loading"
:tree-config="{transform: true}"
:scroll-y="{enabled: true, gt: 20}"
:data="tableData">
<vxe-column type="seq" width="200" tree-node></vxe-column>
<vxe-column field="id" title="Id"></vxe-column>
<vxe-column field="name" title="Name"></vxe-column>
</vxe-table>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { VxeTableInstance } from 'vxe-table'
interface RowVO {
id: number
parentId: number | null
name: string
}
const tableRef = ref<VxeTableInstance<RowVO>>()
const loading = ref(false)
const tableData = ref<RowVO[]>([])
const loadList = () => {
loading.value = true
fetch('/resource/json/provinces_list.json').then(res => res.json()).then((data: RowVO[]) => {
tableData.value = data
loading.value = false
})
}
const expandAllEvent = () => {
const $table = tableRef.value
if ($table) {
$table.setAllTreeExpand(true)
}
}
const claseExpandEvent = () => {
const $table = tableRef.value
if ($table) {
$table.clearTreeExpand()
}
}
loadList()
</script>
template
<vxe-toolbar :refresh="{query: findList}">
<template #buttons>
<vxe-button>
<template #default>新增操作</template>
<template #dropdowns>
<vxe-button type="text" @click="insertEvent(null)">从第一行插入</vxe-button>
<vxe-button type="text" @click="insertEvent(-1)">从最后插入</vxe-button>
<vxe-button type="text" @click="insertEvent($refs.xTable.getData(100))">插入到 100 行</vxe-button>
<vxe-button type="text" @click="insertEvent($refs.xTable.getData(400))">插入到 400 行</vxe-button>
</template>
</vxe-button>
<vxe-button>
<template #default>删除操作</template>
<template #dropdowns>
<vxe-button type="text" @click="$refs.xTable.removeCheckboxRow()">删除选中</vxe-button>
<vxe-button type="text" @click="$refs.xTable.remove($refs.xTable.getData(0))">删除第一行</vxe-button>
<vxe-button type="text" @click="$refs.xTable.remove($refs.xTable.getData($refs.xTable.getData().length - 1))">删除最后一行</vxe-button>
<vxe-button type="text" @click="$refs.xTable.remove($refs.xTable.getData(100))">删除第 100 行</vxe-button>
</template>
</vxe-button>
<vxe-button>
<template #default>校验操作</template>
<template #dropdowns>
<vxe-button type="text" @click="validEvent">快速校验</vxe-button>
<vxe-button type="text" @click="fullValidEvent">完整快速校验</vxe-button>
<vxe-button type="text" @click="selectValidEvent">选中行校验</vxe-button>
</template>
</vxe-button>
<vxe-button @click="getInsertEvent">获取新增</vxe-button>
<vxe-button @click="getRemoveEvent">获取删除</vxe-button>
<vxe-button @click="getUpdateEvent">获取修改</vxe-button>
<vxe-button>
<template #default>滚动操作</template>
<template #dropdowns>
<vxe-button type="text" @click="$refs.xTable.scrollToRow($refs.xTable.getData(10))">滚动到第 10 行</vxe-button>
<vxe-button type="text" @click="$refs.xTable.scrollToRow($refs.xTable.getData(400))">滚动第 400 行</vxe-button>
<vxe-button type="text" @click="$refs.xTable.scrollToColumn($refs.xTable.getColumns(1))">滚动第 1 列</vxe-button>
<vxe-button type="text" @click="$refs.xTable.scrollToColumn($refs.xTable.getColumns(10))">滚动第 10 列</vxe-button>
</template>
</vxe-button>
</template>
</vxe-toolbar>
<vxe-table
border
show-overflow
keep-source
ref="xTable"
height="300"
:column-config="{resizable: true}"
:loading="demo1.loading"
:edit-rules="demo1.validRules"
:mouse-config="{selected: true}"
:edit-config="{trigger: 'dblclick', mode: 'cell', showStatus: true}"
:keyboard-config="{isArrow: true, isDel: true, isEnter: true, isTab: true, isEdit: true}">
<vxe-column type="checkbox" width="60"></vxe-column>
<vxe-column type="seq" width="100"></vxe-column>
<vxe-column field="name" title="Name" sortable width="200" :edit-render="{autofocus: '.vxe-input--inner'}">
<template #edit="scope">
<vxe-input v-model="scope.row.name" type="text" @change="$refs.xTable.updateStatus(scope)"></vxe-input>
</template>
</vxe-column>
<vxe-column field="age" title="Age" width="200" :edit-render="{autofocus: '.vxe-input--inner'}">
<template #edit="scope">
<vxe-input v-model="scope.row.age" type="text" @change="$refs.xTable.updateStatus(scope)"></vxe-input>
</template>
</vxe-column>
<vxe-column field="sex" title="Sex" width="200" :edit-render="{autofocus: '.vxe-input--inner'}">
<template #edit="scope">
<vxe-input v-model="scope.row.sex" type="text" @change="$refs.xTable.updateStatus(scope)"></vxe-input>
</template>
</vxe-column>
<vxe-column field="rate" title="Rate" width="200"></vxe-column>
<vxe-column field="region" title="Region" width="200"></vxe-column>
<vxe-column field="time" title="Time" width="200"></vxe-column>
<vxe-column field="address" title="Address" width="300" show-overflow></vxe-column>
<vxe-column field="updateTime" title="UpdateTime" width="200"></vxe-column>
<vxe-column field="createTime" title="CreateTime" width="200"></vxe-column>
</vxe-table>
script
import { defineComponent, reactive, ref } from 'vue'
import { VXETable, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'
export default defineComponent({
setup () {
const xTable = ref<VxeTableInstance>()
const demo1 = reactive({
loading: false,
validRules: {
name: [
{ required: true, message: 'app.body.valid.rName' },
{ min: 3, max: 50, message: '名称长度在 3 到 50 个字符' }
],
sex: [
{ required: true, message: '性别必须填写' }
]
} as VxeTablePropTypes.ValidConfig
})
const mockList = (size: number) => {
const list: any[] = []
for (let index = 0; index < size; index++) {
list.push({
checked: false,
name: `名称${index}`,
sex: '0',
num: 123,
age: 18,
num2: 234,
rate: 3,
address: 'shenzhen'
})
}
return list
}
const findList = () => {
demo1.loading = true
return new Promise(resolve => {
setTimeout(() => {
const tableData = mockList(600)
// 阻断 vue 对大数组的监听,避免 vue 绑定大数据造成短暂的卡顿
const $table = xTable.value
if ($table) {
$table.loadData(tableData)
}
resolve(null)
demo1.loading = false
}, 300)
})
}
const validEvent = async () => {
const $table = xTable.value
const errMap = await $table.validate()
if (errMap) {
VXETable.modal.message({ status: 'error', content: '校验不通过!' })
} else {
VXETable.modal.message({ status: 'success', content: '校验成功!' })
}
}
const fullValidEvent = async () => {
const $table = xTable.value
const errMap = await $table.fullValidate()
if (errMap) {
const msgList: string[] = []
Object.values(errMap).forEach((errList) => {
errList.forEach(params => {
const { rowIndex, column, rules } = params
rules.forEach(rule => {
msgList.push(`第 ${rowIndex + 1} 行 ${column.title} 校验错误:${rule.message}`)
})
})
})
VXETable.modal.message({
status: 'error',
slots: {
default () {
return [
<div class="red" style="max-height: 400px;overflow: auto;">
{
msgList.map(msg => {
return <div>{ msg }</div>
})
}
</div>
]
}
}
})
} else {
VXETable.modal.message({ status: 'success', content: '校验成功!' })
}
}
const selectValidEvent = async () => {
const $table = xTable.value
const selectRecords = $table.getCheckboxRecords()
if (selectRecords.length > 0) {
const errMap = await $table.validate(selectRecords).catch(errMap => errMap)
if (errMap) {
VXETable.modal.message({ status: 'error', content: '校验不通过!' })
} else {
VXETable.modal.message({ status: 'success', content: '校验成功!' })
}
} else {
VXETable.modal.message({ status: 'warning', content: '未选中数据!' })
}
}
const insertEvent = (row: any) => {
const $table = xTable.value
const record = {
checked: false
}
$table.insertAt(record, row).then(({ row }) => {
$table.setEditRow(row)
})
}
const getInsertEvent = () => {
const $table = xTable.value
const insertRecords = $table.getInsertRecords()
VXETable.modal.alert(insertRecords.length)
}
const getRemoveEvent = () => {
const $table = xTable.value
const removeRecords = $table.getRemoveRecords()
VXETable.modal.alert(removeRecords.length)
}
const getUpdateEvent = () => {
const $table = xTable.value
const updateRecords = $table.getUpdateRecords()
VXETable.modal.alert(updateRecords.length)
}
findList()
return {
xTable,
demo1,
findList,
validEvent,
fullValidEvent,
selectValidEvent,
insertEvent,
getInsertEvent,
getRemoveEvent,
getUpdateEvent
}
}
})
创作不易,要是本文章对广大读者有那么一点点帮助 不妨三连支持一下,您的鼓励就是博主创作的动力