Ant Design Vue 踩过的一些坑

3,619 阅读5分钟

不知道大家使用 Ant Design Vue 的时候有没有感觉不太顺手的地方,有些组件属性总是写的很隐蔽,有点磕磕绊绊的感觉。本篇博客记录一下我这一段儿时间使用 Ant Design Vue 踩过的一些坑,本文会持续更新~

Select 滚动定位问题

正常情况下,Select 的下拉框内容可以正确定位在 Select 下方,但是在微前端中,Select 的下拉框内容可能会出现定位问题,不会随着页面滚动而滚动,而是定位在了页面的某个位置。

企业微信截图_0edc20da-1a64-4930-a87d-2a4cd5bef999.png

这是因为 Select 的下拉框内容默认渲染定位到 body 上;在微前端中,我们知道子应用是被嵌套在主应用的某个容器 DIV 里面,而不是整个页面的 body 上,这就导致了 Select 的下拉框内容在页面出现滚动条的时候不能正确定位。

getPopupContainer 属性可以解决这个问题,

参数说明类型默认值
getPopupContainer菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。Function(triggerNode)() => document.body
<a-select
  :getPopupContainer="
      triggerNode => {
        return triggerNode.parentNode || document.body;
      }
    "
>
</a-select>

其他组件类似,如 DatePicker 日期选择框有 getCalendarContainer 属性;Dropdown 下拉菜单有 getPopupContainer 属性;等等。

修改组件样式

Table 组件

  <Table :dataSource="dataSource" :columns="columns" class="example-table-wrap"/>
  <Table :dataSource="dataSource" :columns="columns"/>

如果想修改页面中第一个表格 class 是 example-table-wrap 字体大小,页面其他表格字体不变,怎么实现呢? image.png 两种方式,一种是在 scoped 中添加样式,另一种是全局的添加。

方式一:对于 scoped的代码片段,需要使用深度作用选择器 >>>

企业微信截图_85c3c145-1f3b-479e-81bb-aa37a21a22fa.png class 为 example-table-wrap 的 DIV 打上了 data-v-7ba5bd90 标志,所以需要使用深度作用选择器 >>> 选中子组件的样式进行修改:

<style scoped>
.example-table-wrap >>> .ant-table{
  font-size: 12px;
}
</style>

转义后:

<style>
.example-table-wrap[data-v-7ba5bd90] .ant-table {
  font-size: 12px
}
</style>

方式二:全局修改。

<style>
.example-table-wrap .ant-table{
  font-size: 12px;
}
</style>

也可以实现,推荐第一种写法,相比较第二种写法,第一种更不容易引起全局环境变量污染。

Modal 对话框

如果认为 Modal 对话框样式的修改跟 Table 组件修改方式一样可以使用 scoped + >>>,那就大错特错了。同样的,我们给 Modal 对话框一个 class 类 example-modal,会发现默认 Modal 对话框并没有打上 data-v-7ba5bd90 标志: image.png 这样的话,我们就不能用第一种方式 scoped + >>> 去修改它的样式,只能用全局样式修改了:

<style>
.example-modal .ant-modal-body{
  padding: 12px;
}

如果仔细看 Modal 的 API 的话就可以看到,还可以通过 bodyStyle 属性去修改 Modal 的样式:

参数说明类型默认值
bodyStyleModal body 样式object{}
  <Modal
    :bodyStyle="{color: 'red', padding: '12px'}"
   >
  </Modal>

Tooltip 文字提示

如果我们想修改 Tooltip 的样式的话,可以使用 overlayClassNameoverlayStyle

参数说明类型默认值
overlayClassName卡片类名string
overlayStyle卡片样式object

但是注意是全局变量使用方式:

<template>
  <Tooltip color="white" class="example-tooltip" overlayClassName="example-overlay">
    <template #title>prompt text</template>
    Tooltip will show when mouse enter.
  </Tooltip>
</template>
<style>
.example-overlay .ant-tooltip-inner{
  color: black;
  padding: 12px;
}
</style>

修改 Table 列的颜色

可以使用 rowClassName 修改表格行的样式,修改表格列的样式 API 文档并没有给出。用过 ant design React 版本的同学知道 Column 属性有一个 className 可以设置列样式类名。通过查看 Ant Design Vue 的源码发现也有这个属性可以使用,疑惑的点是为什么官方 API 不写全一点呢?还要用户去推测?😤

