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

如何在Vue3中高效实现数组特定值的重置?

Vue3 数组内特定值高效重置的几种实现方法

你的现有方案通过structuredClone存储初始值并批量重置的思路是可行的,下面提供几种不同场景下的优化和替代方案:

方法1:基于原始数据源的直观重置

将原始数据作为独立常量存储,重置时通过ID匹配原始值,结构更清晰,便于扩展重置其他字段:

<script setup>
import { ref, watch } from 'vue';
const selected = ref(null)

// 原始数据源(常量,不修改)
const ORIGINAL_DATA = [
  { id: 1, label: 'A', value: 'A', name: 'Student A' },
  { id: 2, label: 'B', value: 'B', name: 'Student B' },
  { id: 3, label: 'C', value: 'C', name: 'Student C' }
]
const data = ref([...ORIGINAL_DATA])

watch(selected, (v) => {
  if (v === null) {
    // 匹配ID重置为原始值
    data.value.forEach(item => {
      const original = ORIGINAL_DATA.find(o => o.id === item.id)
      if (original) item.value = original.value
    })
  } else {
    data.value.forEach(item => item.value = v)
  }
})

const updateValue = (id, newValue) => {
  const item = data.value.find(item => item.id === id)
  if (item) item.value = newValue
}
</script>

<template>
  <div>
    <select v-model="selected">
      <option :value="null">Init Value</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>

    <template v-for="item in data" :key="item.id"> <!-- 用ID作为key,避免index的潜在问题 -->
      <div style="display:flex ; align-items: center;margin-bottom: 16px;">
        <div style="margin-right:16px;"> Name:{{ item.name }}</div>
        <select :value="item.value" @change="updateValue(item.id, $event.target.value)">
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
      </div>
    </template>
  </div>
</template>

方法2:响应式状态拆分(符合Vue设计思想)

通过计算属性拆分基础数据、全局选中状态、自定义修改状态,无需手动遍历修改数组,纯响应式推导:

<script setup>
import { ref, computed } from 'vue';
const globalSelected = ref(null)

// 基础数据
const BASE_DATA = [
  { id: 1, label: 'A', value: 'A', name: 'Student A' },
  { id: 2, label: 'B', value: 'B', name: 'Student B' },
  { id: 3, label: 'C', value: 'C', name: 'Student C' }
]
// 存储用户自定义修改的值
const customValues = ref({})

// 计算最终展示数据:自定义值 > 全局选中值 > 原始值
const data = computed(() => {
  return BASE_DATA.map(item => {
    const finalValue = customValues.value[item.id] ?? globalSelected.value ?? item.value
    return { ...item, value: finalValue }
  })
})

const updateValue = (id, newValue) => {
  customValues.value[id] = newValue
  // 修改单个值后清空全局选中,避免状态冲突
  if (globalSelected.value !== null) {
    globalSelected.value = null
  }
}
</script>

<template>
  <div>
    <select v-model="globalSelected">
      <option :value="null">Init Value</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>

    <template v-for="item in data" :key="item.id">
      <div style="display:flex ; align-items: center;margin-bottom: 16px;">
        <div style="margin-right:16px;"> Name:{{ item.name }}</div>
        <select :value="item.value" @change="updateValue(item.id, $event.target.value)">
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
      </div>
    </template>
  </div>
</template>

方法3:不可变数据模式(适合状态追踪场景)

如果需要追踪数据变化历史或配合状态管理库,可使用不可变数据模式,每次更新生成新数组:

原生Spread版本

<script setup>
import { ref, watch } from 'vue';
const selected = ref(null)

const ORIGINAL_DATA = [
  { id: 1, label: 'A', value: 'A', name: 'Student A' },
  { id: 2, label: 'B', value: 'B', name: 'Student B' },
  { id: 3, label: 'C', value: 'C', name: 'Student C' }
]
const data = ref([...ORIGINAL_DATA])

watch(selected, (v) => {
  if (v === null) {
    data.value = data.value.map(item => {
      const original = ORIGINAL_DATA.find(o => o.id === item.id)
      return original ? { ...item, value: original.value } : item
    })
  } else {
    data.value = data.value.map(item => ({ ...item, value: v }))
  }
})

const updateValue = (id, newValue) => {
  data.value = data.value.map(item => 
    item.id === id ? { ...item, value: newValue } : item
  )
}
</script>

<template>
  <div>
    <select v-model="selected">
      <option :value="null">Init Value</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>

    <template v-for="item in data" :key="item.id">
      <div style="display:flex ; align-items: center;margin-bottom: 16px;">
        <div style="margin-right:16px;"> Name:{{ item.name }}</div>
        <select :value="item.value" @change="updateValue(item.id, $event.target.value)">
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
      </div>
    </template>
  </div>
</template>

Immer简化版本

先安装依赖:npm install immer

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

const selected = ref(null)

const ORIGINAL_DATA = [
  { id: 1, label: 'A', value: 'A', name: 'Student A' },
  { id: 2, label: 'B', value: 'B', name: 'Student B' },
  { id: 3, label: 'C', value: 'C', name: 'Student C' }
]
const data = ref([...ORIGINAL_DATA])

watch(selected, (v) => {
  data.value = produce(data.value, draft => {
    if (v === null) {
      draft.forEach(item => {
        const original = ORIGINAL_DATA.find(o => o.id === item.id)
        if (original) item.value = original.value
      })
    } else {
      draft.forEach(item => item.value = v)
    }
  })
})

const updateValue = (id, newValue) => {
  data.value = produce(data.value, draft => {
    const item = draft.find(item => item.id === id)
    if (item) item.value = newValue
  })
}
</script>

<template>
  <div>
    <select v-model="selected">
      <option :value="null">Init Value</option>
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>

    <template v-for="item in data" :key="item.id">
      <div style="display:flex ; align-items: center;margin-bottom: 16px;">
        <div style="margin-right:16px;"> Name:{{ item.name }}</div>
        <select :value="item.value" @change="updateValue(item.id, $event.target.value)">
          <option value="A">A</option>
          <option value="B">B</option>
          <option value="C">C</option>
        </select>
      </div>
    </template>
  </div>
</template>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:37:03