一个页面有多个el-cascader级联选择器时,怎么解决动态加载和回显问题

前言

在做vue2后台管理项目时,有个是使用el-cascader动态选择省市及回显的需求,并且一个页面中有多个el-cascader,在网上搜了很多,大都讲的是一个el-cascader怎么实现动态加载,现在记录一下一个页面中有多个el-cascader应该注意的点。


一、效果图

在这里插入图片描述如图所示,第一行选择了东城、西城和市中心,第二行就不能再选择这三个。

二、使用ref来区分多个el-cascader

:ref=“cascader_${index}”,其中 index 是 table 的行,要使用模板字符串``,optionsList 是数据源,
v-if=“showCascader” 很重要,没有它编辑的时候就回显不了,limitContent.limits是table的数据源。

代码如下:

<template slot="citiesCode" slot-scope="text, record, index">
  <div class="casBox">
    <el-cascader
      :options="optionsList"
      :props="props"
      :ref="`cascader_${index}`"
      v-if="showCascader"
      :append-to-body="false"
      v-model="limitContent.limits[index].citiesCode"
      clearable
      :show-all-levels="false"
      @change="changeHandler($event, index)"
    ></el-cascader>
  </div>
</template>

三、动态加载

获取省信息我放到了mounted里面执行了,这里的optionsList 里面默认添加上了全国,并且全国是叶子节点,然后当点击某一个省时,会触发 lazyLoads 方法。
代码如下:

    // 获取省信息
    getProviceList () {
      '接口名称'({id:'00'}).then((res) => {
        const result = JSON.parse(res.result)
        this.optionsList = [...this.optionsList, ...result.orgInfoList]
      })
    },
    // 动态加载方法
    async lazyLoads (node, resolve) {
      if (node.level == 1) {
        if (!node.data.children && node.data.orgId != '00') {
          const res = await this.getCityList(node.data.orgId)
          resolve(res)
        } else {
          if (node.data.orgId != '00') {
            if (node.children.length == 0) {
// 此处对于有多个级联选择器特别重要,如果不加判断那么会出现如下情况:当第二个级联选择器点击了天津,
//然后再点击第一个级联选择器,点击天津就不会出现二级面板,因为此时的node.children是空数组(我在这个坑
//里面挣扎了好久o(╥﹏╥)o)。resolve([])执行的数组追加方法。
              resolve(node.data.children)
            } else {
              resolve([])
            }
          }
        }
      } else if (node.level == 2) {
        resolve([])
      }
    },
    // 通过省份id获取市
    getCityList (id) {
      return '接口名称'({ id: id })
        .then((res) => {
          if (res.code == 0) {
            const result = JSON.parse(res.result)
            const cityList = result.orgInfoList
            cityList.forEach((item) => {
              item.leaf = true // 因为默认只有两级,市级的就直接设置为叶子结点了
            })
            this.optionsList.forEach((option, index) => {
              if (option.orgId == suprrOrgId) {
                option.children = cityList
              }
            })
            return cityList
          }
        })
        .catch((error) => {
          // 此处调用resolve 防止接口数据异常时级联选择器一直处于加载状态
          return []
        })
    },

四、选择后置灰

1、置灰是产品提的,为了不重复选择省市。我虽然实现了,但是体验不好,因为选择了就会置灰,没有反悔的可能(-_-||),只能把这一行删除。getCheckedNodes 是获取选中的节点。
代码如下:

    changeHandler (val, index) {
      const nodesInfo = this.$refs['cascader_' + index].getCheckedNodes()
      nodesInfo.forEach((item) => {
        this.$set(item.data, 'disabled', true)
      })
    },

2、上面的方式不好用,好用的来啦~
修改之后的效果如下:
在这里插入图片描述第一行选择后,第二行就不能再选,但当前行选择后可以修改。之前用的是change事件,只要选择某一项就会触发change事件,在change方法里面会把选择的选项置灰;现在使用的是visible-change事件,即下拉框出现/隐藏时触发。
代码如下:

<template slot="citiesCode" slot-scope="text, record, index">
    <div class="casBox">
      <el-cascader
        :options="optionsList"
        :props="props"
        :ref="`cascader_${index}`"
        v-if="showCascader"
        :append-to-body="false"
        v-model="limitContent.limits[index].citiesCode"
        clearable
        :show-all-levels="false"
        @visible-change="visibleHandler($event, index)"
      ></el-cascader>
    </div>
  </template>