<script setup>
const columns = [
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
      className: 'example-column-class'
    },
]
</script>

修改表头样式:

<style>
th.example-column-class{
  color: red;
}
</style>

image.png 修改列的样式:

<style>
tr.example-column-class{
  color: red;
}
</style>

image.png

select 组件 placeholder 属性不起作用

这也是比较常见的一个使用问题,刚使用 Ant Design Vue 组件常见的一个问题。一般因为 select 绑定的参数(selectParam),初始值为空字符串('')导致的,设置为 undefined 即可解决该问题

  <Select 
    v-model:value="selectParam" 
    placeholder="请选择"
   :options="options3">
  </Select>
   
<script setup>
const selectParam = ref('')
</script>

image.png

<script setup>
const selectParam = ref()
</script>

image.png

表单验证的问题

对于 Ant Design Vue 3 版本之前,如果表单验证的 rules 规则里对于 DatePicker 日期选择组件的 type 没有定义会出现即使用户已经选中了日期,仍然校验不通过的问题。

image.png

const rules = {
  date1: [{ required: true, message: 'Please pick a date', trigger: 'change', type: 'object' }]
}

默认 type 是 string类型,如果类型不匹配,对于 Ant Design Vue 3 版本之前是会报错的。需要加上对应的类型 type: 'object' 才可以解决。

如果限制可以取多种类型怎么处理呢?
目前 async-validator 还没有可以限制多种类型的处理,需要我们自己写自定义校验规则实现,或者使用 type: 'any' 来实现。

Table 添加 rowKey

方式一:

<Table 
    :columns="columns" 
    :data-source="tableData" 
    :rowKey='record=>record.id'/>   // id为 tableData 中的一个属性

方式二:

<Table 
    :columns="columns" 
    :data-source="tableData" 
    :rowKey="(record,index)=>{return index}">  //record 为每一条数据, index 索引

方式三:

<Table 
    :columns="columns" 
    :data-source="tableData" 
    rowKey="id">  // id为 tableData 中的一个属性 !!! 这里的rowKey不需要冒号

# antdesign-vue的table三种加rowkey的方式

DatePicker 绑定 string 类型

参数说明类型默认值
valueFormat可选,绑定值的格式,对 value、defaultValue、defaultPickerValue 起作用。不指定则绑定值为 moment 对象string,具体格式-
<a-date-picker
  v-model:value="expireDate"
  format='YYYY-MM-DD'
  value-format='YYYY-MM-DD'
/>

这样我们绑定的 expireDate 变量为 string 类型,直接用于后端数据发送。妈妈再也不用担心我 moment 类型和 string 类型转换来转换去了

关联的表单校验

image.png 如上图,两个时间选择框不仅不要校验非空,而且还需要校验彼此是否满足条件。可以使用自定义 validator 来实现,当 travelStartTimetravelEndTime 变化的时候调用 formRef.value.validateFields('travelStartTime');formRef.value.validateFields('travelEndTime'); 触发校验。


  const checkStartTime = async (rule: RuleObject, value: string) => {
    if (!value) {
      return Promise.reject('请选择开始日期');
    } else {
      if(dayjs(formState.travelEndTime).isBefore(value)){
        return Promise.reject('开始日期不应晚于结束日期');
      }
    }
    return Promise.resolve();
  };

  const checkEndTime = async (rule: RuleObject, value: string) => {
    if (!value) {
      return Promise.reject('请选择开始日期');
    } else {
      if(dayjs(formState.travelStartTime).isAfter(value)){
        return Promise.reject('结束日期不应早于开始日期');
      }
    }
    return Promise.resolve();
  };
  
  const rules = {
    travelEndTime: [
      {
        required: true, type: 'string', validator: checkEndTime
      },
    ],
    travelStartTime: [
      {
        required: true, type: 'string', validator: checkStartTime
      },
    ],
  }
  
watch([() => formState.travelStartTime, () => formState.travelEndTime], ([newStart, newEnd]) => {
    if (newEnd) {
      formRef.value.validateFields('travelEndTime')
    }
    if (newStart) {
      formRef.value.validateFields('travelStartTime')
    }
})

内置 TS 的类型

import { ColumnProps, TableState } from 'ant-design-vue/es/table/interface'