ant-design-vue快速避坑指南
ant-design-vue是蚂蚁⾦服 Ant Design 官⽅唯⼀推荐的Vue版UI组件库,它其实是Ant Design的Vue实现,组件的风格与Ant Design保持同步,组件的html结构和css样式也保持⼀致。⽤下来发现它的确称得上为数不多的完整的VUE组件库与开发⽅案集成项⽬。
本⽂主要⽬的是总结⼀些开发过程中⽐较耗时间去查,⽂档中没有具体说明的常见问题,同时希望能给新上⼿此框架的同学提供⼀些参考作⽤。
1.Table对接后台返回数据
针对Table数据格式与后他接⼝返回数据格式不⼀致问题,修改 `@/components/table/index.js` 132⾏起
主要修改pageNo,pageSize,totalCount,data这字段与后台返回字段⼀致就OK了
result.then(r => {
this.localPagination = Object.assign({}, this.localPagination, {
current: r.pageNo, // 这⾥修改当前分页字段
total: r.totalCount, // 这⾥修改总记录数字段
showSizeChanger: this.showSizeChanger,
pageSize: (pagination && pagination.pageSize) ||
this.localPagination.pageSize // 这⾥修改总记录数当前页数字段
})
//r.data中的data修改为返回列表字段
if (r.data.length == 0 && this.localPagination.current != 1) {
this.localPagination.current--
this.loadData()
return
}
!
this.localDataSource = r.data // 返回结果中的数组数据
this.localLoading = false
});
2.table操作栏参数问题
在table的dataSource中指定的每⼀个数据中,都必须包含有name为key的对象,⽽显⽰出的数据就是相应key对应的数据,dataIndex就⽤来声明列数据在数据项中对应的key
然⽽在操作列中,我们⼀般需要传⼊不知⼀项数据,试了⼀下如下图配置dataIndex,数据并不能正确传⼊slot-scope中
columns: [
...
{
title: '操作',
dataIndex: 'id,text',
key: 'id',
scopedSlots: { customRender: 'operation' }
}
】
多尝试后发现,其实只要不配置dataIndex就好了。。。slot-scope⾃定义⼀个字段,⾃然就拿到了整⾏数据
3.table分页组件展⽰条数
:pagination="{showTotal: total => `共${total}条`}"
4.神奇的最后⼀个标签隐藏问题
使⽤可编辑tags过程中值得注意的问题,⼀般删除某个tag不⽌是从DOM中删除这个tag,⽽是需要调接⼝修改数据,那么这时候如果选择⽤修改完的数据动态渲染tag列表,并且理所当然地认为动态绑定数据就不需要关⼼数据⼿动处理,问题就出现了:
假如⼀共有5个tag,现在删除第⼀个tag,并调⽤接⼝返回新数据,注意tags默认的删除操作也不是从DOM中删除这个tag,⽽是将这个tag设置为```display:none```!这就导致了⼀个很神奇的问题,此时新返回的tags数组长度已经 -1,⽽它仍然认为当前列表的第⼀个Tag是隐藏的,最后呈现的效果就是只剩3个Tag,此时再接着删除第⼀个tag(其实是第⼆个),那么就只剩1个tag了。。
<a-tag
v-for="(tag, index) in Tags"
:key="tag.id"
:closable="tagCloseable"
:afterClose="() => handleTagStatus(0,tag)"
>{{ tag.name }}
</a-tag>
这个问题貌似没什么好的办法,只能放弃绑定动态数据,判断接⼝调⽤成功后,再⽤⽂档中的⼿动操作增减数据的办法:
this.Tags = this.Tags.filter(tag => tag.id !== removeTag.id)
5.表单的各种常规操作
单独触发某个字段的校验:
this.form.validateFields(['name'], { force: true })
清除某个字段的值:
setFields(`name`,'')
设置表单初始值:
setFields(`name`,'')
注意:不初始化的值⽤undefined⽽⾮‘’,否则下拉框会不显⽰placeholder!
⾃定义⽂件上传的action函数:
<a-upload :customRequest="upLoad"></a-upload>
upLoad (info) {
let file = info.file;
let param = new FormData(); //创建form对象
param.append('file',file);//通过append向form对象添加数据
console.('file')); //FormData私有类对象访问不到,可以通过get判断值是否传进去
let config = {
headers:{'Content-Type':'multipart/form-data'}
};
this.$http.post(url, param, config).then(res => {
.
..
})
},
6.接⼝跨域携带cookie问题
做单点登录时需要在请求头中携带cookie,遇到了很坑⼈的问题,实际原因是对mock.js的实现不够了解。
还是在`@/src/utils/request.js`,这⾥创建了axios实例供全局调⽤,根据axios⽂档,**在创建** axios 实例时添加:`withCredentials: true` const service = ate({
baseURL: `${v.VUE_APP_BASEURL}/backend`,
withCredentials: true,
timeout: 6000
})
结果发现接⼝请求仍然不带cookie,⽆奈试了⼀下⽤fetch请求`fetch(url, { credentials: 'include', mode: 'cors' })`,发现可以携带cookie,百思不得其解,两者都是基于promise实现的,但是fetch在写法和拦截请求响应等⽅⾯都⽐较⿇烦,全部替换成fetch也不太现实。最后才发现,是mock.js没有注释(`main.js`中注释掉就好了),原来mock.js是通过拦截XHR请求来实现的接⼝模拟,Axios本质上也是对原⽣XHR的封装,只不过它是Promise的实现版本,所以它当然被拦截了,⽽fetch脱离了XHR,这也是fetch请求能正常携带cookie的原因,这⾥还没有全部梳理清楚,打算在后⼀篇中详细介绍⼀下
7.单点登录的实现
全局的路由钩⼦在`permission.js`中,⼀般单点登录、权限验证都是在这⾥处理,这⾥也不例外。没什么特别的,需要注意的⼀点就是,不要忘记对页⾯其他接⼝的统⼀⽆权限处理,和403请求的响应处理。同时画个流程图会更快⼀些,这⾥就记录⼀下吧:
流程图:
路由钩⼦的处理:
router.beforeEach((to, from, next) => {
// 对403⽆权限的处理
if (to.path === '/403') {
next()
} else {
if (roles) {//已登陆
next()
} else {
//获取⽤户信息,GetUserInfo逻辑如下:
//status=403 && reject(res),返回包含status;
//status=1005 && reject(res.data)返回重定向的URL;
//status=1000 && resolve()
store
.
dispatch('GetUserInfo')
.then(res => {
next()
})
.catch((e) => {
if (e.status) {
next({ path: '/403' })
} else {
//拼接URL跳去登陆页,登陆成功会重定向回当前页(login_redirect)
const url = e.substring(0, e.lastIndexOf('redirect')) + 'redirect=' + login_redirect
window.location.href = url
}
})
}
}
})
`@/ src/utils/request.js`中接⼝返回的统⼀处理:
sponse.use((response) => {
if (response.data.status === 1005){
//... 同上跳去登陆页
}else{
//为返回数据做统⼀处理
return response.data
}
}, err)
7.引⼊eCharts
1)npm install
2) components下新建barChart.vue ,import echarts from 'echarts',正常操作...
3) resize触发图表⾃适应
echart有resizeAPI,⼀般是在图表组件如barChart.vue⾥⾯⼿动监听窗⼝resize
mounted() {
window.addEventListener("resize", () => {
size();
});
},
后⾯借鉴element-admin,利⽤mixins实现了更完善的统⼀处理⽅法:
1)定义⼀个mixin:resize.js
import { debounce } from '@/utils'//防抖函数
export default {
data() {
return {
$_sidebarElm: null
}
},
mounted() {
this.__resizeHandler = debounce(() => {
if (this.chart) {
size()
}vuejs流程图插件
}, 100)
window.addEventListener('resize', this.__resizeHandler)
this.$_sidebarElm = ElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
beforeDestroy() {
this.$_sidebarElm && this.$_veEventListener('transitionend', this.$_sidebarResizeHandler) },
methods: {
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.__resizeHandler()
}
}
}
}
2)@/components/_utils/util.js中添加防抖函数
export const debounce = (func, wait, immediate) => {
let timeout, args, context, timestamp, result
const later = function() {
// 据上⼀次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调⽤时间间隔 last ⼩于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调⽤过了此处⽆需调⽤if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function(...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}
3)resize监听⽅法混⼊图表组件即可
mixins: [resize]
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论