el-select下拉滚动加载更多封装成组件 — vue技术交流群(864583465)
前言:该组件基于typescript 和vue2的class写法,组件代码如下:
<template>
<el-select
size="mini"
v-model="value"
filterable
:multiple="multiple"
:clearable="clearable"
:allow-create="allowCreate"
@change="selectChanged"
@clear="selectChanged"
v-el-select-loadmore="loadMore(rangeNumber)"
:filter-method="filterMethod"
value-key="index"
:placeholder="placeholder">
<el-option
v-for="item in searchedOption.slice(0, rangeNumber)"
:key="item.index"
:label="item[labelValueObj.label]"
:value="item[labelValueObj.value]"/>
</el-select>
</template>
<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import { PropType } from 'vue';
@Component({
directives: {
'el-select-loadmore':(el, binding) => {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
if(SELECTWRAP_DOM){
SELECTWRAP_DOM.addEventListener('scroll', function () {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,
* 常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 10;
if (condition) binding.value();
});
}
},
}
})
export default class extends Vue {
@Prop({ type: String, default: '' }) placeholder
@Prop({ type: Boolean, default: false }) clearable
@Prop({ type: Boolean, default: false }) allowCreate
@Prop({ type: Boolean, default: false }) multiple
@Prop() selectValue
@Prop({ type: Array, default: () => [] }) options
@Prop({ type: Object as PropType<{ label: string, value: string }>, default: () => {} }) labelValueObj
@Prop({ type: Array as PropType<string[]>, default: '' }) searchMatchFields // 搜索时需要匹配的字段
private rangeNumber: number = 10
private searchedOption = []
private value: string | number | string[] | number[] = ''
@Watch('multiple', { immediate: true })
multipleChanged(val){
if(val){
this.value = []
}
}
@Watch('selectValue')
selectValueChanged(val){
this.value = val
}
get optionsStr(){
return JSON.stringify(this.options)
}
@Watch('optionsStr', { immediate: true })
optionsChanged(){
this.searchedOption = this.options.map((item, index) => {
return {
...item,
index: index
}
})
}
selectChanged(val){
this.$emit('update:selectValue', val)
}
loadMore(n) {
console.log('loadMore:' + n, this.rangeNumber)
// n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
// elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数 可自定义
}
filterMethod(query = ''){
try {
console.log('query:' + query)
this.rangeNumber = 10
if(this.searchMatchFields.length === 0){
this.searchedOption = this.options.slice(0)
} else {
this.searchedOption = this.options.filter(item => {
return this.fmtFilterCondition(item, query)
})
}
} catch (e) {
console.log(e)
}
}
fmtFilterCondition(item, query){
for (let field of this.searchMatchFields) {
if(item[field] !== undefined && item[field] !== null && item[field].includes(query)){
return true
}
}
return false
}
}
</script>
如何调用代码如下:
<template>
<div>
<div>当前选择值:{{ userId }}</div>
<select-load-more
placeholder="请选择用户或输入用户姓名或用户id"
:clearable="true"
:select-value.sync="userId"
:options="userList"
:label-value-obj="{ label: 'name', value: 'id' }"
:search-match-fields="['name', 'id']"
/>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
@Component({
components: {
'select-load-more': () => import('组件位置/el-select-scroll-load-more.vue')
}
})
export default class extends Vue {
private userId: string = ''
private userList = [
{
id: 1,
name: '张三',
age: 20,
sex: '男'
},
{
id: 2,
name: '张三2',
age: 20,
sex: '男'
},
{
id: 3,
name: '张三3',
age: 20,
sex: '男'
},
{
id: 4,
name: '张三4',
age: 20,
sex: '男'
}
]
}