Vxe-Table开发中的各种坑以及避坑指南
作者:小狼子丶
背景:
由于公司要开发erp,采用了element-plus做为UI基础框架,但是回想往事点点滴滴,element-ui表格的种种表现令人痛心,于是跟leader商量之后决定使用Vxe-Table做表格插件,虽然element-plus在表格上也在大力优化,但就目前来看可用度确实不高,刚出了一个虚拟滚动,但看上去确实让人有点心急。。。
开发阶段遇到的各种问题
全局size的问题
有点扯犊子的事,我element-plus要做全局的size修改,那就意味着我的表格也要做全局的size修改,庆幸的是它有自带的全局size配置,配置方法也很简单,在setup方法中设置即可,配合vuex、本地存储(包括cookie),还有模有样的可以搞一搞,不幸的是,这特么size跟element-plus的size规则天差地别,虽然可以通过修改变量去规避这个问题,但是成本属实有点高。而且element-plus的为large、default、small,但是Vxe-Table的为下面是medium、small、mini还需要做判断,杂七杂八,有点小恶心。下面附上代码。
import 'xe-utils' import VXETable from 'vxe-table' import 'vxe-table/lib/style.css' //引入font-awesome import 'font-awesome/css/font-awesome.css' import { localAppSizeKey } from '@/store/modules/settings/index' VXETable.setup({ size: formatSize(localStorage.getItem(localAppSizeKey) || 'default') as any }) export default function (app: any) { app.use(VXETable) // 给 vue 实例挂载内部对象,例如: // app.config.globalProperties.$XModal = VXETable.modal // app.config.globalProperties.$XPrint = VXETable.print // app.config.globalProperties.$XSaveFile = VXETable.saveFile // app.config.globalProperties.$XReadFile = VXETable.readFile } /** * 解析element-plus的全局size * @param size * @returns */ function formatSize(size: null | undefined | string) { let resSize = 'small' switch (size) { case 'large': resSize = 'medium' break case 'default': resSize = 'small' break case 'small': resSize = 'mini' break } return resSize }
size是存在localStorage里面的,设置一次,更新一次值,我这里就很简单粗暴了,全局设置element-plus的size然后通过format方法解析,存入本地存储,然后刷新页面,啊哈哈哈哈,问就是还不知道咋搞,有人知道的麻烦私一个,解决这个问题。
按钮的问题
说真的,我很能理解作者的设计模式,我也很佩服作者的代码功底,毕竟我只是一个使用者,但是但是,你自己开发一套按钮什么的,能不能走点心嘛,按钮中的文字居然不能垂直居中。大哥这都啥年代了哎,附上我处理按钮垂直居中的代码
.vxe-button.type--button { display: inline-flex; align-items: center; justify-content: center; }
简单粗暴,flex解决,有问题再解决
合并单元格的问题
单元格合并的按照官网提供的案例,第一次使用了spanMethod方法,那时候数据量少,没有开启虚拟滚动,后来数据量大了,测试滚动了一下叫了一声,我头皮一麻就知道出问题了,结果我看到官网上赫然写着,不支持虚拟滚动,哎~~ 我用这个表格不就是冲着虚拟滚动来的吗?再找解决方案把,后来决定还是用【mergeCells】去解决这个问题,解决思路就是,根据需求,合并固定的列,然后在数据中查询最近的相同数据(后端已排好序),生成要合并的数据,然后赋值到gridOptions对象上面,具体实现如下:
proxyConfig: { seq: true, sort: true, filter: true, form: true, props: { result: 'data.data', total: 'data.totalCount' }, ajax: { query: async ({ page, form }) => { const { pageSize: size, currentPage } = page const paging = { size, page: currentPage } const queryParams: any = Object.assign({ isOdm: 1 }, paging, form) const response = await queryList(queryParams) // 合并单元格选项 let mergeCells: any[] = [] mergeCells = generateMergeCells( response.data.data, 'spuName', [2, 3, 4, 5, 6, 7, 8] ) gridOptions.mergeCells = mergeCells return response } } },
这时候第一页可以分页了,但是跳转页面后,发现问题了,第二页分页居然错乱?后面的全乱了!!为此谷歌百度都查了,结果还是没有解决方案。后来突发奇想,每次分页我reload一下会不会好点,结果还真就行了,其实就是在前面代码中加入一行代码:xGrid.value.reloadData(response.data.data)
proxyConfig: { seq: true, sort: true, filter: true, form: true, props: { result: 'data.data', total: 'data.totalCount' }, ajax: { query: async ({ page, form }) => { const { pageSize: size, currentPage } = page const paging = { size, page: currentPage } const queryParams: any = Object.assign({ isOdm: 1 }, paging, form) const response = await queryList(queryParams) // 合并单元格选项 let mergeCells: any[] = [] mergeCells = generateMergeCells( response.data.data, 'spuName', [2, 3, 4, 5, 6, 7, 8] ) gridOptions.mergeCells = mergeCells xGrid.value.reloadData(response.data.data) return response } } },
芜湖~~,解决!附上动态生成mergeCells的代码
// 生成合并单元格数据 export const generateMergeCells = ( data: any[], key: string, cols: number[] ) => { if (data.length === 0) return [] let pointer: number = 0 let total: number = 0 let curKeyValue: any = data[0][key] const result = data.reduce((acc: any[], cur: any, index: number) => { const val = cur[key] let mergeData: any = [] if (val !== curKeyValue) { // 生成合并数据 if (total > 1) { mergeData = generateCells(cols, pointer, total) } curKeyValue = val pointer = index // 指针index赋值 total = 1 } else { total += 1 if (index === data.length - 1) { mergeData = generateCells(cols, pointer, total) } } acc.push(...mergeData) return acc }, []) return result } export const generateCells = ( cols: number[], rowIndex: number, rowspan: number ) => { return cols.map((col: number) => { return { row: rowIndex, col, rowspan, colspan: 1 } }) }
reload和load的问题
我实在搞不懂为什么每次reload和load要传参数进去,而却重置和查询这种按钮的方法没有抛出来以供调用。
但是也可以解决,作者抛出了很多方法,但是说明文档里面没有...,具体可以参照node_modules/vxe-table/packages/src/grid.ts文件
gridMethods.commitProxy('query') // insert // insert_actived // mark_cancel // remove // import // open_import // export // open_export // reset_custom // _init // 重置page 并查询 gridMethods.commitProxy('_init') // reload // 重新载入,可以重置一些参数但并不能重置查询参数 gridMethods.commitProxy('reload') // query // delete // save
grid在重置之后列表自动查询的时候还是会把原本的数据带过去的问题解决
在被坑的死去活来的时候,发现,grid的查询字段,如果ui不是自带的,这时候就会又有一个问题,那就是点击重置的时候,slots自定义的组件不能重置,后来发现有@form-reset的方法去重置,但是需要自己去写,这一点不是很友好,但是还可以接受
<vxe-grid ref="xGrid" class="sl-main-wrapper" v-bind="gridOptions" @form-reset="gridformReset"> ... </vxe-grid>
const gridformReset = ({ data }) => { const keys = ['picker', 'stereotypeMaker', 'status'] keys.forEach((i: any) => { data[i] = undefined }) }
但是发现了一个问题,我第一次重置的时候,我重置后的值居然带不过去,它还是上一个条件的参数~~,我滴个亲哥,要命啊,找了很多解决方案,首先是代码次序,不行,再次是重新组织查询的参数,发现还是不行,后来在吃饭的时候想起来会不会是因为没有nextTick的原因呢?
果然是!!!!!!!!!!!!!!!!!!!!!!!!!
最后的解决方案是这样的:
以下代码只是我的场景,核心点是return nextTick(() => { return response })
query: ({ page, form }) => { return nextTick(async () => { const { pageSize: size, currentPage } = page const paging = { size, page: currentPage } const queryParams: any = Object.assign(paging, form) const vxeForm = clone(queryParams, true) const picker = vxeForm.picker || [] if (picker.length > 0) { if (form.dateType === 1) { vxeForm.tailorCompleteTimeStart = picker[0] vxeForm.tailorCompleteTimeEnd = picker[1] } else if (form.dateType === 2) { vxeForm.stereotypeCompleteTimeStart = picker[0] vxeForm.stereotypeCompleteTimeEnd = picker[1] } } delete vxeForm.picker delete vxeForm.dateType const response = await queryList(vxeForm) return response }) }
总结
到此这篇关于Vxe-Table开发中各种坑以及避坑指南的文章就介绍到这了,更多相关Vxe-Table避坑指南内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!