表单中的联动下拉框代码思路

问题描述

我们常常在表单中会遇到联动下拉框的需求,最常见的例子是省、市、区的联动。一般联动的特点在于:

  1. 前一级变化时,后面所有层级全部清空:包括下拉框本身的值和下拉框的枚举

  2. 后一级的枚举会带着前一级的某个参数(如id)查询接口

如果只是一个新增表单上面两个注意点在编码过程中,稍加注意即可,用一个 watch 监听事件就可以很好的实现联动。下面我们将以省、市、区的案例简单整理下逻辑。

省、市、区常规案例

下面以vue+伪代码的形式大致梳理下整体思路

定义变量:

// 在vue3中的代码,可以参考思路

const form = reactive({
  province: '',   // 省
  city: '',       // 市
  area: '',       // 区
});

// 枚举
const provinceEnums = ref([]);
const cityEnums = ref([]);
const areaEnums = ref([]);
 

监听省变化:

 watch(
   () => form.province,
   (val) => {
     // 1. 清空市
     form.city = '';
     
     // 2. 如果val有值(选择了新的),根据新选的省查询市的枚举,如果val没有值,则是清空操作,则清空市的枚举
     if (val) {
       // 重新获取市的枚举
       // todo
     } else {
       // 清空市的枚举
       cityEnums.value = [];
     }
   }
 )

监听市变化:

watch(
   () => form.city,
   (val) => {
     // 1. 清空区
     form.area = '';
     
     // 2. 如果val有值(选择了新的),根据新选的市查询区的枚举,如果val没有值,则是清空操作,则清空区的枚举
     if (val) {
       // 重新获取区的枚举
       // todo
     } else {
       // 清空区的枚举
       areaEnums.value = [];
     }
   }
 )

问题描述

如果我们采用了上面的方案,在做新增的时候是没有问题的,但如果我们有重新编辑表单的操作的时候就会出问题了。问题的主要原因在于异步

我们试想一下,还是上面的逻辑,编辑较新增不同的地方在于,表单是有初始值的,这一份数据来自于上一次保存的数据。所以我们的代码会多一步:获取详情数据并赋值

 // 获取详情数据并赋值
 const getDetailData = async () => {
   // 1. 请求接口
   let data = await getDetail();
   
   // 2. 赋值
   form.province = data.province;
   form.city = data.city;
   form.area = data.area;
 }

在实际效果中就可能会出现问题。问题主要是因为 : 使用了watch。我们来梳理这个逻辑:

  1. form.province赋值

  2. form.city赋值

  3. form.area赋值

  4. 触发 city.watch 监听,并在这个时候 清空了 form.area

  5. 触发 province.watch,并在这个时候 清空了 form.city

下面是控制台输出的顺序:

 体现在我们页面上的效果是:只有省有值,市、区的值因 watch执行顺序慢于赋值而被清空

 当然我们可以在watch中添加一些限定条件,比如判断是否是详情进入的,比如在监听省的时候,通过判断是否有 oldVal,来做一些判断,这里就不展开介绍了。

watch(
  () => form.province,
  (val, olaVal) => {
    if (oldVal) {
      // todo
    }
  }

新的思路 onChange

对于这种问题,最后想到的解决方案是,放弃watch监听,因为它的监听模式是自动开启的,只有有变化就会按照固有代码执行,而我们需要的是会根据:

  • 编辑模式第一次进入状态

  • 常规切换状态

来控制代码的逻辑。所以我们不用watch,而用输入框自带的 onChange 事件

这里做一下简单的区别:

  • watch:只要vModel的值变化就会监听到

  • onChange:通过触发输入框改变才会触发事件本身

这就意味着,我们在获取到详情数据赋值时,是不会触发onChange事件的,那这个里面的逻辑就全部由我们自己定制。

获取详情并赋值

// 获取详情数据并赋值
const getDetailData = async () => {
  // 1. 请求接口
  let data = await getDetail();
  
  // 2. 赋值
  form.province = data.province;
  // 获取市枚举
  cityEums.value = await getCityByProvince(form.province);
  // 更新市
  form.city = data.city;
  // 获取区枚举
  cityEums.value = await getAreaByCity(form.area);
  // 更新区
  form.area = data.area;
}

总结

目前遇到这一类问题,我主要用 onChange 代替 watch。如果在比较复杂的业务场景下,一定要用watch来实现的话,可能代码会比较复杂,这个时候不妨考虑下 onChange

以上是本人个人观点,有更好的处理方式可以一起分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值