解决el-select数据量过大卡顿问题
前言
当我们的下拉列表数据量过大时,初始化可能会有卡顿现象,我们可以通过滚动显示更多数据来解决这个问题。
一、el-select封装
// 控件名称 LargeDataSearchSelect
<tempalte>
<div></div>
</tempalte>
<script>
export default {
name: 'large-data-search-select',
directives: {
'el-select-loadmore': {
bind(el, binding) {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector(
'.el-select-dropdown .el-select-dropdown__wrap'
)
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
if (condition) binding.value()
})
}
}
},
props: {
selectProps: {
type: Object,
default: () => {
return {
options: [],
rangeNumber: 100
}
},
require: true
},
value: {
type: String,
default: ''
}
},
data() {
return {
selectValue: '',
rangeNumber: this.selectProps.rangeNumber || 100,
options: [],
originalData: []
}
},
watch: {
value: {
handler(newVal) {
this.selectValue = newVal
},
deep: true,
immediate: true
},
selectProps() {
this.init()
}
},
created() {
this.delayFilter = _.debounce((query)=>{
this.filter(query)
},500)
},
mounted() {
this.$nextTick(() => {
this.init()
})
},
methods: {
init() {
this.originalData = this.selectProps.options
this.initRenderOpions()
},
loadMore(n) {
if (n < 8) this.rangeNumber = 10
return () => (this.rangeNumber += 5) // 每次滚动到底部可以新增条数 可自定义
},
filter(query) {
if (query) {
let newOption = this.originalData.filter((item) =>
item[this.selectProps.label || 'label'].includes(query)
)
if(newOption.length) {
return this.options = newOption
}
}
this.initRenderOpions()
},
selectChange() {
this.$emit('updateChange', this.selectValue)
this.initRenderOpions()
},
initRenderOpions() {
let options = this.originalData.slice(0, this.rangeNumber)
let index = -1
if (_.size(this.selectValue)) {
index = _.findIndex(options, (item)=>{
return item.game_id === this.selectValue
})
if(index === -1) {
let currentItem = _.find(this.originalData, (game)=>{
return game.game_id === this.selectValue
})
if(currentItem) {
options.unshift(currentItem)
}
}
}
this.options = options
}
},
render() {
return (
<el-select
{...this.$attrs}
v-model={this.selectValue}
placeholder={this.selectProps.placeholder || '请选择'}
popper-append-to-body={false}
clearable
filterable
filter-method={this.delayFilter}
onChange={this.selectChange}
v-el-select-loadmore:rangeNumber={this.loadMore(this.rangeNumber)}
>
{this.options.map((item, index) => {
return (
<el-option
key={item[this.selectProps.value || 'value']}
label={item[this.selectProps.label || 'label']}
value={item[this.selectProps.value || 'value']}
></el-option>
)
})}
</el-select>
)
}
}
</script>
二、使用
<template>
<!-- 原本的 el-select -->
<!-- <el-select class="extern-header-gamelist fl" size="small" v-model="gameId" filterable placeholder="请按游戏筛选查看"-->
<!-- @change="onChangeGameIdHandler">-->
<!-- <el-option v-for="(item, index) in gameList" :label="item.game_name" :value="item.game_id" :key="index"-->
<!-- style="width:217px;"></el-option>-->
<!-- </el-select>-->
<!-- 使用自己封装的el-select -->
<LargeDataSearchSelect class="extern-header-gamelist fl" size="small"
v-model="gameId"
:selectProps.sync="selectProps"
@updateChange="onChangeGameIdHandler"
/>
</template>
<script>
import util from '@/common/util'
import LargeDataSearchSelect from "@/components/large-data-search-select";
export default {
name: "app",
components: {
LargeDataSearchSelect
},
data(){
return {
gameList: [],
gameId: util.getGameId(),
}
},
computed: {
selectProps() {
return {
placeholder: '请按游戏筛选查看',
options: _.clone(this.gameList),
rangeNumber: 100,
label: "game_name",
value: "game_id"
}
},
},
created() {
this.fetchGameList()
},
methods: {
async fetchGameList() {
let result;
result = await IBOX.waxios({
url: `${IBOX.config.baseURL}api/get_gs_games`,
method: 'Get'
})
if(result && result.ret === 0 && _.isArray(result.data)) {
this.gameList = _.map(result.data, (game) => {
return {
game_id: '' + game.game_id,
game_name: `[${game.game_id}]${game.game_name}`
}
})
IBOX.gameList = this.gameList;
this.selectProps.options = _.clone(this.gameList);
this.$store.commit('updateGameList', this.gameList)
}else{
this.$alert(staticData.requestFailMessage).then(()=>{
this.fetchGameList()
})
}
},
onChangeGameIdHandler(gameId) {
if(util.getGameId() !== gameId) {
util.setGameId(gameId);
this.$emit('change-game');
}
},
}
}
</script>
总结
原文转载来自: 解决el-select数据量过大卡顿问题-记录贴