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

Vue 3 Composition API ref原始属性响应式失效问题排查

问题根因

代码存在多个核心问题直接导致响应式失效:

  • selectedTitle是独立ref,初始化时仅取了tabTitles首次计算的第一个值做静态赋值,和tabTitles没有任何响应式绑定,后续tabTitles更新不会自动同步到该ref。
  • watcher监听源写法错误:() => tabTitlesLength返回的是computed ref对象本身,没有取.value,watcher根本无法追踪到长度变化。
  • watcher配置冗余错误:给基础类型值的监听加了无意义的deep: true,触发了引用类型监听时新旧值同引用的已知问题,导致新旧值判断逻辑完全失效。
  • 回调赋值逻辑错误:selectedTitle本身已经是ref实例,给selectedTitle.value赋值时额外包裹了一层ref(),实际存入的是ref实例而非标签标题字符串。
  • 原有判断逻辑有缺陷:仅通过长度变小触发更新,没有校验当前选中标签是否已被移除,无法覆盖所有选中值失效的场景。
修复方案

按以下步骤调整即可实现预期效果:

  • 移除冗余的tabTitlesLength计算属性,减少无效代码。
  • 修正watcher监听源为() => tabTitles.value,移除不必要的deep: true配置,只要标签列表发生变化就触发校验。
  • 调整校验逻辑:不依赖新旧长度对比,直接判断当前selectedTitle.value是否存在于最新的标签列表中,不存在则默认选中列表第一个标签,覆盖所有选中值失效的场景。
  • 修正赋值逻辑,给selectedTitle.value赋值时直接传入标题字符串,去掉多余的ref()包裹。

修正后的核心script代码如下:

<script>
import { ref, computed, useSlots, provide, watch } from "vue";
export default {
  props: {
    defaultTagMenu: {
      type: Boolean,
      default: true,
    },
  },
  setup() {
    const slots = useSlots();
    const tabTitles = computed(() =>
      slots.default()[0].children.map((tab) => tab.props.title)
    );
    const selectedTitle = ref(tabTitles.value[0]);
    provide("selectedTitle", selectedTitle);
    provide("tabTitles", tabTitles);

    watch(
      () => tabTitles.value,
      (newTitles) => {
        // 当前选中标签不存在于列表时,默认选中第一个标签
        if (!newTitles.includes(selectedTitle.value)) {
          selectedTitle.value = newTitles[0];
        }
      }
    );

    return {
      tabTitles,
      selectedTitle,
    };
  },
};
</script>

补充优化:如果需要更符合用户操作习惯的交互,比如关闭当前选中标签时自动选中相邻标签而非回到第一个,可以在校验逻辑中先获取当前选中项的索引,优先选中前一个/后一个标签即可,核心响应式逻辑不变。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 13:24:22