
vue 组件内使用 ref([]) 存储多个字典对象时,若每次点击都“看似清空重置”,实际是组件被意外销毁重建导致响应式引用重初始化;需通过生命周期验证、状态提升或组件复用避免重复实例化。
vue 组件内使用 ref([]) 存储多个字典对象时,若每次点击都“看似清空重置”,实际是组件被意外销毁重建导致响应式引用重初始化;需通过生命周期验证、状态提升或组件复用避免重复实例化。
在 Vue 3 的 <script setup> 语法中,const QuizToSub = ref([]) 创建的是一个<strong>组件实例级的响应式引用。当组件被卸载(unmounted)后重新挂载(mounted),该 ref 会随组件实例一起被销毁并重建,从而重置为初始空数组 —— 这正是你观察到“字典被覆盖”或“历史数据消失”的根本原因,而非 .push() 操作本身有问题。</script>
? 验证组件是否被重复创建
首先确认问题根源:在组件中添加 Vue 2 风格的 created 钩子(Vue 3 仍支持 Options API 钩子,即使在 <script setup> 中也可混合使用):</script>
// 在 <script setup> 内部下方添加(注意:需配合 defineOptions)
import { defineOptions } from 'vue'
defineOptions({
created() {
console.log(`[Survey #${id}] 组件已创建,QuizToSub 当前长度:`, this.QuizToSub?.value?.length ?? 0)
}
})</script>
✅ 正确行为:仅页面首次加载时打印一次;
❌ 异常表现:每次切换题块(scroll to next section)都触发新日志 → 表明组件被反复销毁重建。
✅ 推荐解决方案(按优先级排序)
方案一:状态提升(推荐 ✅)
将 QuizToSub 状态上移至父组件,子组件仅接收并更新它:
<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
import Survey from './Survey.vue'
const QuizToSub = ref([])
const handleResponse = (response, question) => {
QuizToSub.value.push({ qst: question, rep: response })
}
</script><template><survey v-for="(q, idx) in quizList" :key="q.id" :quizdata="q" :id="idx" :on-response="handleResponse"></survey></template>
<!-- Survey.vue -->
<script setup>
const props = defineProps({
QuizData: { type: Object, required: true },
id: { type: Number, required: true }
})
const emit = defineEmits(['response'])
const scrollToNext = (response) => {
emit('response', response, props.QuizData.question)
const nextSection = document.getElementById(`${props.id + 2}`)
nextSection?.scrollIntoView({ behavior: 'smooth' })
}
</script>
✅ 优势:状态集中管理、组件可复用、符合 Vue 响应式设计原则;
⚠️ 注意:确保父组件中 quizList 不因响应式变化意外触发子组件全量重渲染(如使用 v-for 时 key 稳定)。
方案二:避免组件销毁(进阶 ✅)
若必须保留在子组件内维护状态,可通过 v-show 替代 v-if 控制显隐,或使用

