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

Laravel Inertia.js Vue3:自定义Select组件默认选中值失效问题

自定义Select组件初始值显示异常问题

我基于Vue3、Inertia.js和Laravel开发时遇到一个问题:测试用例里,自定义Select.vue组件无法正常显示初始值,默认选中了最后一个选项(test);但原生<select v-model="form.test">标签能正常显示初始值。查看DOM结构,两个下拉框的option元素v-if状态都正确(值为2的option的v-if为true),但自定义组件还是异常。

相关代码

Test.vue

<template>
    <form @submit.prevent="submit">
        <select v-model="form.test">
            <option v-for="option in options" :key="option.id" :value="option.id" :v-if="option.id == initial" selected>
                {{ option.name }}
            </option>
        </select>

        <Select name="test" placeholder="Select Something"
                v-model="form.test" :options="options"/>
    </form>
</template>

<script setup>
import {useForm} from "@inertiajs/vue3";
import Select from "./Components/Forms/Input/Select.vue";

let options = [
    {"id": 1, "name": "Some Value"},
    {"id": 2, "name": "Another Value"},
    {"id": 3, "name": "test"},
]

let initial = 2

defineProps({
    options: Array
});

let form = useForm({
    test: initial
});
</script>

Select.vue

<template>
        <label :for="name" class="col-lg-3 col-form-label">{{ name }}:</label>
    
            <select :name="name" :id="name" @change="emit('update:model-value', $event.target.value);" class="form-select" :class="error ? 'is-invalid' : ''">
                <option :value="null" hidden>{{ placeholder }}</option>
                <option v-for="option in options" :key="option.id" :value="option.id" :v-if="option.id == modelValue" selected>
                    {{ option.name }}
                </option>
            </select>

        </div>

    </div>

    {{ modelValue }}

</template>

<script setup>
defineProps({
    name: String,
    placeholder: String,
    options: Object,
    error: String,
    modelValue: String
});

let emit = defineEmits(['update:model-value']);
</script>

问题根源及修复方案

核心问题分析

  1. 类型不匹配:自定义组件中modelValue被定义为String类型,但传入的初始值是数字2,导致option.id == modelValue比较时(数字vs字符串)不相等,无法正确匹配选中项。
  2. Props类型错误:options被定义为Object,但实际传入的是数组,导致渲染异常。
  3. 错误的选项渲染逻辑:用v-if只渲染匹配初始值的选项,而非渲染所有选项并动态标记选中状态,不符合select组件的正常工作逻辑。
  4. 未同步初始值到select元素:自定义select未绑定初始值,仅靠change事件更新值,导致初始化时选中状态异常。

修复步骤

1. 修正Props类型

在Select.vue中调整Props的类型定义,支持数字/字符串类型的modelValue,并将options改为数组类型:

defineProps({
    name: String,
    placeholder: String,
    options: Array, // 修正为数组类型
    error: String,
    modelValue: [String, Number] // 支持数字和字符串
});

2. 修复选项渲染逻辑

移除v-if,改为渲染所有选项,删除静态selected属性,Vue会通过v-model自动管理选中状态:

<option v-for="option in options" :key="option.id" :value="option.id">
    {{ option.name }}
</option>

注:原生组件里的v-if也建议移除,否则只能看到选中的选项,无法切换其他选项。

3. 优化select的双向绑定逻辑

改用v-model绑定本地变量,同步初始值和更新事件,替代手动监听change事件:

<select 
    :name="name" 
    :id="name" 
    v-model="localValue" 
    class="form-select" 
    :class="error ? 'is-invalid' : ''"
>
    <option :value="null" hidden>{{ placeholder }}</option>
    <option v-for="option in options" :key="option.id" :value="option.id">
        {{ option.name }}
    </option>
</select>

在script setup中添加变量和监听:

import { ref, watch } from 'vue';

const props = defineProps({
    name: String,
    placeholder: String,
    options: Array,
    error: String,
    modelValue: [String, Number]
});
const emit = defineEmits(['update:model-value']);

// 本地变量同步modelValue
const localValue = ref(props.modelValue);

// 本地值变化时触发更新事件
watch(localValue, (newVal) => {
    emit('update:model-value', newVal);
});

// 父组件modelValue变化时同步本地值
watch(() => props.modelValue, (newVal) => {
    localValue.value = newVal;
});

4. 清理冗余DOM标签

Select.vue模板中有多余的</div>标签,需删除以确保DOM结构正确。

修复后的完整Select.vue代码

<template>
    <div>
        <label :for="name" class="col-lg-3 col-form-label">{{ name }}:</label>
        <select 
            :name="name" 
            :id="name" 
            v-model="localValue" 
            class="form-select" 
            :class="error ? 'is-invalid' : ''"
        >
            <option :value="null" hidden>{{ placeholder }}</option>
            <option v-for="option in options" :key="option.id" :value="option.id">
                {{ option.name }}
            </option>
        </select>
    </div>
</template>

<script setup>
import { ref, watch } from 'vue';

const props = defineProps({
    name: String,
    placeholder: String,
    options: Array,
    error: String,
    modelValue: [String, Number]
});
const emit = defineEmits(['update:model-value']);

const localValue = ref(props.modelValue);

watch(localValue, (newVal) => {
    emit('update:model-value', newVal);
});

watch(() => props.modelValue, (newVal) => {
    localValue.value = newVal;
});
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:14:59