目录
1.目的
2.原理
3.优点
4.源码
1)安装插件
2) 创建全局组件VirtualListSelect。
a.简单页面也即正常开发的页面中
b.通过表单配置在页面中渲染出来的下拉框
为了解决 element-ui 中 el-select 组件在大数据量的情况下出现的性能问题(数据量太大,导致渲染过慢,或造成页面卡顿甚至于卡死) 。
模拟虚拟滚动,对 el-select组件结合vue-virtual-scroll-list(vue虚拟列表)插件进行二次封装
适用于只查询一次接口,后端一次性把数据返回。 对比其他的优化方案,有以下优点
方案一:后台进行分页;这种。。嗯,那后端人员可能不乐意了,心里想我都把数据返回给你了,加载慢,页面卡顿不应该你前端的问题吗(关我什么事)。ok,为了避免这种情况,我们就不麻烦后端同学在每个下拉框数据返回后进行分页了,那可是个大工程。对比这种方案优点就是
方案二:前端懒加载,这种确实可以,我不用此方案就是考虑到数据量过大,那即使页面初始加载的时候较快,但是在页面销毁,简单来说就是切页面的时候,你要销毁所有的dom节点那肯定会出现你的路由已经变化了,但是你的页面还没跳转,造成用户体验不好。对比这种方案我的方案优点
由于需要使用插件vue-virtual-scroll-list,所以我们先在项目中把插件安装一下;
插件官网地址:vue-virtual-scroll-list - npmvue-virtual-scroll-list - npmvue-virtual-scroll-list - npm
npm install vue-virtual-scroll-list --save
我使用的环境相对来说比较复杂 ,因为我封装的这个组件主要用在低代码平台中,即下拉框是通过页面配置然后渲染出来的,所以需要接收许多参数,但是在正常开发的页面中不需要接收这么多参数,为了方便读者借鉴,我就两种都记录一下。正常开发的页面已经满足大部分读者的需求。
itemComponent.vue 文件
{{ source[label] }}
{{
source[value]
}}
组件封装完成后,我们最好将其注册成全局组件,以便在系统中使用
import VirtualListSelect from './VirtualListSelect';
Vue.component('virtual-list-select', VirtualListSelect);
demo.vue
## VirtualListSelect
### 1. 组件说明
* 本组件是对 el-select组件结合vue-virtual-scroll-list(vue虚拟列表)插件的二次封装。原理:模拟虚拟滚动,目的是为了解决 element-ui 中 el-select 组件在大数据量的情况下出现的性能问题(数据量太大,导致渲染过慢,造成页面卡顿甚至于卡死)。
* 插件地址:https://www.npmjs.com/package/vue-virtual-scroll-list
### 2. 实现原理
* 用vue-virtual-scroll-list这个插件去包裹需要循坏展示的标签。这里就是el-option标签。
* 由于插件的 data-component 属性,需要抽离出el-option标签封装成一个组件
### 3. 属性说明
* data-key=“‘id’” 就是绑定的唯一key值
* data-sources=“selectArr” 下拉框的数组
* data-component=“itemComponent” 就是抽离中的el-option组件
* keeps=“20” 渲染的个数(默认30个)
* extra-props 值为对象,可以传入自定义属性进去
### 4. 方法
* 实现模糊搜索功能,使用el-select自带的filterMethod方法
* visible-change事件实现下拉框出现/隐藏时触发虚拟列表重置和把列表重置成全量数据
### 5. 注意点
1.
render.js
export default {
name: 'render',
props: {
type: String,
config: Object
},
render: function(h) {
switch (this.type) {
case 'select':
// return selectItem(h, this.config);
return virtualListSelect(h, this.config);
default:
return '';
}
}
};
// 虚拟下拉列表
function virtualListSelect(h, config) {
const {
model,
key,
props,
listeners,
options,
optionConfig,
placeholder,
syncConfig,
goods,
value,
multiple
} = config;
let opl = 'label';
let opv = 'value';
if (optionConfig) {
if (optionConfig.label) {
opl = optionConfig.label;
}
if (optionConfig.value) {
opv = optionConfig.value;
}
}
const opts = options;
const on = listeners || {};
let pps = props || {};
if (syncConfig) {
pps = {
...pps,
...syncConfig()
};
}
return h('virtual-list-select', {
props: {
placeholder: placeholder || '请选择',
filterable: true,
...pps,
value: value,
selectData: {
data: opts, // 下拉框数据
label: opl || 'text', // 下拉框需要显示的名称
value: opv, // 下拉框绑定的值
isRight: false //右侧是否显示
},
multiple,
allowCreate: goods.allowCreate,
disabled: goods.readable === 1 || goods.pageDisabled,
'multiple-limit': goods.itemMultipleLimit,
'collapse-tags': true,
clearable: goods.clearAble,
'popper-append-to-body': false
},
on: {
...on,
change: (val) => {
goods.value = val;
if (model) {
model[key] = val;
}
if (on.change) {
on.change(val);
}
}
}
});
}