ant-design-vue 开发常见坑点与解决方案

作者:山岚时间:2026-10-24 03:19:55浏览:437

本文总结ant-design-vue开发中的常见问题,包括Table数据对接、操作栏参数传递、分页显示、动态标签渲染异常、表单校验与重置、跨域Cookie携带以及单点登录路由处理等。通过具体代码示例和配置说明,帮助开发者快速解决实际开发中遇到的难点。

ant-design-vue简介

ant-design-vue是蚂蚁金服Ant Design官方唯一推荐的Vue版本UI组件库,它实现了Ant Design的设计规范,在组件风格、HTML结构及CSS样式上与Ant Design保持同步。经过实际使用,它确实是一个较为完整且成熟的Vue组件库及开发方案集成项目。

本文旨在总结开发过程中耗时较长且官方文档未明确说明的常见问题,希望能为刚开始接触该框架的开发者提供实用的参考。

Table组件常见问题

1. Table组件对接后台返回数据

针对Table组件的数据格式与后台接口返回格式不一致的问题,需要修改`@/components/table/index.js`文件中从第132行开始的代码。

主要调整pageNo、pageSize、totalCount和data这几个字段,使其与后台返回的字段名称保持一致即可。


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
 }
 !r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
 this.localDataSource = r.data // 返回结果中的数组数据
 this.localLoading = false
});

2. Table操作栏参数传递问题

在Table的dataSource中指定的每一项数据都必须包含名为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列表,并认为动态绑定数据无需手动处理,就会出现问题。

假设共有5个Tag,删除第一个Tag并调用接口返回新数据。注意,Tags默认的删除操作并非从DOM中移除该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 }) 

清除某个字段的值:

this.form.resetFields(`name`,'')

设置表单初始值:

this.form.resetFields(`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.log(param.get('file')); //FormData私有类对象访问不到,可以通过get判断值是否传进去
  let config = {
    headers:{'Content-Type':'multipart/form-data'}
  }; 
  this.$http.post(url, param, config).then(res => {
    ...
  })
},

跨域Cookie与单点登录

6. 接口跨域携带Cookie问题

在进行单点登录时,需要在请求头中携带Cookie,遇到了一个棘手的问题,实际原因是对mock.js的实现机制不够了解。

在`@/src/utils/request.js`中创建axios实例供全局调用。根据axios文档,在创建axios实例时需添加:`withCredentials: true`。


const service = axios.create({
  baseURL: `${process.env.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,所以能正常携带Cookie。此处尚未完全梳理清楚,计划在后文中详细介绍。

7. 单点登录的实现

全局路由钩子位于`permission.js`中,通常单点登录和权限验证在此处处理。这里也不例外。需要注意的一点是,不要忘记对页面其他接口的统一无权限处理和403请求的响应处理。同时绘制流程图会更清晰,此处记录如下:

流程图:

ant-design-vue简介路由钩子

路由钩子的处理逻辑:


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`中接口返回的统一处理逻辑:


service.interceptors.response.use((response) => {
  if (response.data.status === 1005){
      //... 同上跳去登陆页
  }else{
    //为返回数据做统一处理
    return response.data
  }
}, err) 

引入eCharts与图表自适应

7. 引入eCharts

1)执行npm install安装依赖。

2)在components下新建barChart.vue,import echarts from 'echarts',按正常流程操作。

3)监听resize触发图表自适应。

echarts提供了resize API,通常在barChart.vue等图表组件内手动监听窗口resize事件。


mounted() {
  window.addEventListener("resize", () => {
    this.chart.resize(); 
  });
},

后续借鉴element-admin,利用mixins实现了更完善的统一处理方法:

1)定义一个mixin:resize.js。


import { debounce } from '@/utils'//防抖函数
export default {
 data() {
  return {
   $_sidebarElm: null
  }
 },
 mounted() {
  this.__resizeHandler = debounce(() => {
   if (this.chart) {
    this.chart.resize()
   }
  }, 100)
  window.addEventListener('resize', this.__resizeHandler)

  this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
  this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
 },
 beforeDestroy() {
  window.removeEventListener('resize', this.__resizeHandler)

  this.$_sidebarElm && this.$_sidebarElm.removeEventListener('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]

总结

以上所述是小编给大家介绍的ant-design-vue快速避坑指南,希望对大家有所帮助。如果大家有任何疑问请留言,小编会及时回复。在此也非常感谢大家对本站网站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

作者最新文章