ElementPlus 中el-select自定义指令实现触底加载请求options数据的方法
作者:小御姐@stella
1) 背景:
老项目翻新时,发现一个下拉框数据非常多,客户呢,希望全部数据一起展示,意思就是全部数据一起返回给前端用于展示。但这会造成明显的卡顿。~~明显的不合理! QAQ!~~
于是压力给到前端,查询资料,各种搜索,最终找到2个解决方案。
1、在el-select下拉框中添加分页组件,让用户点击下一页下一页
2、在el-select下拉框中数据,触底加载当然最终选择了第二个方案,用户体验会更好。
由于项目中有多个地方使用到 且 可能单个页面中会用到多次,为了复用选择了自定义指令的方式去实现。
2) 先来看看实现的效果
3) 思路
- 触底加载,哪个元素滚动触底时加载?
- 承装下拉框中所有元素的容器(.el-scrollbar__wrap)
- 触底时,触发方法做什么?
- 触底时,继续向后端发请求获取下一页的数据,请求回来的数据合并给options
4) 简单的写一下.vue文件代码
接口数据是自己用node写的
后端代码在这里:GitHub - stella99888/tao-express: Vue2+Express
```javascript <!-- 下拉框触底加载页面 --> <template> <div class="m-4"> <p>第一个select</p> <el-select v-model="value" v-loadmore="loadmore" :teleported="false" style="width:240px"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> <p>第二个select</p> <el-select v-model="value" v-loadmore="loadmore" :teleported="false" style="width:240px"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </div> </template> <script setup> import axios from 'axios'; import { onMounted, reactive, ref } from 'vue' const list = ref([]) const options = ref([]) const option = ref([]) const value = ref([]) const loading = ref(false) let pageData = reactive({ pageIndex: 1, pageSize: 10 }) onMounted(() => { getOptions() }) const getOptions = () => { axios.get(`http://localhost:9999/getSelectOptions?pageIndex=${pageData.pageIndex}&pageSize=${pageData.pageSize}`) .then(res => { console.log(res.data); if (res.data.length < 1) { ElMessage({ message: '没有更多数据了...', type: "warning", }); } const newOptions = res.data.map((item) => { return { value: item.name, label: item.index } }) options.value.push(...newOptions) }) } // 触底了,继续发请求 const loadmore = () => { pageData.pageIndex = pageData.pageIndex + 1 getOptions() } </script>
* 注意一下:
1. teleported属性为官网提供,是否将下拉列表插入至 body 元素,默认值为true,插入到body元素中。
> 这是插入body中的
> 这是不插入body中的(可以对比下)
2. 我们需要将其插入body元素中吗?如果是单个页面中只出现一个,那影响不大;如果是多个,我们要选中该元素时就很不方便了。
3. 且,我们这边使用的是自定义指令的方式,指令在el-select元素上,teleported为false,不插入body时,正好可以在自定义指令中使用el.querySelector('.el-scrollbar__wrap')获取滚动的元素。
5) 自定义指令
前端代码在这里:GitHub - wwaini/tao-vue3 at release240625
// src/directives/loadmore/index.js import { debounce } from "lodash"; export default { mounted(el, binding) { // 不插入body时,以下方式可获取元素 // 插入body时,需要以document.querySelector('.el-scrollbar__wrap')获取 let scrollWrap = el.querySelector('.el-scrollbar__wrap') // 把监听的方法防抖一下 const handle = debounce((e) => { let scrollDistance = scrollWrap.scrollHeight - scrollWrap.scrollTop // 比如此处预留10个像素的位置用于触底 if (scrollWrap.clientHeight + 10 > scrollDistance) { binding.value() // 触底通知一下,外界 } }, 170) // 绑定监听滚动事件 scrollWrap?.addEventListener('scroll', handle) // 方法挂载到元素身上便于解绑时使用 el._hanlde = handle }, unmounted(el, binding) { let scrollWrap = document.querySelector('.el-scrollbar__wrap') scrollWrap?.removeEventListener('scroll', el._hanlde) el._hanlde = null } }
// directives/index.js import loadmore from "./loadmore" // 自定义指令对象,用于遍历注册 const directives = { loadmore } // 批量注册指令并暴露到main.js中去便于注册 export default { install(app) { Object.keys(directives).forEach((key) => { app.directive(key, directives[key]) }) } }
// main.js import { createApp } from 'vue'; import App from './App.vue'; const app = createApp(App); // 引入并使用自定义指令 import directive from './directives' app.use(directive); app.mount('#app');
// src/views/num/six.vue <!-- 下拉框触底加载自定义指令 --> <template> <div class="m-4"> <p>第一个select</p> <el-select v-model="value" v-loadmore="loadmore" :teleported="false" style="width:240px"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> <p>第二个select</p> <el-select v-model="value" v-loadmore="loadmore" :teleported="false" style="width:240px"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </div> </template> <script setup> import axios from 'axios'; import { onMounted, reactive, ref } from 'vue' const list = ref([]) const options = ref([]) const option = ref([]) const value = ref([]) const loading = ref(false) let pageData = reactive({ pageIndex: 1, pageSize: 10 }) onMounted(() => { getOptions() }) const getOptions = () => { axios.get(`http://localhost:9999/getSelectOptions?pageIndex=${pageData.pageIndex}&pageSize=${pageData.pageSize}`) .then(res => { console.log(res.data); if (res.data.length < 1) { ElMessage({ message: '没有更多数据了...', type: "warning", }); } const newOptions = res.data.map((item) => { return { value: item.name, label: item.index } }) options.value.push(...newOptions) }) } // 触底了,继续发请求 const loadmore = () => { pageData.pageIndex = pageData.pageIndex + 1 getOptions() } </script>
到此这篇关于ElementPlus 中el-select自定义指令实现触底加载请求options数据的文章就介绍到这了,更多相关el-select触底加载请求options数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!