• 使用 element-ui 级联插件遇到的坑


    需求描述【省市区三级联动】

    组件:Cascader 级联选择器

    • 后端需要所选中的地区的名字,如:['北京市', '北京市', '东城区']
    • 获取后端省市区具体列表的接口返回数据:
    // 省 - 参数1
    [
      {
        value: 1,
        label: '北京市'
      },
      ...
    ]
    // 市 - 参数2
    [
      {
        value: 1,
        label: '北京市'
      },
      ...
    ]
    // 区 - 参数3
    [
      {
        value: 1,
        label: '东城区'
      },
      ...
    ]
    
    • 因 element-ui 级联选择器 Cascader 有可以直接获取指定字段的属性,所以直接使用
    {
        value: this.label
    }
    
    • 一般情况下都没有问题,偶然发现当省市区有名字一样时出现没有值选中的情况,如:['北京市', '北京市', '东城区']
    • 发现接口也有点问题

      组件的回调级别 level 在相同内容的情况下,返回的一直是最上层的节点,猜想可能是 level 的判断的问题,于是只能找源码了

    经常不断打断点终于找到的原因所在

    • 问题原因:查找节点的方法,不管当前找到了几个节点,都会只返回第一个节点,然后第一个节点肯定是在最前面的所以级别最高 level 是1,这个应该是一个问题,还得想下怎么才能解决自己的问题
     // cascader-panel/src/store.js
     
     getNodeByValue(value) {
        if (value) {
            const nodes = this.getFlattedNodes(false, !this.config.lazy)
                .filter(node => (valueEquals(node.path, value) || node.value === value));
            return nodes && nodes.length ? nodes[0] : null;
        }
        return null;
     }
    


    • 既然组件是必须唯一找到才能正常,那我只能设置一个唯一的值了,把层级【级别】也加到里面去,这样就能显示唯一的,最后返回出来时再把层级【级别】去掉就好了

    本来是想用 computed 做转换的,结果发现转换有问题,只能用 watch 了,感觉 watch 性能可能会不大好,自己一般情况下能用 computed 解决的绝不用 watch 的

    • 组件实现代码:

    显示的值还是 label
    比对的值是 value, 确定唯一的值
    返回到父组件的值要做对应的去格式化处理

    <template>
      <div class="the-city-cascader">
        <el-cascader
          class="city-cascader"
          :separator="separator"
          v-on="$listeners"
          v-bind="$attrs"
          v-model="innerValue"
          :options="cityOptions"
          :props="cascaderProps"
          @change="changeHandle"
        >
        </el-cascader>
      </div>
    </template>
    
    <script>
    export default {
      name: 'the-city-cascader',
      props: {
        value: {
          type: [Array, String],
          default: () => []
        },
        expandTrigger: {
          type: String,
          default: 'click'
        },
        /**
         * value 传出的字段组
         */
        valueKey: {
          type: String,
          default: 'value',
        },
        separator: {
          type: String,
          default: ' / ',
        },
      },
      data() {
        return {
          cityOptions: [],
          innerValue: [],
          isLazy: true,
        };
      },
      computed: {
        cascaderProps() {
          return {
            expandTrigger: this.expandTrigger,
            value: this.valueKey,
            lazy: true,
            lazyLoad: async (node, resolve) => {
              const { data, level } = node
              let nodes = []
              const findLevel = level + 1
              if (level === 0) {
                nodes = await this.initCityList(findLevel)
              } else {
                nodes = await this.initCityList(findLevel, data.code)
              }
              nodes.forEach(item => {
                if (findLevel < 3) {
                  item.leaf = false
                } else {
                  item.leaf = true
                }
              })
              // 通过调用resolve将子节点数据返回,通知组件数据加载完成
              resolve(nodes)
            }
          }
        },
      },
      created() {
        this.innerValue = this.value.map((item, itemI) => `${itemI + 1}-${item}`)
      },
      methods: {
        /**
         * 省1市2区3
         */
        async initCityList(flag, areaId = 0) {
          const params = { flag, areaId }
          let result = []
          try {
            const { data, status } = await this.axios.get(this.$API.cascaderCity, { params })
            if (status === 200) {
              result = (data.result || []).map(item => ({
                // 显示的值
                label: item.label,
                // 值的id
                value: `${flag}-${item.label}`,
                // 接口参数的值
                code: item.value,
              }))
            }
          } catch (error) {
            console.error(error)
          }
          return result
        },
        changeHandle(val) {
          const list = val.map(item => {
            const splitList = item.split('-')
            if (splitList.length > 0) {
              return splitList[1]
            } else {
              return splitList[0]
            }
          })
          this.$emit('input', list)
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .the-city-cascader {
       100%;
      .city-cascader {
         100%;
      }
    }
    </style>
    
    
  • 相关阅读:
    【IDEA】IDEA自定义注解无法自动识别入参和出参
    vue脚手架安装成功,但依然提示'vue' 不是内部或外部命令,也不是可运行的程序 或批处理文件。解决方案
    小程序怎么将input宽输入字母全部转大写字母
    微信小程序van-popup左右弹窗无法显示白色背景
    vscode中实现滚轮缩放代码
    element-ui监听el-dialog关闭事件
    测试人必看的5本好书,没看过你就吃亏啦~
    解决Access在Windows7下数据源的配置问题(32位)
    微软Win10补丁KB5005565更新后打印机连接不上(0x0000011b)
    Windows设置共享文件夹无法访问问题
  • 原文地址:https://www.cnblogs.com/chentingjun/p/11858855.html
Copyright © 2020-2023  润新知