visibleHandler (val, index) { // val是 true 或 false
  const nodesInfo = this.$refs['cascader_' + index].getCheckedNodes() // 获取当前级联选择器已选择的选项
  if (val) {
    nodesInfo.forEach((item) => {
      this.$set(item.data, 'disabled', false)
      if (item.parent) {
        this.$set(item.parent.data, 'disabled', false)
      }
    })
  } else {
    nodesInfo.forEach((item) => {
      this.$set(item.data, 'disabled', true)
    })
  }
}

五、回显

编辑的时候先请求详情接口,然后调 formatting() 方法来处理省市的回显。

limitHandler (record) {
      this.getProviceList()
      '接口名称'({ id: record.id }).then(async (res) => {
        if (res && res.code === 0) {
          const result = res.result
          this.limitContent.limits = result
          if (result.length > 0) {
            result.forEach((item) => {
              if (item) {
                item.citiesCode = JSON.parse(item.citiesCode)
              }
            })
            await this.formatting() // 调处理回显的方法
            this.showCascader = true // 等回显的数据处理完后再显示级联选择器
            this.$nextTick(() => { // 此处是为了把回显的数据置灰
              this.limitContent.limits.forEach((item, index) => {
                this.changeHandler('', index) // 手动调changeHandler方法
              })
            })
          } else {
            this.showCascader = true
          }
        }
      })
    },
    async formatting () {
      const limitData = JSON.parse(JSON.stringify(this.limitContent.limits)) // 简单的深复制一下
      for (let i = 0; i < limitData.length; i++) {
        const citiesList = limitData[i].citiesCode // 如:[[11,11600],[11,2333]]
        let list = []
        for (let m = 0; m < citiesList.length; m++) {
          list.push(citiesList[m][0])
        }
        list = [...new Set(list)] // 去重,稍微提一下性能。。。
        for (let m = 0; m < list.length; m++) {
        // 此处循环调接口非常不可取(给产品说了,他能接受 (*^▽^*)),优化啥的以后再说吧-_-||
          await this.getCityList(list[m])
        }
      }
    },
    findItem (res, arr, id) {
      for (let i = 0; i < res.length; i++) {
        if (!res[i].children && res[i].orgId == id) {
          res[i].children = arr
          return
        }
        if (res[i].children) {
          this.findItem(res[i].children, arr, id)
        }
      }
    },

六、删除

删除一行后,要把置灰的市,变为可选的。

// 删除
   delHandler (index) {
     const _this = this
         _this.limitContent.limits.splice(index, 1)
         const nodesInfo = _this.$refs['cascader_' + index].getCheckedNodes()
         nodesInfo.forEach((item) => {
           _this.$set(item.data, 'disabled', false)
           if (item.parent) { // 如果是市,那么对应的省也要变为可选
             _this.$set(item.parent.data, 'disabled', false)
           }
         })
    }
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于 Element UI 的级选择 el-cascader,如果需要回显已经选中的值,可以通过设置 v-model 和 :options 属性来实现。 假设有一个三级动的级选择,选项数据如下: ``` options: [{ value: 'zhinan', label: '指南', children: [{ value: 'shejiyuanze', label: '设计原则', children: [{ value: 'yizhi', label: '一致' }, { value: 'fankui', label: '反馈' }] }, { value: 'daohang', label: '导航', children: [{ value: 'cexiangdaohang', label: '侧向导航' }, { value: 'dingbudaohang', label: '顶部导航' }] }] }] ``` 如果需要回显已经选中的值,可以将当前选中的值通过 v-model 绑定到 data 中的一个变量上,例如: ``` <el-cascader v-model="selectedOptions" :options="options" ></el-cascader> ``` 其中,selectedOptions 是一个数组,用于保存当前选中的值。 接下来,需要在 mounted 钩子函数中设置已选中的值,例如: ``` mounted() { this.selectedOptions = ['zhinan', 'shejiyuanze', 'yizhi'] } ``` 这样,在页面完成后,级选择就会自动回显已经选中的值。 需要注意的是,如果级选择的选项数据是异步的,需要在完成后再设置已选中的值,例如: ``` mounted() { this.loadOptions().then(() => { this.selectedOptions = ['zhinan', 'shejiyuanze', 'yizhi'] }) }, methods: { loadOptions() { // 异步选项数据 } } ``` 这样就可以实现 Element UI 的级选择 el-cascader回显功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值