Vue Dropdown组件onChange回调在iPhone设备上无法触发问题
问题分析与解决方案
问题现象
- 桌面端下拉菜单组件运行正常
- iPhone Safari浏览器中,选择下拉选项后菜单消失,但选中项未变更
- iOS横屏模式下偶尔可正常工作
问题根源
- 组件中
selectedOption与modelValue重复传递且未同步,导致内部状态和外部v-model脱节 - iOS Safari下
v-close-popper的事件触发顺序优先于onChange,弹窗关闭时状态更新逻辑被中断 - 未监听
modelValue变化来同步内部选中状态,引发数据不一致
修复后的BaseSelect.vue代码
<script lang="ts" setup> import HelperMethods from '@/methods/helper'; import { ref, watch } from 'vue'; const emit = defineEmits(['update:modelValue']) const props = defineProps({ label: { type: String }, modelValue: { type: String, default: '' }, choices: { type: Array<string>, default: () => [] }, autoCapitalize: { type: Boolean, default: true }, disabled: { type: Boolean, default: false } }) // 内部维护选中状态,与外部modelValue同步 const selectedOption = ref(props.modelValue); // 监听外部modelValue变化,实时更新内部状态 watch(() => props.modelValue, (newVal) => { selectedOption.value = newVal; }, { immediate: true }) const onChange = (value: string) => { selectedOption.value = value; emit('update:modelValue', value); } </script> <template> <label v-if="label">{{ label }}</label> <VDropdown :class="{ disabled: disabled }"> <button v-if="choices.length > 1" type="button" :disabled="disabled"> {{ autoCapitalize ? HelperMethods.uppercaseFirstLetter(selectedOption) : selectedOption }} <span>▼</span> </button> <h3 v-else> {{ autoCapitalize ? HelperMethods.uppercaseFirstLetter(selectedOption) : selectedOption }} </h3> <template #popper> <div class="select-content" v-bind="$attrs"> <button @click="onChange(choice)" v-for="choice in choices" :value="choice" :key="choice" :class="{ 'selected': selectedOption === choice }" type="button" > {{ autoCapitalize ? HelperMethods.uppercaseFirstLetter(choice) : choice }} </button> </div> </template> </VDropdown> </template> <style scoped> .select-content { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.5rem; border-radius: 15px; } .selected { background-color: #f0f0f0; } </style>
页面代码优化(移除冗余传递)
<template> <BaseSelect v-if="websiteDataStore.websites.length > 0" :choices="websiteDataStore.websites.map(website => website.url)" :autoCapitalize="false" :label="`Now viewing:`" v-model="currentWebsiteUrl" /> <nav-bar> <RouterLink :to="{ name: 'WebsiteStats' }">Stats</RouterLink> <RouterLink :to="{ name: 'content' }">Content</RouterLink> <RouterLink :to="{ name: 'forms' }">Forms</RouterLink> <RouterLink :to="{ name: 'settings' }">Settings</RouterLink> </nav-bar> <div> <RouterView v-if="websiteDataStore.websites.length > 0" /> </div> </template>
修复说明
- 移除冗余的
selectedOption属性,组件内部通过ref维护状态并监听modelValue实现双向同步,避免数据不一致 - 删除
v-close-popper,依赖下拉组件自身的弹窗关闭逻辑,规避iOS Safari下的事件顺序冲突 - 添加选中项样式,提升用户识别度
- 给触发按钮绑定
disabled状态,完善组件禁用逻辑
内容的提问来源于stack exchange,提问作者Jacob Miller
相关产品推荐
相关产品推荐

