fix(overlay): 修复手机端图片/视频本地选择兼容性问题

- 将 local-files 事件类型由 FileList 改为 File[],避免 WebView 中 FileList 在 input 清空后失效
- 屏蔽文件选择器关闭后 500ms 内的 backdrop click,防止 touch 穿透误关 overlay
- 延迟 200ms 清空 input value,避免国产手机 WebView 异步填充 files 被截断
This commit is contained in:
JOJO 2026-06-07 17:19:53 +08:00
parent 7c08031413
commit d639278182
2 changed files with 31 additions and 10 deletions

View File

@ -79,12 +79,14 @@ const props = withDefaults(
const emit = defineEmits<{
(e: 'close'): void;
(e: 'confirm', list: string[]): void;
(e: 'local-files', files: FileList | null): void;
(e: 'local-files', files: File[] | null): void;
}>();
const selectedSet = ref<Set<string>>(new Set(props.initialSelected || []));
const localInput = ref<HTMLInputElement | null>(null);
let ignoreBackdropClickUntil = 0;
watch(
() => props.initialSelected,
(val) => {
@ -106,25 +108,35 @@ const toggle = (path: string) => {
selectedSet.value = set;
};
const close = () => emit('close');
const close = () => {
if (Date.now() < ignoreBackdropClickUntil) return;
emit('close');
};
const confirm = () => emit('confirm', Array.from(selectedSet.value));
const triggerLocal = () => {
if (props.uploading) return;
// 500ms backdrop click touch 穿 overlay
ignoreBackdropClickUntil = Date.now() + 500;
localInput.value?.click();
};
const onLocalChange = (event: Event) => {
const target = event.target as HTMLInputElement;
const files = target?.files || null;
const rawFiles = target?.files;
// WebView input value FileList
const files = rawFiles && rawFiles.length ? Array.from(rawFiles) : null;
if (!files || files.length === 0) {
console.warn('[ImagePicker] change fired but files empty — likely WebView compat issue');
emit('local-files', null);
} else {
emit('local-files', files);
}
emit('local-files', files);
if (target) {
target.value = '';
}
// WebView files files
setTimeout(() => {
if (target) target.value = '';
}, 200);
};
const previewUrl = (path: string) => `/api/gui/files/download?path=${encodeURIComponent(path)}`;

View File

@ -81,12 +81,14 @@ const props = withDefaults(
const emit = defineEmits<{
(e: 'close'): void;
(e: 'confirm', list: string[]): void;
(e: 'local-files', files: FileList | null): void;
(e: 'local-files', files: File[] | null): void;
}>();
const selectedSet = ref<Set<string>>(new Set(props.initialSelected || []));
const localInput = ref<HTMLInputElement | null>(null);
let ignoreBackdropClickUntil = 0;
watch(
() => props.initialSelected,
(val) => {
@ -108,18 +110,25 @@ const toggle = (path: string) => {
selectedSet.value = set;
};
const close = () => emit('close');
const close = () => {
if (Date.now() < ignoreBackdropClickUntil) return;
emit('close');
};
const confirm = () => emit('confirm', Array.from(selectedSet.value));
const triggerLocal = () => {
if (props.uploading) return;
// 500ms backdrop click touch 穿 overlay
ignoreBackdropClickUntil = Date.now() + 500;
localInput.value?.click();
};
const onLocalChange = (event: Event) => {
const target = event.target as HTMLInputElement;
const files = target?.files || null;
const rawFiles = target?.files;
// WebView input value FileList
const files = rawFiles && rawFiles.length ? Array.from(rawFiles) : null;
if (!files || files.length === 0) {
console.warn('[VideoPicker] change fired but files empty — likely WebView compat issue');
}