之前出过一篇《解决el-select数据量过大导致页面卡顿》的博客。最近在开发过程中发现需要用到的地方很多,并且发现change事件与blur事件在一起使用会出bug,于是开发了一个公共组件。
1、封装组件selectLoadmore.vue
<template>
<div>
<el-select clearable filterable v-model="selected"
:filter-method="(e)=>searchGoodsList(e)"
ref="mySelect"
v-el-select-loadmore:rangeNumber="loadMore(rangeNumber)"
@change="handleChange" @blur.capture="handleBlur" :placeholder="text">
<el-option
v-for="(item,index) in dataList.slice(0, rangeNumber)"
:key="index"
style="width: 200px"
:label="item"
:value="item">
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: "selectLoadmore",
directives: {
"el-select-loadmore": function(el,binding) {
let self = this
// 获取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 - Math.ceil(this.scrollTop) <= this.clientHeight;
if (condition) binding.value()
});
}
}
},
props: {
value: String,
text: String,
name: String,
dataArr: Array,
filterList: Array,
},
data() {
return {
selected:'',
dataList:[],
rangeNumber:10,
status:false,
}
},
watch:{
dataArr(val) {
this.dataList=val
},
value(val){
this.selected=val
},
},
mounted() {
// const mySelect = this.$refs.mySelect;
// mySelect.$on('customChangeAndBlur', () => {
// this.$nextTick(()=>{
// mySelect.$emit('change');
// mySelect.$el.querySelector('.el-input__inner').dispatchEvent(new Event('blur'));
// })
// });
// mySelect.$el.addEventListener('blur', () => {
// this.$nextTick(()=>{
// this.$bus.$emit('blurEvent', mySelect);
// })
// });
this.$refs.mySelect.$el.querySelector('.el-input__inner').addEventListener('blur', this.handleBlur);
},
beforeDestroy() {
this.$refs.mySelect.$el.querySelector('.el-input__inner').removeEventListener('blur', this.handleBlur);
},
methods:{
handleBlur(event) {
if(this.filterList.length!==1){
this.status=false
}else {
this.status=true
}
if(!this.status){
// this.$refs.mySelect.$emit('change');
this.$bus.$emit('blurEvent', this.selected,this.name);
}
},
handleChange(){
this.status=true
this.$bus.$emit('changeEvent', this.selected,this.name);
},
searchGoodsList(e){
this.selected=e//注意:这里一定要给value赋值
if (e) {
//val存在
this.dataList = this.filterList.filter((item) => {
if (!!~item.indexOf(e) || !!~item.toUpperCase().indexOf(e.toUpperCase())) {
return true
}
})
} else {
//val为空时,还原数组
this.dataList = this.filterList;
}
},
loadMore(n){
//n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
//if(n < 8) this.rangeNumber = 10 //elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
return () => this.rangeNumber += 5 //每次滚动到底部可以新增条数 可自定义
},
}
}
</script>
<style scoped>
</style>
2、页面使用
<template>
<my-select text="请输入名称"
name="name"
:dataArr="list"
:filterList="list"
:value="form.name">
</my-select>
</template>
<script>
import SelectLoadmore from '@/components/selectLoadmore'
export default {
name: "index",
components: {
'my-select':SelectLoadmore,
},
data() {
return {
list:['小红','张三','小明','李四','王五'],
form:{
name:''
},
}
},
mounted() {
this.$bus.$off('changeEvent')
this.$bus.$off('blurEvent')
this.$bus.$on('changeEvent', (selected, name) => {
this.form[name]=selected
this.changeVal()
});
this.$bus.$on('blurEvent', (selected, name) => {
if(selected){
this.form[name]=selected
this.changeVal()
}
});
},
methods:{
changeVal(){
let _this=this
setTimeout(function(){
_this.pageIndex = 1
_this.getDataList()
// 时间间隔
},500);
},
getDataList(){
//此方法中做查询操作
console.log(this.form.name)
},
}
}
</script>
补充:
文中用到了this.$bus,可以看下我上篇博文:
Vue组件之间传值,使用全局 bus 在 Vue 的兄弟组件中传值