You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue Dropdown组件onChange回调在iPhone设备上无法触发问题

问题分析与解决方案

问题现象

  • 桌面端下拉菜单组件运行正常
  • iPhone Safari浏览器中,选择下拉选项后菜单消失,但选中项未变更
  • iOS横屏模式下偶尔可正常工作

问题根源

  1. 组件中selectedOption与modelValue重复传递且未同步,导致内部状态和外部v-model脱节
  2. iOS Safari下v-close-popper的事件触发顺序优先于onChange,弹窗关闭时状态更新逻辑被中断
  3. 未监听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>&#9660;</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>

修复说明

  1. 移除冗余的selectedOption属性,组件内部通过ref维护状态并监听modelValue实现双向同步,避免数据不一致
  2. 删除v-close-popper,依赖下拉组件自身的弹窗关闭逻辑,规避iOS Safari下的事件顺序冲突
  3. 添加选中项样式,提升用户识别度
  4. 给触发按钮绑定disabled状态,完善组件禁用逻辑

内容的提问来源于stack exchange,提问作者Jacob Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:45:54