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