floatingUI的使用, 这个主要是解决弹窗等的自适应的问题, 官网:https://floating-ui.com/docs/getting-started
//usePatchSelect.ts
import {
autoUpdate,
flip,
offset as offsetMiddleware,
shift,
useFloating,
} from "@floating-ui/vue";
export const usePatchSelect = () => {
const id = useId();
const wrapperElement = ref<HTMLElement | null | undefined>(null);
const floatingElement = ref<HTMLElement | null | undefined>(null);
const referenceElement = ref<HTMLElement | null | undefined>(null);
const floating = useFloating(referenceElement, floatingElement, {
placement: "bottom-start",
middleware: [offsetMiddleware(0), shift(), flip()],
whileElementsMounted: autoUpdate,
});
const onBeforeOpen = () => {
nextTick(() => {
wrapperElement.value = document.querySelector<HTMLElement>(
`[data-app-select-id="${id}"]`,
);
referenceElement.value = wrapperElement.value?.querySelector<HTMLElement>(
".common-field__dropdown-input",
);
floatingElement.value = wrapperElement.value?.querySelector<HTMLElement>(
".common-field__options",
);
floating.update();
wrapperElement.value?.classList.add("overflow-hidden");
});
};
const onAfterClose = () => {
floatingElement.value = null;
floating.update();
};
watch(floating.floatingStyles, (styles) => {
wrapperElement.value?.classList.remove("overflow-hidden");
const listBox = floatingElement.value;
if (listBox) {
if (listBox.classList.contains("transition")) {
listBox.classList.remove("transition");
listBox.classList.add("transition-[opacity]");
}
Object.assign(listBox.style, styles);
}
});
return {
onBeforeOpen,
onAfterClose,
"data-app-select-id": id,
};
};
const patchedProps = usePatchSelect();
<AppSelect
:model-value="perPageSelection"
class="min-w-[8rem] md:!w-auto"
:items="perPageOptions"
v-bind="patchedProps" //重要的是这个,会把usePatchSelect中暴露的 "data-app-select-id": id 绑定到这个元素(有个data-app-select-id属性),然后后面所有的操作都是基于这个id进行的
@update:model-value="emit('changePerPage', $event as MSelectItem<number>)"
/>
<!-- AppSelect.vue -->
<template>
<div class="app-select-wrapper" v-bind="$attrs"> // vue3使用这个v-bind="$attrs" 来获取需要绑定的属性,这里是data-app-select-id
<!-- dropdown, input, etc -->
</div>
</template>
