Vue select 选中了错误的 Map 选项:检查集合值比较
模型中的 Map 内容正确,原生 select 却高亮另一个选项。区分集合比较缺陷与模型更新,并按正式修复或稳定 ID 处理。
原生 <select v-model> 的模型保存了第二个 Map,界面却一直选中第一个选项;读取模型里的 id 又确实是第二个值。若选项直接用 Map 或 Set 作 :value,应检查 Vue 的集合值比较,而不是先给 change 事件增加延时。
在 Vue 3.5.41 的正式实现中,Map、Set 没有独立的内容比较分支。两个 Map 的键值即使不同,也可能被判为相等。Vue 3.5.42 已加入集合比较;3.5.43 还补充了循环引用处理。需要支持循环集合时,不能只停在 3.5.42;还可对照循环集合的表单值处理,区分集合比较与表单模型设计。
模型正确,选项扫描仍可能提前结束
下面是说明问题的组件示例,集合都不含循环引用:
<script setup>
import { ref } from 'vue';
const first = new Map([['id', 1]]);
const second = new Map([['id', 2]]);
const selected = ref(second);
</script>
<template>
<select v-model="selected">
<option :value="first">第一项</option>
<option :value="second">第二项</option>
</select>
<p>模型编号:{{ selected.get('id') }}</p>
</template>
旧版的 looseEqual 将集合送入普通对象比较。Map 的条目不在 Object.keys() 中,两个集合都可能表现为“没有可枚举键”;字符串兜底又同为 [object Map]。select 按顺序找到第一个宽松相等的值就停止,于是模型为 2,视觉选择却落在第一项。Set 有相同的旧比较缺口。
先核对页面实际加载的 Vue 版本、选项类型,并比较高亮项与模型值。如果模型本身已被 change 回调改写,或 option 没有正确绑定值,应先处理实际数据流;这条集合分支不能解释所有 select 误选。
更新比较实现,或让表单保存稳定 ID
项目兼容时,采用包含集合比较修复的正式 Vue 版本,并让 vue、编译器和框架管理的依赖保持兼容。不要直接从 @vue/shared 导入内部比较函数来替换表单行为,它不是应用需要自行接管的公共表单接口。
不准备让原生表单比较复杂对象时,可以把模型改成稳定的标识,例如 selectedId = ref('second'),两个 option 分别使用 value="first"、value="second",再通过业务 Map 查出所选对象。该方案会改变表单值契约:存储、提交与读取端都要从“整个集合”改为“标识加查找”,不能只改模板一处。
不要把两个集合一律转成字符串作为值。默认字符串会再次丢失差异,JSON 序列化也不会自动保留 Map、Set 的成员语义。业务确实需要保存整个集合时,应保留原模型契约,优先修正工具版本。
验收要同时核对首次挂载的高亮项、切换后的模型内容,以及重新加载保存值后的选择。再覆盖顺序不同但内容相同的集合和内容确实不同的集合;有循环数据时另加循环路径。仅确认 selected.get('id') 正确,无法证明视觉选择已恢复。


