背景
随着公司业务越来越来,越来越大,前端很多页面都要做懒加载、避免页面卡顿。
直接上代码(重点关注地方会有备注)
.vue文件代码
- 这里的话,因为要把原有elementUI组件,原有的属性都继承过来,除了几个固定配置属性项。
- 重点项会有备注
<template>
<el-select
ref="el-select"
class="lazy-select"
:value="value"
:placeholder="placeholder"
:multiple="multiple"
:clearable="clearable"
:filterable="filterable"
:disabled="disabled"
:filter-method="filterMethod"//查询自定义过滤方法
:popper-class="popperClass"//下拉选项弹出框类名
reserve-keyword
:collapse-tags="collapseTags"
:autocomplete="autocomplete"
:automatic-dropdown="automaticDropdown"
:size="size"
:allow-create="allowCreate"
:loading="loading"
:loading-text="loadingText"
:no-data-text="noDataText"
:default-first-option="defaultFirstOption"
:popper-append-to-body="popperAppendToBody"
:value-key="valueKey"
@change="change"
@visible-change="visibleChange"//下拉选项弹出框的显示与隐藏事件
@remove-tag="(e)=>$emit('remove-tag',e)"
@clear="(e)=>$emit('clear',e)"
@blur="(e)=>$emit('blur',e)"
@focus="(e)=>$emit('focus',e)"
>
<el-option
v-for="item in newOptions"
:key="item[props.value]"
:label="item[props.label]"
:value="item[props.value]"
/>
</el-select>
</template>
<script>
import index from './index'
export default index
</script>
<style lang="scss" scope>
@import 'style.scss';
</style>
.js文件代码
重点项会有备注,其余属性与官方文档作用相同,
export default {
name: 'lazy-select',
components: {},
props: {
value: {
require: true
},
disabled: Boolean,
clearable: {
type: Boolean,
require: false,
default: true
},
filterable: {
type: Boolean,
require: false,
default: true
},
placeholder: {
type: String,
require: false,
default: '请选择'
},
multiple: Boolean,
collapseTags: {
type: Boolean,
require: false,
default: true
},
autocomplete: {
type: String,
default: 'off'
},
/** @Deprecated in next major version */
autoComplete: {
type: String,
validator(val) {
process.env.NODE_ENV !== 'production' &&
console.warn('[Element Warn][Select]\'auto-complete\' property will be deprecated in next major version. please use \'autocomplete\' instead.')
return true
}
},
automaticDropdown: Boolean,
size: String,
allowCreate: Boolean,
loading: Boolean,
remote: Boolean,
loadingText: String,
noMatchText: String,
noDataText: String,
defaultFirstOption: Boolean,
reserveKeyword: Boolean,
//弹窗类名,设置默认命名了,同一个路由页面有多个懒加载的下拉,一定要命不同的名字
popperClass: {
type: String,
default: 'lazy-selsect'
},
popperAppendToBody: {
type: Boolean,
default: true
},
valueKey: {
type: String,
default: 'value'
},
// 下拉数据
options: {
type: Array,
require: false,
default: () => { return [] }
},
// options取值
props: {
type: Object,
require: false,
default: () => { return { value: 'value', label: 'label' } }
},
// 默认显示及加载数量
defaultNumber: {
type: Number,
require: false,
default: 30
},
// 触底距离
bottomRange: {
type: Number,
require: false,
default: 100
}
},
data() {
return {
searchName: '', // 搜索字段
page: 1, // 当前页数
filterOptions: [] // 过滤后的下拉数据
}
},
computed: {
//对下拉数据options进行处理
newOptions() {
//这里有两种情况,一种是有筛选条件options,一种是无筛选条件options,然后对它们分页处理,每次滚动到一定距离page数字增大。
const { page, defaultNumber, searchName } = this
if (searchName) return this.filterOptions.slice(0, page * defaultNumber)
else return this.options.slice(0, page * defaultNumber)
},
className() {
return '.' + this.popperClass
}
},
methods: {
change(e) {
this.$emit('change', e)
this.$emit('input', e)
},
//在打开下拉弹窗时监听scroll事件
visibleChange(e) {
const selectScorll = document.querySelector(this.className).querySelector('.el-select-dropdown__wrap')
if (selectScorll) {
if (e) selectScorll.addEventListener('scroll', () => this.lazyLoad(selectScorll))
else {
this.searchName = ''
selectScorll.removeEventListener('scroll', () => this.lazyLoad(selectScorll))
}
}
this.page = 1
this.$emit('visible-change', e)
},
lazyLoad(selectScorll) {
const scrollTop = selectScorll.scrollTop
const scrollHeight = selectScorll.scrollHeight
const clientHeight = selectScorll.clientHeight
if (scrollTop + clientHeight + this.bottomRange >= scrollHeight) {
const { page } = this
this.page = page + 1
}
},
//筛选时过滤的方法
filterMethod(query) {
const selectScorll = document.querySelector(this.className).querySelector('.el-select-dropdown__wrap')
selectScorll.scrollTop = 0
this.page = 1
if (query !== '') {
this.searchName = query
this.filterOptions = this.options.filter(i => i[this.props.label].includes(query))
} else {
this.searchName = ''
}
}
}
}
有看不懂的欢迎留言,有bug欢迎提出来,学无止境,达者为师!大家一起讨论及学习。