element-plust的select触底加载更多

550 阅读1分钟

页面组件

// 自定义指令loadMore
<template>
    <el-select v-load-more="loadMore">
        <el-option label="北京"/>
        <el-option label="上海"/>
        <el-option label="天津"/>
    </el-select>
</template>

<script setup>
    // 触发自定义指令的函数
    const loadMore = () => {
        ...
    }
</script>

新建自定义指令文件 src/directive/index.js

// 导出函数,在main.js文件中使用
const loadMore = {
    beforeMount(el, binding) {
        // 监视器的回调
        function callback(records) {
            // 观察会监视属性的新增、删除,以及值的变化
            // 所以在点击select时,会添加上aria-describedby属性并赋值,所以records是个列表,
            // 遍历一下,我们要的标签属性是aria-describedby,以及它的值oldValue
            records.map((record) => {
                if (record.attributeName == 'aria-describedby' && record.oldValue) {
                    // 根据aria-describedby的值,也就是oldValue,我们获取id为oldValue的下拉框DOM
                    let poper = document.getElementById(record.oldValue)
                     
                    if (poper) {
                        // 再获取popup的子元素scrollbar,监听滚动事件loadMores
                        const optionDom = poper.querySelector('.el-scrollbar .el-select-dropdown__wrap');
                        optionDom.addEventListener('scroll', loadMores.bind(optionDom))
                    }
                }
            })
        }
        // scroll时的事件
        function loadMores() {
            let condition = this.scrollHeight - this.scrollTop <= this.clientHeight +30
            if (condition) {
                binding.value && binding.value()
            }
        }
        // 获取select-trigger,因为它身上有一个属性aria-describedby
        // (我看其他教程 不是aria-describedby这个名字,可能是版本不一样,官方有所改动吧)
        // 这个属性的值和下拉框popup的id是相同的
        const selectDom = el.querySelector('.select-trigger')
        // 使用观察器,callback回调在上面已经定义了
        // 因为下拉框未显示时,select-trigger身上没有aria-describedby属性
        let observer = new MutationObserver(callback);
        // observer.observe('观察的DOM', '观察的属性'),这里我们要监视select的属性aria-describedby
        // MutationObserver观察器具体配置可以自己百度一下
        observer.observe(selectDom, {
            attributes: true, 
            attributeOldValue: true
        })
    }
}

export default function directive(app) {
    // 注册自定义指令app.directive('指令名', 指令事件)
    app.directive('loadMore', loadMore)
}

在main.js中导入自定义指令directive

...
import directive from './directive/index.js'

const app = createApp(App)
// 往函数中传入app
directive(app)