ant-design-vue中的table自定义格式渲染解析
作者:hufi
ant-design-vue中table自定义格式渲染
一般业务开发中,难免会遇到将一些状态值(如 0 / 1)转化为相应的描述(如 关闭 / 开启),也可能是对日期时间的格式化,如下两图转化前后对比:
开始之前,需要注意的是,定义的 columns 一定要写在 data 中,否则在加载过程中由于渲染顺序会导致其中的渲染函数无法识别。
有两种方式修改:
1、直接调用对应插槽模板
<template> <div class="vehicle-list"> <a-table :columns="columns" :data-source="data" bordered> <template slot="tradeState" slot-scope="state"> {{ state === 1 ? '交易完成' : (state === 0 ? '等待交易' : '交易失败') }} </template> <template slot="tradeTime" slot-scope="time"> {{ timeFormat(time) }} </template> </a-table> </div> </template> <script> import moment from 'moment' const columns = [ { title: '交易状态', dataIndex: 'tradeState', // customRender: 'tradeState' -> 自定义 slot 属性名,对应模版中的 slot 属性,即这里自定义为啥,对应模版中的 slot 就要等于啥 // 模板中对应的 slot-scope 属性可以用来传递三个参数(val,row,index),分别是当前值、当前行数据和当前索引 scopedSlots: { customRender: 'tradeState' } }, { title: '交易时间', dataIndex: 'tradeTime', scopedSlots: { customRender: 'tradeTime' } } ] const data = [ { key: '1', tradeState: 1, tradeTime: '2020-11-01T12:50:19+08:00' }, { key: '2', tradeState: -1, tradeTime: '2020-11-02T18:06:32+08:00' }, { key: '3', tradeState: 0, tradeTime: '2020-11-03T08:25:03+08:00' } ] export default { name: 'VehicleList', data () { return { data, columns } }, methods: { timeFormat (val) { // 时间格式化函数 return moment(val).format('YYYY-MM-DD HH:mm:ss') } } } </script>
2、指定渲染函数
<template> <div class="vehicle-list" style="width: 50%"> <a-table :columns="columns" :data-source="data" bordered></a-table> </div> </template> <script> import moment from 'moment' const columns = [ { title: '交易状态', dataIndex: 'tradeState', customRender: (state) => { // customRender属性是一个方法,可接收三个参数(val,row,index),分别是当前值、当前行数据和当前索引,与方式 1 中模版的 slot-scope 属性传参类似 return state === 1 ? '交易完成' : (state === 0 ? '等待交易' : '交易失败') } }, { title: '交易时间', dataIndex: 'tradeTime', customRender: (time) => moment(time).format('YYYY-MM-DD HH:mm:ss') } ] const data = [ { key: '1', tradeState: 1, tradeTime: '2020-11-01T12:50:19+08:00' }, { key: '2', tradeState: -1, tradeTime: '2020-11-02T18:06:32+08:00' }, { key: '3', tradeState: 0, tradeTime: '2020-11-03T08:25:03+08:00' } ] export default { name: 'VehicleList', data () { return { data, columns } } } </script>
对比以上,可以看出方式2代码更加简洁,且易读性更好。
ant-design-vue快速上手指南+排坑
公司要开发一个后台管理系统,对于UI库的选择上选择了颜值爆表的Ant-Design-Vue作为整个项目UI库,但谁曾想,暗中的坑一个接一个,文档也不怎么详细,可能习惯了element-ui的掘友们也许不怎么好适应,本文就带大家一起学习如何高效使用Ant-Design-Vue。
NO.1 表单组件
首先就来说说最常用的Form组件的正确使用姿势:
先来看官方一段话述:
第一、我们不推荐在Form中使用双向绑定,同一份数据可能在多处使用,如果使用双向绑定,那么数据的修改会同时同步到各个组件,但这并不是我们想要的, 你应该在表单提交成功或失败或确认时同步数据,使用非双向绑定的表单,你会拥有最大限度的控制数据修改/同步的权限。
第二、如果你不使用表单的自动校验/收集功能,即没有使用v-decorator修饰过的组件,你依然可以使用v-model
看了官方的建议后,我们愉快的使用v-decorator修饰input组件,代码如下:
<a-form-item> <a-input placeholder="账号" v-decorator="['account',{rules: [{ required: true,whitespace:true,message: '请输入您的登陆账号' }]}]" /> </a-form-item>
划重点:
v-decorator里的account可以理解为input的name值,后面{}对象可以配置校验规则,初始值等参数,这里需要注意的是使用了v-decorator的组件无法使用v-model,也无法设置value等与值有关的属性,否则报错
v-decorator会自动收集你表单里的数据到form对象里,所以别忘了在data中加上这句代码:
form: this.$form.createForm(this)
模板中这么写:
如何自定义表单校验规则
这里拿确认密码举例:
<a-input type="password" v-decorator="['new_password',{rules:[{required: true,whitespace:true,message: '请输入新密码'},{validator: handlePass}]}]" /> <a-input type="password" v-decorator="['confirm_password',{rules:[{required: true,whitespace:true,message: '请重复新密码'},{validator:handleConfirmPass}]}]" />
这里我们使用validator校验器自定义函数
handlePass(rule, value, callback) { this.password = value; callback(); }, handleConfirmPass(rule, value, callback) { if (this.password && this.password !== value) { callback('与新密码输入不一致'); } callback(); },
这里需要注意callback()必须调用
这里的value就是对应表单输入了的值,然后知道了这些我们就可以写我们自己的业务逻辑了
做好的效果如图:
表单回显
我们在做编辑时首先需要通过后端接口读取到之前的数据,但是因为现在没有了v-model,那么我们该怎么办?
可以调用form对象中的setFieldsValue把后端返回的对象直接设置上去,如果是在mounted方法里必须加上$nextTick,不然会抛出警告说我们在表单未渲染好之前给予了数据
代码如图:
图中setFieldsInitialValue是设置表单初始值,如果表单中有重置按钮,就需要设置上,重置按钮调用this.form.resetFields()就可以重置form表单了
这个setFieldsValue方法会把传进去的对象的key和模板中v-decorator中的第一个参数比较,会自动把对应的值set进去。
提交表单
按钮加上html-type="submit"后点击会触发这个方法,这个方法校验表单中所有必填项没有问题后会自动帮我们把表单中所有带有v-decorator修饰的组件的值和name序列化好,我们就可以直接传给后端了。
NO.2 表格(Table)
我们的模板可以这么写:
ant-design-vue的表格自带分页,接下来我把上图中的参数挨个解释下,columns是单元格信息,我们可以把他导出为一个数组,如下图:
这里的title是用户看到的文字,dataIndex要和后台传过来的字段一致,不然数据不会显示出来,其次还提供了customRender和scopedSlots两种方式自定义内容,这里使用了第一种方式,但值得一提的是如果使用的是slot-scope方式,在模板中定义一个点击事件,想要获取到当前行的数据时,一定一定不要加dataIndex属性,否则会是undefined
看一个scopedSlots使用的例子:
可以看到上面定义columns时给action没有加dataIndex
我们继续看dataSource是什么,他就是你给table传递的数据
rowKey
可以理解为时循环时需要的key
(必有)pagination
初始化一个空对象scroll
定义表格可以横向滚动handleTableChange
是当分页数据发生改变时抛出的事件
为了简化操作,我这里封装了一个mixin,当页面中有table时直接混入mixin就支持分页和拉取数据的逻辑了,代码如下:
export const mixin = { data() { return { pagination: {}, data: [], }; }, methods: { handleTableChange(pagination) { const pager = {...this.pagination}; pager.current = pagination.current; this.pagination = pager; this.loadData({ page: pagination.current }); }, async loadData(params = {}) { try { const {data: table_data, total, per_page} = await this.loadMethod('flush' in params ? {page: 1} : {page: 1, ...params}); const pagination = {...this.pagination}; pagination.total = total; pagination.pageSize = per_page; 'flush' in params && (pagination.current = 1); this.data = table_data; this.pagination = pagination; } catch (e) { console.log(e); } } } };
flush用于标识是否是插入新数据或者删除了数据,如果是我们直接把page重置为1返回第一页
我们在页面使用只需要以下几行代码:
import { getLog } from '@/api/api'; import { mixin } from '@/mixins'; export default { name: "log", mixins: [mixin], data() { return { columns, loadMethod: getLog }; }, mounted() { this.loadData(); } };
这样其他类似的组件也可以直接复用本逻辑。
NO.3 Spin组件
我们平时在后台管理系统中,ajax请求过程中都会出现全屏加载提示的遮罩层,做这个功能时我想到了这个组件,然后去官方文档查看,看到了如下图的操作方式:
然后粘贴到代码中,各种操作,没有任何反应,甚至有时候还来点小报错,Spin组件肯定是引入了,反正就是最后怎么操作都没成功,无奈之下,自己用了他的样式写了个Vue的Spin插件:
我们首先新建Loading.vue
<template> <div v-if="show" class="loading-container"> <div class="loading-mask"></div> <div class="loading-content"> <a-spin tip="正在加载数据中..." size="large"> </a-spin> </div> </div> </template> <script> export default { name: 'Loading', props: { show: Boolean, }, data() { return { } } } </script> <style lang="scss" scoped> .loading-container{ position: relative; text-align: center; z-index:9999; .loading-mask{ position: fixed; top:0; bottom:0; left:0; right:0; background-color:rgba(0,0,0,.7); } .loading-content{ position: fixed; left: 50%; top: 50%; z-index: 300; transform: translate(-50%,-50%); text-align: center; color:#fff; } } </style>
然后再新建Loading.js
import Vue from 'vue'; import loadingComponent from './Loading.vue'; const LoadingConstructor = Vue.extend(loadingComponent); const instance = new LoadingConstructor({ el: document.createElement('div') }); instance.show = false; // 默认隐藏 const loading = { show() { // 显示方法 instance.show = true; document.body.appendChild(instance.$el); }, hide() { // 隐藏方法 instance.show = false; } }; export default { install() { if (!Vue.$loading) { Vue.$loading = loading; } Vue.mixin({ created() { this.$loading = Vue.$loading; } }); } };
然后在main.js中
import loading from '@/components/Loading/loading.js'; Vue.use(loading);
然后我们就可以愉快的调用了:
Vue.$loading.show();
打包优化
首先就是用官方快速上手中提供的按需加载,这里不再赘述,使用之后还存在以下问题:
里面的moment.js,还有lodash,还有icon的dist居然占用了我们500KB的空间,这不能忍,那怎么办呢?
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
我们首先忽略掉语言包,然后看看图标怎么优化:
config.resolve.alias .set('@', resolve('src')) .set('@ant-design/icons/lib/dist$',resolve('src/icon.js'))
我们还需要在src文件夹下面加一个文件 icons.js
//自己项目里面用到的Icon export {default as UserOutline} from '@ant-design/icons/lib/outline/UserOutline'; export {default as CloseCircleFill} from '@ant-design/icons/lib/fill/CloseCircleFill'; export {default as InfoCircleFill} from '@ant-design/icons/lib/fill/InfoCircleFill'; export {default as CheckCircleFill} from '@ant-design/icons/lib/fill/CheckCircleFill';
我们还可以开启gzip压缩等,使用DLL优化我们的打包速度,这些在这里就不再赘述了,社区有很多类似的贴子。
结语
那么对于ant-design-vue使用的前两天感觉不怎么顺手,现在只能说真香
其实这个UI库用习惯之后会发现好像Form表单的设计其实比v-model更好用,哈哈
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。