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

使用ref而非reactive时,如何让数组中单个属性具备响应式?

Vue组件中仅让单个属性响应式实现详情切换功能

我有一个展示数据行的组件,需要实现详情的显示/隐藏切换功能。原本用reactive把数据映射成包含opened属性的数组,功能正常,但不想让整个数组深度响应式。于是尝试用ref只让opened属性响应式,虽然opened具备响应性,但切换功能失效。怎么在不使整个值响应式的前提下让切换功能正常工作?

可正常工作的代码

<script setup>
import { defineProps, reactive } from 'vue';

const props = defineProps({
  data: {
    type: Array,
    required: true,
  },
  dataKey: {
    type: String,
    required: true,
  },
});

const rows = reactive(props.data.map(value => {
  return {
    value,
    opened: false,
  };
}));

function toggleDetails(row) {
  row.opened = !row.opened;
}
</script>

<template>
  <div>
    <template v-for="row in rows" :key="row.value[dataKey]">
      <div>
        <!-- Toggle Details -->
        <a @click.prevent="() => toggleDetails(row)">
          {{ row.value.key }}: {{ row.opened ? 'Hide' : 'Show' }} details
        </a>

        <!-- Details -->
        <div v-if="row.opened" style="border: 1px solid #ccc">
          <div>opened: <pre>{{ row.opened }}</pre></div>
          <div>value: </div>
          <pre>{{ row.value }}</pre>
        </div>
      </div>
    </template>
  </div>
</template>

尝试的非工作代码

const rows = props.data.map(value => {
  return {
    value,
    opened: ref(false),
  };
});

function toggleDetails(row) {
  row.opened.value = !row.opened.value;
}

解决方案

问题根源是模板里没正确读取ref的value属性:ref作为顶层属性时会自动解包,但嵌套在普通对象里的ref不会,必须手动访问.value才能获取响应式状态。

修改后的完整代码

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

const props = defineProps({
  data: {
    type: Array,
    required: true,
  },
  dataKey: {
    type: String,
    required: true,
  },
});

const rows = props.data.map(value => {
  return {
    value,
    opened: ref(false),
  };
});

function toggleDetails(row) {
  row.opened.value = !row.opened.value;
}
</script>

<template>
  <div>
    <template v-for="row in rows" :key="row.value[dataKey]">
      <div>
        <!-- Toggle Details -->
        <a @click.prevent="() => toggleDetails(row)">
          {{ row.value.key }}: {{ row.opened.value ? 'Hide' : 'Show' }} details
        </a>

        <!-- Details -->
        <div v-if="row.opened.value" style="border: 1px solid #ccc">
          <div>opened: <pre>{{ row.opened.value }}</pre></div>
          <div>value: </div>
          <pre>{{ row.value }}</pre>
        </div>
      </div>
    </template>
  </div>
</template>

关键说明

  • 普通对象中的ref不会自动解包,必须通过.value访问其响应式值
  • 这种方式既避免了整个数组被reactive深度响应式处理,又保证了opened属性的响应性,切换功能就能正常运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:21:23