a-cascader级联选择的使用以及注意事项(基于AntDesignVue)
包括a-cascader的基本使用,进阶的动态加载数据或者预加载数据,以及自定义字段名简化代码。
一. 介绍以及基础使用
1. 介绍
级联选择其实就是下拉框的升级版本,适用于多级分类的数据,并且减少了页面元素占据的空间。
2. 基础使用
在a-cascader
组件中,最重要的一个api就是options
参数,其类型是数组,表示需要传入的数据源。其他api可以根据需要自由添加。如下例子是基础用法:
<template>
<a-cascader :options="options" @change="onChange" placeholder="Please select" />
</template>
<script>
export default {
data() {
return {
options: [
{
value: 'zhejiang',
label: '浙江省',
children: [
{
value: 'hangzhou',
label: '杭州市',
children: [
{
value: 'xihu',
label: '西湖区',
},
],
},
],
},
{
value: 'shanghai',
label: '上海市',
disabled: true, //禁用选择
children: [
{
value: 'qingpuqu',
label: '青浦区',
children: [
{
value: 'beijinglu',
label: '北京路',
},
],
},
],
},
],
};
},
methods: {
onChange(value) {
console.log(value);
},
},
};
</script>
当然,也可以参考示例或者官网的说明。
二. 根据接口传入的数据进行动态加载
1.使用loadData进行动态加载
使用该方法虽然不错,但是这种方法在点击每一层的时候会有一些缓冲的空白时间,因为它是点击每一个分类标题,然后随之加载该类的分级。请看以下例子:
<template>
<a-cascader
:options="options"
@change="onChange"
:loadData="loadData"
placeholder="请选择"
changeOnSelect
style="width:330px"
/>
</template>
<script>
export default {
data() {
return {
options: [
{
value: 'zhejiang',
label: '浙江省',
isLeaf: false,
},
{
value: 'jiangsu',
label: '江西省',
isLeaf: false,
},
],
};
},
methods: {
onChange(value) {
console.log(value);
},
//这个是模拟的ajax请求,你可以把这部分代码改成真正的ajax请求
loadData(selectedOptions) {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
// load options lazily
setTimeout(() => {
targetOption.loading = false;
targetOption.children = [
{
label: `${targetOption.label} 服务器端加载1`,
value: 'dynamic1',
},
{
label: `${targetOption.label} 服务器端加载2`,
value: 'dynamic2',
},
];
this.options = [...this.options];
}, 1000);
},
},
};
</script>
当然,我们还有一种选择,想要防止这种空白时间的缓冲,可以先对数据进行预加载。
2.对所有分级数据进行加载(不使用loadData)
在这里,我的数据源firstLevelCategory
(类似于官网的options
)初始都是空的,因为数据全都是从服务端过来的,并没有什么默认的数据。我要做的就是,当打开这个页面的时候,数据开始加载进去,直到我点击分类的时候,所有数据已经加载完成。好了,明白了要干什么我们就可以开始写代码了。
- 首先,打开这个页面数据开始加载,所以我把加载数据的函数方法放在了vue的生命周期函数
created()
里面。 - 定义三个存储数组
firstLevelCategory
,secondLevelCategory
,thirdLevelCategory
分别用于存储三个层级的下拉菜单(因为我写的项目所用到的数据只有三个层级,若是遇到更多的层级的话,可以使用this.$set
进行对象属性的添加,使用this.$set
还有一个好处,视图可以实时的更新,因为视图层实时更新是需要data()
里面的数据发生了变化才会更新状态,使用this.$set
添加对象可以达到一样的效果),三个存储数组之间的关系就是firstLevelCategory
的children
数组是secondLevelCategory
,secondLevelCategory
的children
数组是thirdLevelCategory
,依照这个关系,数据的流转层级依次向下,在以下代码中,我直接只用firstLevelCategory
一个数组往下不停更新children
。
<template>
<a-cascader
:options="firstLevelCategory"
:field-names="{ label: 'categoryName', value: 'categoryId', children: 'children' }"
placeholder="请选择分类"
@change="changeClassify"
change-on-select
/>
</template>
<script>
import { getPaperCategory, getExamTypes } from '@/views/learn/services/paper'
import { importPaper } from '@/views/makePaper/services/artificial'
export default {
data() {
return {
// value: ref([]),
options: [],
// 第一层级的下拉菜单(考试类型)
firstLevelCategory: [],
secondLevelCategory: [],
thirdLevelCategory: [],
},
},
},
methods: {
// 一级下拉框获取考试类型
async getFirstLevelCategory() {
const { data: firstLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: 0 })
for (let i = 0; i < firstLevelCategoryList.length; i++) {
this.getSecondClassify(i, firstLevelCategoryList[i])
}
this.firstLevelCategory = firstLevelCategoryList
},
// 获取二级下拉框
async getSecondClassify(firstIndex, val) {
const { data: secondLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: val.categoryId })
for (let i = 0; i < secondLevelCategoryList.length; i++) {
this.getThirdClassify(firstIndex, i, secondLevelCategoryList[i])
}
this.firstLevelCategory[firstIndex].children = secondLevelCategoryList
},
// 获取三级下拉框
async getThirdClassify(firstIndex, secondIndex, val) {
const { data: thirdLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: val.categoryId })
this.firstLevelCategory[firstIndex].children[secondIndex].children = thirdLevelCategoryList
},
}
</script>
三. 通过fieldNames自定义字段名缩减代码量
如果不使用fieldNames
参数的话,每次获取分类数据时,会一直需要将服务端传过来的数据赋值给label
, value
字段,就像这样:
targetOption.children = [
{
label: `${targetOption.label} 服务器端加载1`,
value: 'dynamic1',
},
{
label: `${targetOption.label} 服务器端加载2`,
value: 'dynamic2',
},
];
如果我们加上fieldNames
参数,对原始字段名进行重定义的话,就可以将服务端传过来的数据直接拿来使用,而不需要搞什么赋值之类的操作,不需要进行数据的处理,因为同名的字段会自动匹配到一起去。比如,我需要的是categoryId
和categoryName
这两个参数:
:field-names="{ label: 'categoryName', value: 'categoryId', children: 'children' }"
这样重定义字段名和接口传过来的字段名相同后,我就可以直接放入到chidren
数组里面。数据中的其他字段名没有匹配到,会自动忽略。
四. 在a-form-model表单中使用a-cascader级联选择的注意事项
在表单中使用级联选择的时候出了一个令我懵逼的错误:
type check failed for prop “value”. Expected Array, got Number with value 1.
原因是我习惯性的在表单中使用双向绑定v-model
,但是在a-cascader
中,这是用来绑定参数value
指定选中项的。将v-model
替换成:model
就没问题了。
错误代码:
<template>
<a-form-model :model="form" ref="form">
<a-form-model-item label="考试类型" prop="categoryId">
<a-cascader
v-model="form.categoryId"
:options="firstLevelCategory"
:field-names="{ label: 'categoryName', value: 'categoryId', children: 'children' }"
placeholder="请选择分类"
@change="changeClassify"
change-on-select
/>
</a-form-model-item>
<a-form-model>
</template>
<script>
import { getPaperCategory, getExamTypes } from '@/views/learn/services/paper'
import { importPaper } from '@/views/makePaper/services/artificial'
export default {
data() {
return {
// value: ref([]),
options: [],
// 第一层级的下拉菜单(考试类型)
firstLevelCategory: [],
secondLevelCategory: [],
thirdLevelCategory: [],
},
form: {
paperName: '',
paperType: undefined,
duration: undefined,
examId: undefined,
examTypeId: undefined,
categoryId: undefined,
paperId: undefined,
score: undefined,
remark: '',
categoryExamTypeId: undefined,
},
},
},
methods: {
// 一级下拉框获取考试类型
async getFirstLevelCategory() {
const { data: firstLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: 0 })
for (let i = 0; i < firstLevelCategoryList.length; i++) {
this.getSecondClassify(i, firstLevelCategoryList[i])
}
this.firstLevelCategory = firstLevelCategoryList
},
// 获取二级下拉框
async getSecondClassify(firstIndex, val) {
const { data: secondLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: val.categoryId })
for (let i = 0; i < secondLevelCategoryList.length; i++) {
this.getThirdClassify(firstIndex, i, secondLevelCategoryList[i])
}
this.firstLevelCategory[firstIndex].children = secondLevelCategoryList
},
// 获取三级下拉框
async getThirdClassify(firstIndex, secondIndex, val) {
const { data: thirdLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: val.categoryId })
this.firstLevelCategory[firstIndex].children[secondIndex].children = thirdLevelCategoryList
},
}
</script>
正确代码:
<template>
<a-form-model :model="form" ref="form">
<a-form-model-item label="考试类型" prop="categoryId">
<a-cascader
:model="form.categoryId"
:options="firstLevelCategory"
:field-names="{ label: 'categoryName', value: 'categoryId', children: 'children' }"
placeholder="请选择分类"
@change="changeClassify"
change-on-select
/>
</a-form-model-item>
<a-form-model>
</template>
<script>
import { getPaperCategory, getExamTypes } from '@/views/learn/services/paper'
import { importPaper } from '@/views/makePaper/services/artificial'
export default {
data() {
return {
// value: ref([]),
options: [],
// 第一层级的下拉菜单(考试类型)
firstLevelCategory: [],
secondLevelCategory: [],
thirdLevelCategory: [],
},
form: {
paperName: '',
paperType: undefined,
duration: undefined,
examId: undefined,
examTypeId: undefined,
categoryId: undefined,
paperId: undefined,
score: undefined,
remark: '',
categoryExamTypeId: undefined,
},
},
},
methods: {
// 一级下拉框获取考试类型
async getFirstLevelCategory() {
const { data: firstLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: 0 })
for (let i = 0; i < firstLevelCategoryList.length; i++) {
this.getSecondClassify(i, firstLevelCategoryList[i])
}
this.firstLevelCategory = firstLevelCategoryList
},
// 获取二级下拉框
async getSecondClassify(firstIndex, val) {
const { data: secondLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: val.categoryId })
for (let i = 0; i < secondLevelCategoryList.length; i++) {
this.getThirdClassify(firstIndex, i, secondLevelCategoryList[i])
}
this.firstLevelCategory[firstIndex].children = secondLevelCategoryList
},
// 获取三级下拉框
async getThirdClassify(firstIndex, secondIndex, val) {
const { data: thirdLevelCategoryList = [] } = await getPaperCategory({ parentCategoryId: val.categoryId })
this.firstLevelCategory[firstIndex].children[secondIndex].children = thirdLevelCategoryList
},
}
</script>
更多推荐
所有评论(0)