vue2虚拟滚动下拉选择器
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
vue虚拟滚动下拉选择器
目的
为了解决 element-ui 中 el-select 组件在大数据量的情况下出现的性能问题(数据量太大,导致渲染过慢,或造成页面卡顿甚至于卡死) 。
原理
本组件时基于vue-virtual-scroll-list(一个基于vue2的虚拟滚动组件,通过不渲染可视区域以外的内容,显示虚拟的滚动条来提升页面性能)实现的下拉选中框,该下拉选择组件支持单选,多选,筛选等操作,若是选中了数据,再次打开会自动定位到数据的位置
一.安装
npm install vue-virtual-scroll-list --save
常用参数及方法
常用参数
参数名 | 类型 | 描述 |
---|---|---|
data-key | String|Function | 从每个数据对象中的“数据源”获取唯一键。或者用每个“数据源”调用一个函数,并返回它们的唯一键。它的值在“数据源”中必须是唯一的,用于标识条目的大小。 |
data-sources | Array[Object] | 为列表构建的源数组,每个数组数据必须是一个对象,并具有唯一的键ID(data-key)属性。 |
data-component | Component | vue创建/声明的渲染项组件,它将使用’ data-sources ‘中的数据对象作为渲染道具,并命名为’source’。 |
keeps | Number | 你希望虚拟列表在真正的dom中保持呈现多少项,默认30个。 |
extra-props | Object | 分配给不在数据源中的项目组件的额外道具。注意:索引和源都被占用在内部。 |
常用方法
可以通过ref方式调用以下这些方法:
方法名 | 描述 |
---|---|
reset | 将所有状态重置为初始状态。 |
scrollToIndex(index) | 手动设置滚动位置为指定的索引。 |
scrollToOffset(offset) | 手动设置滚动位置到指定的偏移量。 |
上述是组件常用的参数和方法,其他参数及方法可 官方插件
二.开始封装element的select组件
在src/components中创建文件夹SelectV2
1.创建index.vue文件
<template>
<div>
<el-select
:value="value"
popper-class="virtualselect"
filterable
:filter-method="filterMethod"
@visible-change="visibleChange"
v-bind="$attrs"
v-on="$listeners"
>
<vue-virtual-list
ref="virtualList"
class="virtualselect-list"
:data-key="fields.value"
:data-sources="dataSources"
:data-component="itemComponent"
:keeps="20"
:extra-props="{
label: fields.label,
value: fields.value,
rightLabel: fields.rightLabel
}"
></vue-virtual-list>
</el-select>
</div>
</template>
<script>
import VueVirtualList from 'vue-virtual-scroll-list';
import itemComponent from './itemComponent';
export default {
name: 'select-v2',
components: {
'vue-virtual-list': VueVirtualList
},
model: {
prop: 'value',
event: 'change'
},
props: {
// 下例列表数据
data: {
type: Array,
default: () => []
},
// 字段参数配置,默认为label,value
// 可尝试传入rightLabel字段,使其在右边也展示内容
fields: {
type: Object,
default() {
return {
label: 'label',
value: 'value',
};
}
},
// 绑定的默认值
value: {
type: [String, Array],
default: () => []
}
},
mounted() {
this.init();
},
watch: {
'data'() {
this.init();
}
},
data() {
return {
// 内容组件
itemComponent,
// 下拉列表中的数据
dataSources: [],
// 用来定位滚动到某个位置
start: 0
};
},
methods: {
init() {
if (!this.value || this.value.length === 0) {
// 初始化数据
this.dataSources = this.data;
} else {
// 回显问题
// 单选时,存储当前的index
// 多选时,取选中的所有值中下标的最小值
this.dataSources = JSON.parse(JSON.stringify(this.data));
if (typeof this.value === 'string') {
const value = this.value
for (let i = 0; i < this.dataSources.length; i++) {
const element = this.dataSources[i];
if (element[this.fields.value] === value) {
this.start = i
break;
}
}
} else if (Array.isArray(this.value)) {
let start = []
const valueSet = new Set(this.value)
for (let i = 0; i < this.dataSources.length; i++) {
const element = this.dataSources[i];
if (valueSet.has(element[this.fields.value])) {
start.push(i)
}
}
this.start = Math.min(...start)
}
}
},
// 搜索
filterMethod(query) {
if (query !== '') {
setTimeout(() => {
this.$refs.virtualList.scrollToIndex(0);
this.dataSources = [...this.data.filter((item) => {
return this.fields.rightLabel
? item[this.fields.label]
.indexOf(query) > -1 ||
item[this.fields.rightLabel]
.indexOf(query) > -1
: item[this.fields.label]
.indexOf(query) > -1;
})];
}, 100);
} else {
this.init();
}
},
visibleChange(bool) {
if (!bool) {
this.$refs.virtualList.reset();
this.init();
} else {
// 定位到选中的位置
this.$nextTick(() => {
this.$refs.virtualList.scrollToIndex(this.start);
})
}
}
}
};
</script>
<style lang="scss">
.virtualselect {
// 设置最大高度
&-list {
max-height: 245px;
overflow-y: auto;
}
.el-scrollbar .el-scrollbar__bar.is-vertical {
width: 0 !important;
}
}
</style>
2.同目录下创建itemComponent.vue文件
<template>
<div>
<el-option
:key="label + value"
:label="source[label]"
:value="source[value]"
>
<span>{{ source[label] }}</span>
<span v-if="rightLabel" style="float:right;color:#939393">{{
source[rightLabel]
}}</span>
</el-option>
</div>
</template>
<script>
export default {
name: 'item-component',
props: {
// index of current item
// 每一行的索引
index: {
type: Number
},
// 每一行的内容
source: {
type: Object,
default() {
return {};
}
},
// 需要显示的名称
label: {
type: String
},
// 绑定的值
value: {
type: String
},
// 右侧显示绑定的值,为空则不显示
rightLabel: {
type: String,
default: ''
}
},
mounted() {}
};
</script>
三.使用用例
创建测试页面
<template>
<div class="cw-select">
<select-v2
:data="list"
v-model="value"
placeholder="请选择下拉数据"
clearable
multiple
@change="selectChange"
></select-v2>
</div>
</template>
<script>
import SelectV2 from '@/components/SelectV2'
export default {
name: 'demo',
components: {
'select-v2': SelectV2
},
data() {
return {
list: [],
// 下拉框选择的默认值,可以时字符串和数组
value: []
};
},
mounted() {
this.list = [];
// 创建20000条测试数据
for (let i = 0; i < 20000; i++) {
this.list.push({ value: i, label: '测试' + i + '' });
}
},
methods: {
selectChange(val) {
console.log('下拉框选择的值', val);
}
}
};
</script>
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献2条内容
所有评论(0)