一、基础内核-自定义指令
1.背景
2.定义
3.使用
4.注意
当编辑时需要回显,此时由于分页导致可能匹配不到对应label文本显示,此时可以这样解决
二、升级使用-二次封装组件
三、核心代码
1.自定义指令
定义
----------------selectLoadMoreDirective.ts--------------------
import { Directive, DirectiveBinding, nextTick } from "vue";
import { debounce } from "../utils/index";
const loadMore: Directive = {
beforeMount(el: any, binding: DirectiveBinding) {
// 查询下拉框的滚动容器
const popperClassName = el.getAttribute("popper-class-name");
let selectDom = document.querySelector(
`.${popperClassName} .el-select-dropdown__wrap`
);
function loadMores(this: any) {
// 判断是否滚动到底部
const isBase =
this.scrollHeight - this.scrollTop - 1 <= this.clientHeight;
if (isBase) {
binding.value && binding.value(); // 触发绑定的回调函数
}
}
// 使用防抖处理滚动事件
const debouncedLoadMore = debounce(loadMores, 300); // 设置防抖时间为300ms
el.selectDomInfo = selectDom;
el.userLoadMore = debouncedLoadMore; // 将防抖后的函数赋值给 el.userLoadMore
nextTick(() => {
selectDom?.addEventListener("scroll", debouncedLoadMore);
});
},
beforeUnmount(el: any) {
if (el.userLoadMore) {
el.selectDomInfo?.removeEventListener("scroll", el.userLoadMore);
delete el.selectDomInfo;
delete el.userLoadMore;
}
},
};
export default loadMore;
全局注册
------------------main.ts-----------------
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'
import loadMore from '@/directive/selectLoadMoreDirective'
const app = createApp(App)
app.use(ElementPlus)
app.use(router)
app.directive('loadMore', loadMore)
app.mount('#app')
2.二次封装组件代码
定义
-------------------------CustomSelect.vue---------------------------
<template>
<el-select
v-model="selectedValue"
v-loadMore="loadMore"
:popper-class="popperClassName"
:popper-class-name="popperClassName"
:remote-method="remoteMethod"
:loading="loading"
:placeholder="placeholder"
:style="style"
filterable
remote
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item"
/>
</el-select>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
// 定义 props
const props = defineProps({
// 双向绑定值
modelValue: {
type: [Object, String, Number],
default: null,
required: true
},
placeholder: {
type: String,
default: "请选择",
},
popperClassName: {
type: String,
default: "",
required: true
},
remoteMethod: {
type: Function,
required: true
},
loading: {
type: Boolean,
default: false,
},
style: {
type: Object,
default: () => ({}),
},
loadMore: {
type: Function,
required: true,
},
options: {
type: Array<{ value: number; label: string }>,
default: () => [],
required: true
},
});
// 加载状态
const loading = ref(false);
// 定义 emits
const emit = defineEmits(["update:modelValue"]);
// 双向绑定值
const selectedValue = ref(props.modelValue);
// 监听 modelValue 的变化
watch(
() => props.modelValue,
(newVal) => {
selectedValue.value = newVal;
}
);
// 监听 selectedValue 的变化并触发更新
watch(selectedValue, (newVal) => {
emit("update:modelValue", newVal);
});
</script>
<style scoped>
/* 自定义样式 */
</style>
使用
----------------------xxx.vue------------------------------
<template>
<CustomSelect
v-model="selectedGrade"
placeholder="选择年级"
popper-class-name="grade_select2"
:remote-method="searchGrades"
:style="{ width: '100px', marginRight: '10px' }"
:load-more="() => loadMore('grade')"
:options="grades"
/>
</template>