element-ui中Select 选择器异步加载下一页
场景
当我们使用 Select 选择器存放大量数据的时候。
会发现存在这么2个问题。
1.接口响应时间较长。(因为数据量较多,一次查询的所有)甚至有可能超时。
2.前端下拉框滑动卡顿。
这个时候们如何解决上面面临的问题呢?
有的小伙伴可能会说:
1.分页加载。确实是可以解决问题。
2.页面卡顿使用虚拟dom.超时喊后端自己优化代码
因为项目中使用的是 element-ui,没有虚拟加载。
不想 Ant Design Vue一样,有virtual属性,设置 true可以开启虚拟滚动。
这里就感觉到 Ant Design Vue处理的比element-ui好一些(希望各位大佬不要喷我)
所以我们只能选择异步加载。
当页面滑动到底部的时候,加载下一页的数据
下拉框滑动到底部触发事件,加载下一页的数据
我们首先需要做到的是:获取下拉框元素的DOM节点。
由于一个页面可能有多个dom节点。
我们需要使用 popper-class属性来设置 Select 下拉框的类名。
然后后通过dom.scrollHeight - dom.scrollTop <= dom.clientHeight
来判断是否触底了。下面我们就来实现了一下
// 子组件
<template>
<div>
<el-select popper-class="more-next-box" v-model="value" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
export default {
data() {
return {
options: [{
value: '001',
label: '数据1'
}, {
value: '002',
label: '数据2'
}, {
value: '003',
label: '数据3'
}, {
value: '004',
label: '数据4'
}],
value: ''
}
},
mounted() {
// 获取dom节点
const domElementNode = document.querySelector('.more-next-box .el-select-dropdown__wrap')
// 注册下拉滚动事件
domElementNode.addEventListener('scroll', ()=>{
const isBottom = domElementNode.scrollHeight - domElementNode.scrollTop <= domElementNode.clientHeight
if (isBottom) {
console.log('是否到底了')
}
})
},
}
</script>
现在我们已经成功判断是否下拉到底了。
接下来我们应该去封装一下这个组件的属性和事件
争取拥有官方文档中的所有属性和事件
如何让 el-select拥有官方的所有属性呢?
我们可以使用props属性,一个一个的写上去。
这个操作虽然可以但是官方文档多20+多个属性。
是不是太麻烦了呀?
我们可以使用 $attrs配合inheritAttrs: false 来解决这个问题
$attrs里面包含着父组件传递的所有数据(除style和class)。
当一个组件声明了prop时候,attrs里面包含除去prop里面的数据剩下的数据。
而inheritAttrs: false,表示将属性不设置在根元素上,而是设置在指定的元素上
//组件优化为
<template>
<div>
<el-select v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
//表示不添加在组件的根元素上
inheritAttrs: false,
//页面使用
<SelectLoadMore
popper-class="more-next-box"
:clearable="true"
placeholder="请选择数据">
</SelectLoadMore>
如何让 el-select拥有官方的所有事件呢?
$listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。
//组件再次优化为
<el-select v-on="$listeners" v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
//页面使用
<div>
<SelectLoadMore popper-class="more-next-box"
:clearable="true"
@visible-change="visibleChange"
placeholder="请选择数据"
@change="changeHandler"
></SelectLoadMore>
</div>
el-option中key,label,value这些字段不一样怎么处理?
这个我们直接使用props来处理就好了。
这样我们就需要担心key键名不一致这个问题了
<div>
<el-select v-on="$listeners" v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item[setKey]"
:label="item[setLabel]"
:value="item[setValue]">
</el-option>
</el-select>
</div>
props: {
setKey: {
type: String,
default:'key'
},
setLabel: {
type: String,
default: 'label'
},
setValue: {
type: String,
default: 'value'
}
},
下拉到底部加载下一页的数据
// 组件
created() {
this.getList()
},
mounted() {
// 获取dom节点
const domElementNode = document.querySelector('.more-next-box .el-select-dropdown__wrap')
// 注册下拉滚动事件
domElementNode.addEventListener('scroll', ()=>{
const isBottom = domElementNode.scrollHeight - domElementNode.scrollTop <= domElementNode.clientHeight
if (isBottom) {
console.log('是否到底了')
// 这里应该还有一个判断,总条数和当前列表中的数据做一个比较。
// 这里我就不写了
this.getList(this.pageSize += 1)
}
})
},
methods: {
// 请求的数据
getList(index = 1) {
let arr = []
setTimeout(() => {
for (let i = 0; i < 10; i++){
arr.push({
value: (index-1) *10 + i,
label: '数据'+ (index - 1) * 10 + i
})
}
this.options=this.options.concat(arr)
},2500)
}
},
加载下一页的时候做一个加载提示
从上面这张图中,我们可以看见。
加载的时候没有任何的提示和效果。非常的不友好。
用户都不知道是在加载数据。我们现在优化一下
//子组件
<el-select v-on="$listeners" v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item[setKey]"
:label="item[setLabel]"
:value="item[setValue]">
</el-option>
<el-option v-show="loadingFlag" label="正在努力加载中" value="xx01"></el-option>
</el-select>
data() {
return {
options: [],
value: '',
pageSize: 1,
loadingFlag:false //控制加载显示的
}
},
getList(index = 1) {
this.loadingFlag=true //开启加载中
let arr = []
setTimeout(() => {
for (let i = 0; i < 10; i++){
arr.push({
value: (index-1) *10 + i+'',
label: '数据'+ (index - 1) * 10 + i
})
}
this.options = this.options.concat(arr)
this.loadingFlag = false //加载结束
},2500)
}
md发现了一个bug,用户选择‘正在努力加载中’中这一项怎么办?
有细心的小伙伴,可能会说:
<el-option v-show="loadingFlag" label="正在努力加载中" value="xx01"></el-option>
这样写真的没有问题吗?
万一用户选择了,这一项数据怎么办?
这,这,这,这,这恐怕就会100%出现bug了。
使用 disabled 来处理禁止选择这一项。
哈哈··,我简直是一个小天才(手动狗头)
使用 disabled 来处理禁止选择这一项
<el-select v-on="$listeners" v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item[setKey]"
:label="item[setLabel]"
:value="item[setValue]">
</el-option>
<el-option disabled v-show="loadingFlag" label="正在努力加载中" value="xx01"></el-option>
</el-select>
继续优化加载动画
有的小伙伴说,这个虽然不能选择,也有加载提示。
但是是灰色的,不太友好。
你他娘的,就你屁事多。烦死了(悟空表情)。
<el-select v-on="$listeners" v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item[setKey]"
:label="item[setLabel]"
:value="item[setValue]">
</el-option>
<p v-show="loadingFlag">正在努力加载中</p>
</el-select>
我们可以自己用一个标签来处理动画,这里我就不在做动画了。
其实如果你觉得 disabled的样式也可以修改的,
其实中的disabled也是可以修改样式的
<el-option disabled v-show="loadingFlag" label="正在努力加载中" value="xx01"></el-option>
<style lang="scss" scoped>
.el-select-dropdown__item.is-disabled{
color: red;
}
</style>
如何做数据回填
有些时候,我们除了需要选择值,还需要回填值。
我们可以使用 props来传递值,然后在created中赋值。
// 数据回填的值
writeData: {
type: String,
default: ''
}
created() {
if (this.writeData) {
this.value = this.writeData
}
this.getList()
},
全部代码
// 使用的页面
<template>
<div>
<SelectLoadMore popper-class="more-next-box"
:clearable="true"
:writeData="writeData"
@visible-change="visibleChange"
placeholder="请选择数据"
@change="changeHandler"
></SelectLoadMore>
</div>
</template>
<script>
import SelectLoadMore from "@/components/SelectLoadMore.vue"
export default {
components: {
SelectLoadMore
},
data() {
return {
writeData: 108
}
},
methods: {
changeHandler() {
console.log('值发生了改变')
},
visibleChange(flag){
console.log('flag', flag)
}
},
}
</script>
组件
<template>
<div>
{{ value }}
<el-select v-on="$listeners" v-bind="$attrs" v-model="value" >
<el-option v-for="item in options"
:key="item[setKey]"
:label="item[setLabel]"
:value="item[setValue]">
</el-option>
<!-- <p v-show="loadingFlag">正在努力加载中</p> -->
<el-option disabled v-show="loadingFlag" label="正在努力加载中" value="xx01"></el-option>
</el-select>
</div>
</template>
<script>
export default {
//表示不添加在组件的根元素上
inheritAttrs: false,
props: {
setKey: {
type: String,
default:'key'
},
setLabel: {
type: String,
default: 'label'
},
setValue: {
type: String,
default: 'value'
},
// 数据回填的值
writeData: {
type: String,
default: ''
}
},
data() {
return {
options: [],
value: '',
pageSize: 1,
loadingFlag:true
}
},
created() {
if (this.writeData) {
this.value = this.writeData
}
this.getList()
},
mounted() {
// 获取dom节点
const domElementNode = document.querySelector('.more-next-box .el-select-dropdown__wrap')
// 注册下拉滚动事件
domElementNode.addEventListener('scroll', ()=>{
const isBottom = domElementNode.scrollHeight - domElementNode.scrollTop <= domElementNode.clientHeight
if (isBottom) {
console.log('是否到底了')
// 这里应该还有一个判断,总条数和当前列表中的数据做一个比较。
// 这里我就不写了
this.getList(this.pageSize += 1)
}
})
},
methods: {
getList(index = 1) {
this.loadingFlag=true
let arr = []
console.log('index', index)
setTimeout(() => {
for (let i = 0; i < 10; i++){
arr.push({
value: (index-1) *10 + i+'',
label: '数据'+ (index - 1) * 10 + i
})
}
this.options = this.options.concat(arr)
// this.loadingFlag = false
},1500)
}
},
}
</script>
<style lang="scss" scoped>
.el-select-dropdown__item.is-disabled{
color: red;
}
</style>
尾声
如果你觉得,这篇文章写的不错,对你有用。
请给我点一个赞,感谢了。
element-ui中Select 选择器异步加载下一页的更多相关文章
- Yii 1开发日记 -- Ajax实现点击加载下一页
功能实现:先输出一页的内容,然后点击加载下一页,如图 1.控制器中 /** * 消费记录:列出用户购买章节的记录 */ public function actionMyPayHis() { //点击加 ...
- viewpager处理(三):让viewpager不预加载下一页
有时候viewpager加载页面的时候,我们发现页面的数据量很大,预加载的话会消耗性能,为了节省用户流量和手机性能,所以我们想让viewpager不自动预加载下一页,怎么实现呢? viewpager预 ...
- windows phone LongListSelector加载下一页
LongListSelector利用ListHeader.ListFooter加载上一页和下一页XAML代码: <phone:LongListSelector> <phone:Lon ...
- 微信小程序下拉加载下一页
小程序做得多了,有些常用功能就有必要记录一下 请看详解: 微信小程序之下拉触底时加载下一页 wxml参考: <scroll-view class='dataContainer' scroll-y ...
- 微信小程序:上滑触底加载下一页
给商品列表页面添加一个上滑触底加载下一页的效果,滚动条触底之后就发送一个请求,来加载下一页数据, 先在getGoodsList中获取总条数 由于总页数需要再另外的一个方法中使用,所以要把总页数变成一个 ...
- js 移动端上拉加载下一页通用方案
取页面三种高度 //取进度条到底部距离 var getScrollTop = function () { var scrollTop = 0; if (document.documentElement ...
- 兼容IE8,滚动加载下一页
// 滚动加载下一页 var nowScrolledHeight = document.documentElement.scrollTop || document.body.scrol ...
- WPF 多线程 UI:设计一个异步加载 UI 的容器
对于 WPF 程序,如果你有某一个 UI 控件非常复杂,很有可能会卡住主 UI,给用户软件很卡的感受.但如果此时能有一个加载动画,那么就不会感受到那么卡顿了.UI 的卡住不同于 IO 操作或者密集的 ...
- 简单的ListView中item图片异步加载
前言: 在android开发当中,从目标地址获取图片往往都是采用异步加载的方法.当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来. 这两个区别只是对流的处理不同而已.现 ...
- Android中图片的异步加载
转: 1. 为什么要异步加载图片 下载图片比较费时,先显示文字部分,让加载图片的过程在后台,以提升用户体验 2. SoftReference的作用 栈内存—引用 堆内存—对象 Eg: Object ...
随机推荐
- vue在js公用文件中使用this
main.js 中 let $vue = new Vue({ router, el: '#app', render: h => h(App) }); export default $vue 在j ...
- day01-SpringCloud基本介绍
SpringCloud基本介绍 SpringCloud官方文档 1.提出问题 先思考一个问题,没有微服务技术,是不是程序员就不能开发大型项目? 是可以的,对大型项目进行模块划分,对各个模块进行实现.但 ...
- Archlinux最新安装教程
介绍 Arch Linux(或 Arch /ˈɑːrtʃ/))是一款基于 x86-64 架构的 Linux发行版 .系统主要由自由和开源软件组成,支持社区参与.系统设计以 KISS原则(保持简单和愚蠢 ...
- [Python]Python安装教程
anaconda Anaconda:python的一种软件发行版.Anaconda发行版会预装很多pydata生态圈里的软件,而Miniconda是最小的conda安装环境, 一个干净的conda环境 ...
- 两种路由模式的区别(hash模式,history模式)
1. hash 带#号的,history不带#号2.hash模式用的hashChange监听路径的变化3.history用的是HTML5相关的API语法 使用pushState => 添加一条历 ...
- Ubuntu Server搭建个人服务器
Ubuntu Server20.04.5 LTS [参考资料] Ubuntu官方地址:https://www.ubuntu.com/ Ubuntu论坛地址:https://ubuntuforums.o ...
- DES算法图解、密码学
- .Net 6.0 部署Linux+Nginx +PM2教程
今天带大家将本地.Net6.0项目部署到Linux系统中,其中有用到Nginx反向代理和PM2进程管理工具,希望本偏文章能对你有所帮助,成为你成功路上的垫脚石! 背景: 在.Net 5.0横空出世之后 ...
- ClickHouse主键索引最佳实践
在本文中,我们将深入研究ClickHouse索引.我们将对此进行详细说明和讨论: ClickHouse的索引与传统的关系数据库有何不同 ClickHouse是怎样构建和使用主键稀疏索引的 ClickH ...
- 【Ubuntu】2. 安装Ubuntu操作系统+VMware Tools
接上一篇,这一部分介绍了操作系统的安装 开启虚拟机,首先由四个选项,选第一个正常安装即可,这里稍等片刻就可以进入安装选项 到了这一步的话可以在左侧设置系统语言,我的英语比较垃圾就选中文了,选择完之后点 ...