Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道...

  1. 最近在做一个移动端的H5项目,从后端获取省市区数据实现省市区等数据多级联动,运用的vant,大家可以先去有赞官网看Cascader的介绍,链接:有赞Vant3.6.12(没错我用的是3);
<template>
     <van-field v-model="userInfo.nowAddress" placeholder="请输入现居住地址" label="现居住地址" input-align="right" @click="onClickCascader" />
        <!--现居住地址 级联选择框 -->
        <van-popup v-model:show="showCascader" round position="bottom">
          <van-cascader v-model="cascaderAddress" title="请选择所在地区" :options="options" @close="showCascader = false"
            @change="onChange" @finish="onFinish" />
        </van-popup>
</template>
  • 由于我的项目的地址是固定广东省,所以options初始值设置为:
options: [{
  text: '广东省',
  value: '440000',
  children: [],
}],
  • 后端根据value的传值获取不同的市、区、街道等,直到返回为空;
<script>
import { Cascader, Popup } from 'vant'
import {  reactive, toRefs } from "vue"
import { getAllCity } from "@api/user"
export default {
  name: 'userInfo',
  components: {
    [Cascader.name]: Cascader,
    [Popup.name]: Popup,
  },
  setup() {
    const state = reactive({
      userInfo: {//用户个人信息,此处只放现居住地址nowAddress
      	nowAddress:'',
      },
      showCascader: false,//是否显示级联选择
      cascaderAddress: '',//绑定的是当前选择的 value值(如:选择了广东省,当前值为440000)
      options: [{
        text: '广东省',
        value: '440000',
        children: [],
      }],
    });
   
    const onClickCascader = () => {
      state.showCascader = true;
    };
    //获取数据
    const getAreas = async (value) => {
      const { result } = await getAllCity(value);
      return result;
    };
    const onChange = ({ value, tabIndex, selectedOptions }) => {
      if (tabIndex === 0) {
        getAreas(value).then((res) => {
          if (res.length) {
            addTree(selectedOptions, res, value);
          }
        });
      }
    };
    const addTree = (selectedOptions, res, value) => {
      selectedOptions.forEach(item => {
        if (item.value === value) {
          item.children = res;
        }
      })
    };
    const onFinish = ({ value, tabIndex, selectedOptions }) => {
      console.log('onFinish', selectedOptions, state.finishIndex, tabIndex);
       state.showCascader = false;
       state.userInfo.nowAddress = selectedOptions.map((option) => option.text).join('');
    };
    return {
      ...toRefs(state),
      onClickCascader,
      onChange,
      onFinish
    }
  }
}
</script>
  • 此处需要着重说明的是,点击广东省的时候(tabIndex=0),触发的是onChange 事件,但是后续选择会触发onChange 事件和onFinish事件,本身我以为下图事件说明的意思是点击不同的省、市、区、街道…触发的是onChange 事件,直到选择完最后一层(该层没有了children属性)就表明全部选项选择完成,触发onFinished事件;

  • 上述代码就是onChange 事件为每个层级获取children数数组,onFinish事件则关闭级联选择(state.showCascader = false;),并将选择的所有数据进行拼接获取nowAddress 的值(state.userInfo.nowAddress = selectedOptions.map((option) => option.text).join(‘’););

  • 但是事实结果不是这样,除了第一层点击没有问题之外,点击第二层以及往后的每一层,级联选择器会关闭了,再次点击打开,数据还保存在上一次点击的状态,很明显,这触发了onFinish事件,关闭了级联选择器。

  • 我尝试在onFinish事件中进行判断,记录当请求数据为空的时候,说明当前层级没有children,试了之后发现并不能控制onFinish事件的触发,该事件并不根据是说没有children属性就触发onFinish事件;

  • 试了很多次,不知道是我理解问题还是我哪里出错了;

  • 如图:

    • 选择第一层:只触发onChange 事件

Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第1张图片

Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第2张图片

  • 选择第二层:触发onChange 事件和onFinish事件
    Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第3张图片
    Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第4张图片

  • 选择第三层:触发onChange 事件和onFinish事件
    Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第5张图片
    Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第6张图片

  • 后续层级不再赘述

  • 如果我的理解错了的话,根据上述得出结果:首次点击触发onChange ,后面触发onFinished,因此,为了控制

Vue Vant Cascader级联选择 异步加载地区数据 实现省市区街道..._第7张图片

  • 解决办法:
    首次点击 在onChange事件中插入数据,后续点击,在onFinish 中插入数据,存在则插入,不存在则关闭级联选择器,问题解决;
    const onChange = ({ value, tabIndex, selectedOptions }) => {
      console.log('onChange',value, tabIndex, selectedOptions[tabIndex].text);
      if (tabIndex === 0) {
        getAreas(value).then((res) => {
          if (res.length) {
            addTree(selectedOptions, res, value);
          }
        });
      }
    };
    const onFinish = ({ value, tabIndex, selectedOptions }) => {
      console.log('onFinish', value, tabIndex, selectedOptions[tabIndex].text);
      getAreas(value).then((res) => {
        if (res.length) {
          addTree(selectedOptions, res, value);
        } else {
          state.showCascader = false;
          state.userInfo.nowAddress = selectedOptions.map((option) => option.text).join('');
        }
      });
    };
  • 看了下很多文档并没有类似问题以及说明,记录一下,希望给你一点思路;
  • 当然该解决办法不一定是最优的,欢迎来讨论。

你可能感兴趣的:(前端学习原创文,vue.js,javascript,前端)