Compare commits

3 Commits

View File

@ -67,8 +67,8 @@
style="width: 100%"
:disabled="isEditMode"
class="beautified-select"
popper-class="bom-loadmore-popper parent-popper"
@visible-change="(visible: boolean) => handleVisibleChange(visible, 'parent')"
v-loadmore="loadMoreParent"
>
<el-option
v-for="item in parentOptions"
@ -147,8 +147,8 @@
:loading="selectLoading"
style="width: 100%"
:loading-text="`正在加载第 ${childQueryParams.page} 页...`"
:popper-class="`bom-loadmore-popper child-popper-${$index}`"
@visible-change="(visible: boolean) => handleVisibleChange(visible, 'child', $index)"
v-loadmore="(el: HTMLElement) => loadMoreChild(el, $index)"
>
<el-option
v-for="item in getChildOptions($index)"
@ -207,56 +207,6 @@ import { getBomList, getBomDetail, saveBom, deleteBom } from '@/api/bom'
import { getMaterialBaseList } from '@/api/inbound/stock'
import { useUserStore } from '@/stores/user'
// ============================================================
// v-loadmore 自定义指令(局部注册)
// 用于监听 Element Plus 下拉面板的滚动触底事件
// ============================================================
const vLoadmore = {
mounted(el: HTMLElement, binding: any) {
// 找到 .el-select-dropdown__wrap滚动容器
const targetSelector = '.el-select-dropdown:not(.is-hidden) .el-select-dropdown__wrap'
const scrollHandler = () => {
const scrollContainer = el.querySelector(targetSelector) as HTMLElement | null
if (!scrollContainer) return
const { scrollTop, scrollHeight, clientHeight } = scrollContainer
const distanceToBottom = scrollHeight - scrollTop - clientHeight
// 距离底部 10px 以内时触发加载更多
if (distanceToBottom <= 10) {
binding.value(el)
}
}
// 使用 MutationObserver 监听 DOM 变化Element Plus 下拉弹窗是动态创建的)
const observer = new MutationObserver(() => {
const dropdown = el.querySelector('.el-select-dropdown:not(.is-hidden)') as HTMLElement | null
if (dropdown) {
const wrap = dropdown.querySelector('.el-select-dropdown__wrap') as HTMLElement | null
if (wrap) {
wrap.removeEventListener('scroll', scrollHandler)
wrap.addEventListener('scroll', scrollHandler)
}
}
})
observer.observe(el, {
childList: true,
subtree: true
})
// 存储清理函数
;(el as any)._loadmoreObserver = observer
},
unmounted(el: HTMLElement) {
const observer = (el as any)._loadmoreObserver
if (observer) {
observer.disconnect()
}
}
}
// ============================================================
// 类型定义
// ============================================================
@ -432,6 +382,38 @@ const handleVisibleChange = (visible: boolean, type: 'parent' | 'child', index?:
state.hasMore = true
fetchMaterialOptions('child', index)
}
// 延迟 50ms 等待弹窗 DOM 完全渲染
setTimeout(() => {
// 动态拼接精确的选择器
const exactSelector = type === 'parent'
? '.parent-popper .el-select-dropdown__wrap'
: `.child-popper-${index} .el-select-dropdown__wrap`;
const popperWrap = document.querySelector(exactSelector) as HTMLElement;
if (popperWrap) {
// 解绑旧事件,防止重复触发
if ((popperWrap as any)._scrollHandler) {
popperWrap.removeEventListener('scroll', (popperWrap as any)._scrollHandler);
}
// 定义滚动触发逻辑
(popperWrap as any)._scrollHandler = function() {
const { scrollTop, scrollHeight, clientHeight } = this;
// 距离底部 10px 触发
if (scrollHeight - scrollTop - clientHeight <= 10) {
if (type === 'parent') {
loadMoreParent();
} else if (type === 'child' && index !== undefined) {
// 触发子件加载
loadMoreChild(popperWrap, index);
}
}
};
popperWrap.addEventListener('scroll', (popperWrap as any)._scrollHandler);
}
}, 50);
}
// ============================================================