vue3 el-select懒加载以及自定义指令

<template>

<el-select

v-model="state.input"

:loading="loading"

loading-text="数据加载中..."

filterable

clearable

popper-class="event-select-poper"

v-el-select-loadmore="loadmore"

placeholder="请输入属性值"

style="width: 100%"

:filter-method="filterOptions"

@change="handleEventsChange"

@visible-change="handleVisibleChange">

<el-option

v-for="item in dataList"

:key="item.id"

:label="item.name"

:value="item.name">

</el-option>

<div style="margin:10 auto; text-align: center; color:#ccc">----已到底----</div>

</el-select>

</template>

<script setup>

import { ref, nextTick } from 'vue';

import axios from 'axios';

const emits = defineEmits('change')

const dataList = ref(\[\]); //渲染数据数组

let loading = ref(false)

const state = ref({input: '', val: ''});

const pageIndex = ref(1);

const scrollpSize = ref(10);

const scrollPages = ref(1);

// 自定义v-el-select-loadmore指令

const vElSelectLoadmore = {

beforeMount(el, binding) {

/**

* vue2时:

* el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');

* vue3时:

* 在el-select给一个参数popper-class="event-select-poper"

* element-plus中el-select的选项是使用的popper.js生成的,无法直接获取

*/

const selectDom = document.querySelector('.event-select-poper .el-select-dropdown__wrap')

let loadMores = function() {

/**

* scrollHeight 获取元素内容高度(只读)

* scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.

* clientHeight 读取元素的可见高度(只读)

* 如果元素滚动到底, 下面等式返回true, 没有则返回false:

* ele.scrollHeight - ele.scrollTop === ele.clientHeight;

*/

// 判断是否到底

const isBase = this.scrollHeight - this.scrollTop <= this.clientHeight + 20

if (isBase) {

// 增加防抖

binding.value && binding.value()

}

}

// 将获取到的dom和函数挂载到el-select上,实例销毁时好处理

el.selectDomInfo = selectDom

el.selectLoadMore = loadMores

// 监听滚动事件

selectDom?.addEventListener('scroll', loadMores.bind(selectDom))

},

// 实例销毁

beforeUnmount(el) {

if (el.selectLoadMore) {

el.selectDomInfo.removeEventListener('scroll', el.selectLoadMore)

delete el.selectDomInfo

delete el.selectLoadMore

}

}

}

// onBeforeMount(async () => {

// await loadEvents()

// })

loadEvents();

// 模拟懒加载

const loadmore = () => {

// 数据加载完成之后,不需要再执行懒加载

if (pageIndex.value >= scrollPages.value) { return }

pageIndex.value++

nextTick(() => {

loading.value = true

getList();

loading.value = false

})

}

function getList() {

axios({

method: 'post',

url: 'https://xxx.xx.x.xxx/dataSource/list',

data: { name : state.value.val, pageIndex: pageIndex.value, pageSize: scrollpSize.value },

headers: {'Content-Type': 'application/json;charset=UTF-8'}

}).then(res => {

let resdata = res.data && res.data.data || res.data;

let respage = res.page || (res.data && res.data.page);

for (let index = 0; index < resdata.length; index++) {

dataList.value.push({ name:resdataindex.name, id:resdataindex.id });

}

scrollPages.value = respage.totalPage;

pageIndex.value = respage.pageIndex;

});

}

// 自定义过滤函数

const filterOptions = (query = '') => {

pageIndex.value = 1

nextTick(async () => {

dataList.value = \[\];

state.value.val = query;

getList();

})

}

// 下拉框隐藏时,重置分页已经过滤得到的列表

const handleVisibleChange = (visible) => {

if(!visible){

pageIndex.value = 1;

}

}

// 获取事件列表

function loadEvents () {

loading.value = true;

getList();

// 调用接口

loading.value = false;

}

const handleEventsChange = (val) => {

console.log(val);

emits('change', val)

}

</script>

相关推荐
linux_cfan2 小时前
17 · 引擎适配器全景:HLS/DASH/Vimeo/Mux/Cast
前端·javascript·音视频
何何____4 小时前
Vue 生命周期详解
前端·javascript
默_笙5 小时前
💫 闭包是个背包:拆解小米前端面试题里的三道"闭包陷阱"
前端·javascript·面试
老男孩游戏时光7 小时前
Vue3 Composition API 最佳实践,别再乱写 setup 了
vue.js
+VX:Fegn08957 小时前
计算机毕业设计|基于java+ vue共享单车信息系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
尾善爱看海8 小时前
《JavaScript 数组操作全攻略:12 类 API + 30 个实战场景 + 20 个避坑指南》
前端·javascript·面试
Bs_MoneyMagnet8 小时前
基于springboot+vue的非遗物质文化遗产系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
计算机毕设定制辅导-无忧学长8 小时前
《基于SpringBoot的未成年人健康知识科普平台的设计与实现》
java·开发语言·vue.js·spring boot·未成年人健康知识科普平台
OpsEye8 小时前
为什么你的 Agent 莫名烧钱?聊聊循环调用的兜底方案
javascript·ai编程
linux_cfan9 小时前
16 · `custom-media-element`:属性拦截与转发
前端·javascript·音视频