一. 介绍以及基础使用

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)初始都是空的,因为数据全都是从服务端过来的,并没有什么默认的数据。我要做的就是,当打开这个页面的时候,数据开始加载进去,直到我点击分类的时候,所有数据已经加载完成。好了,明白了要干什么我们就可以开始写代码了。

  1. 首先,打开这个页面数据开始加载,所以我把加载数据的函数方法放在了vue的生命周期函数created()里面。
  2. 定义三个存储数组firstLevelCategorysecondLevelCategorythirdLevelCategory分别用于存储三个层级的下拉菜单(因为我写的项目所用到的数据只有三个层级,若是遇到更多的层级的话,可以使用this.$set进行对象属性的添加,使用this.$set还有一个好处,视图可以实时的更新,因为视图层实时更新是需要data()里面的数据发生了变化才会更新状态,使用this.$set添加对象可以达到一样的效果),三个存储数组之间的关系就是firstLevelCategorychildren数组是secondLevelCategorysecondLevelCategorychildren数组是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参数的话,每次获取分类数据时,会一直需要将服务端传过来的数据赋值给labelvalue字段,就像这样:

		targetOption.children = [
            {
              label: `${targetOption.label} 服务器端加载1`,
              value: 'dynamic1',
            },
            {
              label: `${targetOption.label} 服务器端加载2`,
              value: 'dynamic2',
            },
          ];

如果我们加上fieldNames参数,对原始字段名进行重定义的话,就可以将服务端传过来的数据直接拿来使用,而不需要搞什么赋值之类的操作,不需要进行数据的处理,因为同名的字段会自动匹配到一起去。比如,我需要的是categoryIdcategoryName这两个参数:
在这里插入图片描述

: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>
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