mirror of https://github.com/halo-dev/halo
fix: dropdown options cannot be clicked in some mobile devices (#4116)
#### What type of PR is this? /area console /kind improvement /milestone 2.7.x #### What this PR does / why we need it: 修复在部分移动端浏览器(比如 iOS Safari)中,下拉框组件(VDropdown)的选项点击无效的问题,即没有触发 click 事件。此问题的原因可能是因为我们用的 floating-vue 组件提供的 `v-close-popper` 指令的兼容问题,最小复现:https://stackblitz.com/edit/vitejs-vite-ncpzhj?file=src%2FApp.vue 此 PR 改写了关闭下拉框的方式,不再使用 v-close-popper 指令,而且对其他使用此组件的地方没有破坏性更新。 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/3689 Ref https://github.com/halo-dev/halo/issues/2699 #### Special notes for your reviewer: 如果有条件可以在移动端测试一下,尤其是 iOS Safari,目前在桌面端 Chrome 的设备模拟中测试正常。 #### Does this PR introduce a user-facing change? ```release-note 修复 Console 端的下拉框组件选项在移动端无法正常点击的问题。 ```pull/4061/head
parent
aaa3548c97
commit
27ef8d3bab
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts" setup>
|
||||
import { Dropdown as FloatingDropdown, type Placement } from "floating-vue";
|
||||
import "floating-vue/dist/style.css";
|
||||
import { provide, ref } from "vue";
|
||||
import { DropdownContextInjectionKey } from "./symbols";
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
|
@ -15,13 +17,28 @@ withDefaults(
|
|||
}
|
||||
);
|
||||
|
||||
const dropdownRef = ref();
|
||||
|
||||
function hide() {
|
||||
dropdownRef.value?.hide();
|
||||
}
|
||||
|
||||
provide(DropdownContextInjectionKey, {
|
||||
hide,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "show"): void;
|
||||
}>();
|
||||
|
||||
defineExpose({
|
||||
hide,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FloatingDropdown
|
||||
ref="dropdownRef"
|
||||
:placement="placement"
|
||||
:triggers="triggers"
|
||||
@show="emit('show')"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { VClosePopper } from "floating-vue";
|
||||
import { DropdownContextInjectionKey } from "./symbols";
|
||||
import { inject } from "vue";
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
|
@ -11,15 +12,26 @@ withDefaults(
|
|||
type: "default",
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "click", e: MouseEvent): void;
|
||||
}>();
|
||||
|
||||
const { hide } = inject(DropdownContextInjectionKey) || {};
|
||||
|
||||
function onClick(e: MouseEvent) {
|
||||
hide?.();
|
||||
emit("click", e);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-close-popper
|
||||
class="dropdown-item-wrapper"
|
||||
:class="[`dropdown-item-wrapper--${type}${selected ? '--selected' : ''}`]"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
@click="onClick"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<slot name="prefix-icon" />
|
||||
|
|
|
@ -2,3 +2,4 @@ export { default as VDropdown } from "./Dropdown.vue";
|
|||
export { default as VDropdownItem } from "./DropdownItem.vue";
|
||||
export { default as VDropdownDivider } from "./DropdownDivider.vue";
|
||||
export { VClosePopper } from "floating-vue";
|
||||
export * from "./symbols";
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import type { InjectionKey } from "vue";
|
||||
|
||||
export const DropdownContextInjectionKey: InjectionKey<{
|
||||
hide: () => void;
|
||||
}> = Symbol("dropdown-context");
|
|
@ -22,6 +22,8 @@ const emit = defineEmits<{
|
|||
|
||||
const { categories } = usePostCategory();
|
||||
|
||||
const dropdown = ref();
|
||||
|
||||
const handleSelect = (category: Category) => {
|
||||
if (
|
||||
props.selected &&
|
||||
|
@ -34,6 +36,8 @@ const handleSelect = (category: Category) => {
|
|||
|
||||
emit("update:selected", category);
|
||||
emit("select", category);
|
||||
|
||||
dropdown.value.hide();
|
||||
};
|
||||
|
||||
function onDropdownShow() {
|
||||
|
@ -71,7 +75,7 @@ const searchResults = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<VDropdown :classes="['!p-0']" @show="onDropdownShow">
|
||||
<VDropdown ref="dropdown" :classes="['!p-0']" @show="onDropdownShow">
|
||||
<slot />
|
||||
<template #popper>
|
||||
<div class="h-96 w-80">
|
||||
|
@ -91,7 +95,6 @@ const searchResults = computed(() => {
|
|||
<li
|
||||
v-for="(category, index) in searchResults"
|
||||
:key="index"
|
||||
v-close-popper
|
||||
@click="handleSelect(category)"
|
||||
>
|
||||
<VEntity
|
||||
|
|
|
@ -23,6 +23,8 @@ const emit = defineEmits<{
|
|||
|
||||
const { tags } = usePostTag();
|
||||
|
||||
const dropdown = ref();
|
||||
|
||||
const handleSelect = (tag: Tag) => {
|
||||
if (props.selected && tag.metadata.name === props.selected.metadata.name) {
|
||||
emit("update:selected", undefined);
|
||||
|
@ -32,6 +34,8 @@ const handleSelect = (tag: Tag) => {
|
|||
|
||||
emit("update:selected", tag);
|
||||
emit("select", tag);
|
||||
|
||||
dropdown.value.hide();
|
||||
};
|
||||
|
||||
function onDropdownShow() {
|
||||
|
@ -69,7 +73,7 @@ const searchResults = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<VDropdown :classes="['!p-0']" @show="onDropdownShow">
|
||||
<VDropdown ref="dropdown" :classes="['!p-0']" @show="onDropdownShow">
|
||||
<slot />
|
||||
<template #popper>
|
||||
<div class="h-96 w-80">
|
||||
|
@ -89,7 +93,6 @@ const searchResults = computed(() => {
|
|||
<li
|
||||
v-for="(tag, index) in searchResults"
|
||||
:key="index"
|
||||
v-close-popper
|
||||
@click="handleSelect(tag)"
|
||||
>
|
||||
<VEntity
|
||||
|
|
|
@ -27,6 +27,8 @@ const emit = defineEmits<{
|
|||
|
||||
const { users, handleFetchUsers } = useUserFetch();
|
||||
|
||||
const dropdown = ref();
|
||||
|
||||
const handleSelect = (user: User) => {
|
||||
if (props.selected && user.metadata.name === props.selected.metadata.name) {
|
||||
emit("update:selected", undefined);
|
||||
|
@ -36,6 +38,8 @@ const handleSelect = (user: User) => {
|
|||
|
||||
emit("update:selected", user);
|
||||
emit("select", user);
|
||||
|
||||
dropdown.value.hide();
|
||||
};
|
||||
|
||||
function onDropdownShow() {
|
||||
|
@ -71,7 +75,7 @@ const searchResults = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<VDropdown :classes="['!p-0']" @show="onDropdownShow">
|
||||
<VDropdown ref="dropdown" :classes="['!p-0']" @show="onDropdownShow">
|
||||
<slot />
|
||||
<template #popper>
|
||||
<div class="h-96 w-80">
|
||||
|
@ -91,7 +95,6 @@ const searchResults = computed(() => {
|
|||
<li
|
||||
v-for="(user, index) in searchResults"
|
||||
:key="index"
|
||||
v-close-popper
|
||||
@click="handleSelect(user)"
|
||||
>
|
||||
<VEntity
|
||||
|
|
|
@ -266,15 +266,10 @@ onMounted(async () => {
|
|||
{{ $t("core.common.buttons.delete") }}
|
||||
</VDropdownItem>
|
||||
<template #popper>
|
||||
<VDropdownItem
|
||||
v-close-popper.all
|
||||
type="danger"
|
||||
@click="handleDelete(group)"
|
||||
>
|
||||
<VDropdownItem type="danger" @click="handleDelete(group)">
|
||||
{{ $t("core.attachment.group_list.operations.delete.button") }}
|
||||
</VDropdownItem>
|
||||
<VDropdownItem
|
||||
v-close-popper.all
|
||||
type="danger"
|
||||
@click="handleDeleteWithAttachments(group)"
|
||||
>
|
||||
|
|
|
@ -208,18 +208,10 @@ const handleUninstall = async (theme: Theme, deleteExtensions?: boolean) => {
|
|||
{{ $t("core.common.buttons.uninstall") }}
|
||||
</VDropdownItem>
|
||||
<template #popper>
|
||||
<VDropdownItem
|
||||
v-close-popper.all
|
||||
type="danger"
|
||||
@click="handleUninstall(theme)"
|
||||
>
|
||||
<VDropdownItem type="danger" @click="handleUninstall(theme)">
|
||||
{{ $t("core.common.buttons.uninstall") }}
|
||||
</VDropdownItem>
|
||||
<VDropdownItem
|
||||
v-close-popper.all
|
||||
type="danger"
|
||||
@click="handleUninstall(theme, true)"
|
||||
>
|
||||
<VDropdownItem type="danger" @click="handleUninstall(theme, true)">
|
||||
{{ $t("core.theme.operations.uninstall_and_delete_config.button") }}
|
||||
</VDropdownItem>
|
||||
</template>
|
||||
|
|
|
@ -154,14 +154,10 @@ const handleResetSettingConfig = async () => {
|
|||
{{ $t("core.common.buttons.uninstall") }}
|
||||
</VDropdownItem>
|
||||
<template #popper>
|
||||
<VDropdownItem v-close-popper.all type="danger" @click="uninstall">
|
||||
<VDropdownItem type="danger" @click="uninstall">
|
||||
{{ $t("core.common.buttons.uninstall") }}
|
||||
</VDropdownItem>
|
||||
<VDropdownItem
|
||||
v-close-popper.all
|
||||
type="danger"
|
||||
@click="uninstall(true)"
|
||||
>
|
||||
<VDropdownItem type="danger" @click="uninstall(true)">
|
||||
{{ $t("core.plugin.list.actions.uninstall_and_delete_config") }}
|
||||
</VDropdownItem>
|
||||
</template>
|
||||
|
|
Loading…
Reference in New Issue