下拉框渲染大量数据时的解决方案

如果在下拉框中直接一次性渲染几百上千条数据可能导致页面卡死或报错,所以要分批次载入。使用频率较高,所以封装成一个组件,该组件效果类似于触底加载。支持搜索,且能够正常回显数据。该组件可拿来即用

组件代码

// 下拉框渲染多数据时的解决方案
<template>
  <a-form-model-item :label="config.label" :prop="config.prop" :rules="rules">
    <a-select
      allowClear
      show-search
      style="width: 100%"
      v-model="form[config.prop]"
      option-filter-prop="children"
      :placeholder="loading ? '正在加载...' : '请选择'"
      :mode="mode"
      :loading="loading"
      :disabled="loading"
      @popupScroll="handlePopupScroll"
      @search="handleSearch"
      @select="handleSelect"
    >
      <a-select-option v-for="(item, index) in options" :key="index" :value="item[config.code]">
        {{ item[config.name] }}
      </a-select-option>
    </a-select>
  </a-form-model-item>
</template>

<script>
import debounce from 'lodash/debounce'

export default {
  props: {
    // 一个引用类型数据,达到双向绑定的作用
    form: { type: Object, default: () => {} },
    rules: { type: Array, default: () => [] },// 表单验证
    originData: { type: Array, default: () => [] },// 原始数据
    mode: { type: String, default: 'default' },// 多选还是单选 multiple为多选
    // 配置项 {label:'船舶名称',prop:'vesselName',code:'vesselId',name:'vesselName'}
    // code为下拉数据显示的值,name为下拉数据提交的值
    config: { type: Object, default: () => {} },
  },
  data () {
    // this.searchUser = debounce(this.searchUser, 800) // 防抖
    return {
      searchName: null, // 下拉框搜索值
      loading: false, // 下拉框数据加载
      options: [], // 下拉框中载入数据
    }
  },
  watch: {
    originData: function (newVal, oldVal) {
      if (newVal && newVal.length > 0) {
        this.getOptions(newVal)
      }
    },
  },
  methods: {
    // 得到下拉框中的载入数据
    getOptions () {
      if (this.searchName) {
        // 根据搜索值过滤数据
        const data = this.originData.filter(
          (x) => x[this.config.name] && x[this.config.name].indexOf(this.searchName) > -1
        )
        this.options = data
      } else {
        // 展示前20条数据
        this.options = this.originData < 20 ? this.originData : this.originData.slice(0, 20)
        // 用于回显 这样写就需要,先查询表单数据再查询下拉数据
        if (this.form[this.config.prop]) {
          // select的mode是否为多选
          let data = []
          if (this.mode === 'multiple') {
            data = this.originData.filter((x) => this.form[this.config.prop].includes(x[this.config.code]))
          } else {
            data = this.originData.filter((x) => this.form[this.config.prop] === x[this.config.code])
          }
          if (data && data.length > 0) {
            this.options = [...this.options, ...data]
          }
        }
      }
    },
    // 下拉列表滚动事件
    // 实现思路:当前下拉的展示列表+10小于全部数据的长度,newArr为新加载的10条数据,当前展示列表拼上新加载的10条;否则, newArr为全部列表中剩余的数据,当前展示列表拼上剩余的数据。
    handlePopupScroll: debounce(function () {
      if (this.loading === false) {
        const curLen = this.options.length
        const allLen = this.originData.length
        if (curLen + 10 < allLen) {
          const newArr = this.originData.slice(curLen, curLen + 10)
          this.options = this.options.concat(newArr)
        } else {
          const newArr = this.originData.slice(curLen, allLen)
          this.options = this.options.concat(newArr)
        }
      }
    }, 500),
    // 搜索事件
    handleSearch: debounce(function (val) {
      this.searchName = val
      this.getOptions()
    }, 500),
    // 选中事件
    handleSelect () {
      if (this.searchName) {
        this.searchName = null
        this.getOptions()
      }
    },
  },
}
</script>

使用组件

<template>
    <a-form-model :model="form" :rules="rules">
        <!-- 多选时需要添加mode="multiple",并且form里的member属性值要改为数组 -->
        <SelectLimit
        :form="form"
        :rules="rules.member"
        :originData="originData"
        :config="{ label: '船舶名称', prop: 'member', code: 'id', name: 'name' }"
        />
    </a-form-model>
</template>

<script>
import SelectLimit from '@/components/MyComponents/SelectLimit/index.vue' // 渲染多数据的下拉框
import { query } from '@/views/yangtze/express/vessel/service/vesselService' // 根据实际修改

export default {
  name: 'BaseForm',
  components: { SelectLimit },
  data () {
    return {
      form: {
        // member: ['11240002','11240019'] ,// mode: 'multiple'
        member: '11240002'
      },
      rules: {
        member: [{ required: true, message: '必填' }],
      },
      originData: [], // 原始数据
    }
  },
  mounted () {
    this.queryOriginData() // 查询全部数据
  },
  methods: {
    // 查询全部数据
    queryOriginData () {
      const param = { current: 1, pageSize: 100 }
      query(param).then((res) => {
        if (res.code === '0') {
          const data = res.data || {}
          const list = data.list || []
          this.originData = list.map((x) => ({ id: x.id, name: x.name })) // 得到全部数据
        }
      })
    },
  },
}
</script>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值