vant Cascader 级联选择 异步加载

<template>
  <div class="cascader">
    <van-field v-model="fieldValue"
      is-link
      readonly
      :label="label"
      :required="required"
      :rules="rules"
      :placeholder="placeholder"
      @click="show = true" />
    <van-popup v-model="show"
      round
      position="bottom">
      <van-cascader v-model="cascaderValue"
        :title="label"
        :options="options"
        @change="selectChange"
        active-color="#1989fa"
        :field-names="fieldNames"
        @close="show = false"
        @finish="onFinish" />
    </van-popup>
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: String,
      default: () => ''
    },
    isCode: {
      type: Boolean,
      default: () => false
    },
    name: {
      type: String,
      default: () => '默认'
    },
    valueKey: {
      type: String,
      default: () => 'value'
    },
    labelKey: {
      type: String,
      default: () => 'label'
    },
    label: {
      type: String,
      default: () => '默认'
    },
    prop: {
      type: String,
      default: () => ''
    },
    url: {
      type: String,
      default: () => ''
    },
    superCodeVal: {
      type: String,
      default: () => ''
    },
    required: {
      type: Boolean,
      default: () => false
    },
    rules: {
      type: Array,
      default: () => []
    },
    placeholder: {
      type: String,
      default: ''
    },
    lastLevel: {
      type: Number,
      default: () => 3
    }
  },
  data() {
    return {
      show: false,
      fieldValue: '',
      cascaderValue: '',
      fieldNames: {
        text: 'dictName',
        value: 'dictCode'
      },
      options: [],
      isExecute: 1,
      tileArr: []
    }
  },
  methods: {
    // 全部选项选择完毕后,会触发 finish 事件
    onFinish({ selectedOptions }) {
      // this.show = false
      if (this.level > 0) {
        this.show = false
      }

      if (this.isCode) {
        this.fieldValue = selectedOptions.map((option) => `${option.dictName}${option.dictCode})`).join('/')
      } else {
        const fieldValue = selectedOptions.map((option) => option.dictName).join(',')
        if (fieldValue.split('/').length) {
          this.fieldValue = fieldValue
          this.$emit('input', fieldValue)
          return
        }
        this.fieldValue = fieldValue.split(',').join('/')
      }
      this.$emit('input', this.fieldValue.split('/') + '')
    },
    selectChange({ value, selectedOptions, tabIndex, index }) {
      this.level = tabIndex > 0 ? tabIndex - 1 : 0
      // 判断循环了多少次 并且是回显还是重新选择
      if (this.isExecute >= this.lastLevel + 1 && !selectedOptions) {
        return
      }
      // 判断重新选择的个数是否大于传入的lastLevel
      if (selectedOptions && selectedOptions.length >= this.lastLevel) {
        return
      }
      if (this.url) {
        this.$http.post(this.url, { level: this.level, parentCode: value }).then((res) => {
          // 检查重复项
          if (!this.deWeightFour(this.tileArr, res.data)) {
            this.tileArr.push(...res.data)
          }
          if (res.data && res.data.length) {
            this.isExecute++
            this.getDicData(index++)
          }
          this.$set(this, 'options', this.setTreeData(this.tileArr))
        })
      } else {
        console.error('请配置Url地址')
      }
    },
    // 遍历数据并添加children
    setTreeData(source) {
      const cloneData = JSON.parse(JSON.stringify(source)) // 对源数据深度克隆
      return cloneData.filter((father) => {
        // 循环所有项,并添加children属性
        const branchArr = cloneData.filter((child) => father.dictCode === child.parentCode) // 返回每一项的子级数组
        branchArr.length > 0 && (father.children = branchArr) // 给父级添加一个children属性,并赋值
        return father.parentCode === this.superCodeVal // 返回第一层
      })
    },
    // 判断要添加的值是否在这个数组李是否有重复
    deWeightFour(sourceData, inspectData) {
      const source = sourceData.map((item) => item.id)
      return inspectData.map((item) => source.includes(item.id)).includes(true)
    },
    getDicData(tabIndex = 0) {
      // eslint-disable-next-line no-useless-escape
      const str = this.value.split(',').map((item) => item.replace(/\([^\)]*\)/g, ''))
      const items = str[tabIndex]
      this.tileArr.forEach((item) => {
        if (item.dictName === items) {
          console.log(item.dictCode)
          this.cascaderValue = item.dictCode
          this.selectChange({ value: item.dictCode, tabIndex: 0, index: ++tabIndex })
        }
      })
    }
  },
  created() {
    this.fieldValue = this.value.split(',').join('/')
    this.selectChange({ value: this.superCodeVal, tabIndex: 1 })
  },
  watch: {
    value: {
      handler(v) {
        this.fieldValue = this.value.split(',').join('/')
      }
    },
    show: {
      handler(v) {
        if (v && this.fieldValue && this.isExecute) {
          this.getDicData()
        }
      }
    }
  }
}
</script>

<style>
</style>

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vant级联选择器组件可以通过异步加载来实现动态加载级联数据。具体实现方法如下: 1. 在选择器组件中设置 `:load-data="loadData"` 属性,指定加载数据的方法。 2. 实现 `loadData` 方法,该方法接收一个参数 `item`,表示当前需要加载子级数据的选项。该方法应返回一个 Promise 对象,在 Promise 对象的回调函数中,将子级数据作为 Promise 对象的返回值返回。 3. 在 `loadData` 方法中,根据 `item` 的值,异步加载子级数据,并将子级数据作为 Promise 对象的返回值。 4. 在 `loadData` 方法中,如果需要在加载数据时显示 loading 状态,可以使用 Vant 的 Loading 组件,在加载数据前调用 `this.$toast.loading()` 方法显示 loading 状态,在加载完成后调用 `this.$toast.clear()` 方法隐藏 loading 状态。 下面是一个示例代码: ```html <van-cascade-picker :data="cascadeData" :load-data="loadData" ></van-cascade-picker> ``` ```js export default { data() { return { cascadeData: [ { value: '1', label: '一级选项' } ] } }, methods: { loadData(item) { // 显示 loading 状态 this.$toast.loading({ message: '加载中...', duration: 0 }); // 异步加载子级数据 return new Promise(resolve => { setTimeout(() => { const childData = [ { value: '1-1', label: '二级选项' } ]; // 隐藏 loading 状态 this.$toast.clear(); // 将子级数据作为 Promise 对象的返回值返回 resolve(childData); }, 1000); }); } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值