惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
L
LangChain Blog
Jina AI
Jina AI
爱范儿
爱范儿
C
Check Point Blog
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
月光博客
月光博客
GbyAI
GbyAI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Stack Overflow Blog
Stack Overflow Blog
V
V2EX
A
About on SuperTechFans
有赞技术团队
有赞技术团队
Microsoft Azure Blog
Microsoft Azure Blog
The GitHub Blog
The GitHub Blog
博客园 - Franky
Apple Machine Learning Research
Apple Machine Learning Research
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题

博客园 - VipSoft

FastAPI 全局 HTTP 异常处理器 + 统一响应封装 SpringBoot 心跳日志不记录 access.log Qdrant Linux 安装(非Docker) LangChain — RAG 知识库(实操) LangChain — RAG 构建知识库(理论) LangChain — RAG 构建知识库(实操) Python PyCharm 运行,取不到 .env 文件中的值 Qdrant 安装(Windows) LangChain — RAG 构建知识库 Python 项目简单部署(Linux) MinerU - 将非结构化文档(PDF、图片、Office 文件等)转换为机器可读的 Markdown 和 JSON LangChain 入门 服务端部署-FastAPI LangChain 入门 LangSmith LangChain 入门 实战 - 食谱推荐 LangChain 入门 Memory 会话记忆 LangChain 入门 Tools 工具 LangChain 入门 Tools 工具 LangChain 入门 Prompts 提示词 LangChain 入门 Message 消息 LangChain 入门 Model 的初始化和调用 LangChain 入门 Agent 的基本运行机制 AI 0基础学习,名词解析 LangChain 和 LangGraph AI大模型知识体系 Dify — Workflow - 数据可视化 Dify — 连接MySQL配置 Dify — Chatflow - 数据库智能查询 Dify — Chatflow - 文档知识库 Dify — Agent 智能体 高安全券码、注册码生成
Vue ref reactive
VipSoft · 2026-01-09 · via 博客园 - VipSoft

问题1

const allotVO = reactive<DeviceInfoVO[]>([]);
allotVO = [];
不能对 allotVO  进行初始化,怎么能把 allotVO 里面的数据给清掉。

直接修改数组长度(推荐)

// 方法1 - 最简洁
allotVO.length = 0;

// 或者方法2 - 更明确
allotVO.splice(0);

问题2

const selectedItems = ref<DeviceInfoVO[]>([]);

const allotVO = ref<DeviceInfoVO[]>([]);

怎么把 selectedItems 赋值给 allotVO,可以直接等吗。
为什么不能直接等?

// 解构赋值(推荐)
allotVO.value = [...selectedItems.value];

// ❌ 错误做法 - 会共享引用
allotVO.value = selectedItems.value;

// 这样修改 allotVO 也会影响 selectedItems
allotVO.value.push(someItem); // selectedItems 也会被修改!

深层次对象拷贝

// 浅拷贝(对于一层结构足够)
allotVO.value = [...selectedItems.value];

// 深拷贝(如果对象有嵌套)
import { cloneDeep } from 'lodash-es';
allotVO.value = cloneDeep(selectedItems.value);

// 或者使用 JSON(有局限性,不能处理函数、循环引用等)
allotVO.value = JSON.parse(JSON.stringify(selectedItems.value));

赋值问题

const selectedItems = ref<DeviceInfoVO[]>([]);

const allotVO = reactive<DeviceInfoVO[]>([]);

Object.assign(allotVO, { ...selectedItems.value });
我第一次选10条,第二次选2条。最后  allotVO 还是 10条

原因分析

// 第一次:selectedItems 有10条
selectedItems.value = [item1, item2, ..., item10]; // 10条
Object.assign(allotVO, { ...selectedItems.value });
// 结果:allotVO 变成 {0:item1, 1:item2, ..., 9:item9},length=10

// 第二次:selectedItems 有2条
selectedItems.value = [itemA, itemB]; // 2条
Object.assign(allotVO, { ...selectedItems.value });
// 结果:allotVO 变成 {0:itemA, 1:itemB, 2:item3, ..., 9:item9}
// 因为 Object.assign 只覆盖已有的属性,不会删除多余的属性!
// 所以 allotVO.length 仍然是 10,后面8个是旧数据

正确的解决方案:

方案1:使用 splice(最推荐)

// 清空并替换
allotVO.splice(0, allotVO.length, ...selectedItems.value);

方案2:先清空再push

allotVO.length = 0;
allotVO.push(...selectedItems.value);

方案3:如果需要用 Object.assign

// 必须先清空所有属性
allotVO.splice(0); // 清空数组
// 然后再赋值
selectedItems.value.forEach((item, index) => {
  allotVO[index] = item;
});

总结:

  • Object.assign 只是合并属性,不会删除多余的属性
  • 对于数组操作,应该使用数组的原生方法
  • 使用 splice 可以确保完全替换数组内容

reactive 的优缺点:

优点:

  1. 直接访问:不需要 .value
  2. 更直观:对于对象/数组,代码更简洁
  3. 性能稍好:Vue 内部优化

缺点:

  1. 不能解构:解构会失去响应性
  2. 类型限制:只能是对象类型(对象、数组、Map、Set)
  3. 替换麻烦:不能直接赋值 = [],需要用 splice

ref 的优缺点:

优点:

  1. 更灵活:可以存储任何类型的值
  2. 直接赋值:可以 allotVO.value = []
  3. 解构方便:在组合式函数中更容易返回
  4. 类型支持更好:TypeScript 类型推断更准确

缺点:

  1. 需要 .value:访问和修改都要加 .value
  2. 代码稍繁琐:多了 .value

具体建议:

使用 reactive 的场景:

// 场景1:作为组件内部状态,不经常重新赋值
const formState = reactive({
  name: '',
  age: 0,
  list: [] as DeviceInfoVO[]
});

// 场景2:嵌套在对象中的数组
const state = reactive({
  allotList: [] as DeviceInfoVO[],
  selectedList: [] as DeviceInfoVO[],
  loading: false
});
// 使用:state.allotList.push(item)

使用 ref 的场景:

// 场景1:需要频繁重新赋值的数组
const allotVO = ref<DeviceInfoVO[]>([]);
// 清空:allotVO.value = []
// 赋值:allotVO.value = [...selectedItems.value]

// 场景2:在组合式函数中返回
function useDeviceList() {
  const list = ref<DeviceInfoVO[]>([]);
  
  const clear = () => {
    list.value = []; // 直接赋值很方便
  };
  
  return { list, clear }; // 返回 ref 更方便
}

// 场景3:需要模板自动解包
// 模板中可以直接使用 allotVO 而不是 allotVO.value

针对你的情况:

如果你需要:

  • 频繁清空和重新赋值 → 用 ref
  • 主要是 push/pop/splice 操作 → 用 reactive 也可以

推荐方案:

// 如果经常需要 allotVO = [] 或 allotVO = newArray
const allotVO = ref<DeviceInfoVO[]>([]); // ✅ 推荐

// 如果主要是数组方法操作
const allotVO = reactive<DeviceInfoVO[]>([]); // 也可以

// 或者结合使用(最灵活)
const state = reactive({
  allotVO: [] as DeviceInfoVO[],
  // 其他状态...
});

// 清空和赋值可以用辅助函数
const clearAllotVO = () => {
  state.allotVO.splice(0);
};

const setAllotVO = (items: DeviceInfoVO[]) => {
  state.allotVO.splice(0, state.allotVO.length, ...items);
};

结论:

对于你的 allotVO,我推荐使用 ref,因为:

  1. 你明显需要清空和重新赋值操作
  2. refallotVO.value = []reactivesplice 更直观
  3. 现代 Vue 3 项目中更倾向于使用 ref
  4. 组合式 API 中 ref 更通用
// 最终建议
const selectedItems = ref<DeviceInfoVO[]>([]);
const allotVO = ref<DeviceInfoVO[]>([]); // 改用 ref

// 使用
allotVO.value = [...selectedItems.value]; // 赋值
allotVO.value = []; // 清空
allotVO.value.push(item); // 添加
allotVO.value = [...selectedItems.value];
      // 根据条件遍历赋值
      allotVO.forEach((item) => {
        // 示例:根据索引或其他逻辑赋值
        item.HospitalId = dept.HospitalId;
        item.HospitalName = dept.HospitalName;
        item.HospitalShortName = dept.HospitalShortName;
        item.DeptId = dept.Id;
        item.DeptName = dept.DeptName;
      }); 
是不是得用 allotVO.value.forEach

是的,必须用 allotVO.value.forEach

因为 allotVOref,所以访问它的值需要使用 .value

// ✅ 正确
allotVO.value.forEach((item) => {
  item.HospitalId = dept.HospitalId;
  item.HospitalName = dept.HospitalName;
  item.HospitalShortName = dept.HospitalShortName;
  item.DeptId = dept.Id;
  item.DeptName = dept.DeptName;
});

// ❌ 错误:allotVO 是 ref,没有 forEach 方法
allotVO.forEach((item) => { ... });

完整正确代码:

// 定义 ref
const allotVO = ref<DeviceInfoVO[]>([]);

// 赋值
allotVO.value = [...selectedItems.value];

// 遍历修改每一项
allotVO.value.forEach((item) => {
  item.HospitalId = dept.HospitalId;
  item.HospitalName = dept.HospitalName;
  item.HospitalShortName = dept.HospitalShortName;
  item.DeptId = dept.Id;
  item.DeptName = dept.DeptName;
});

如果你用的是 reactive:

// 如果用 reactive(不需要 .value)
const allotVO = reactive<DeviceInfoVO[]>([]);

// 赋值(需要 splice 而不是直接 =)
allotVO.splice(0, allotVO.length, ...selectedItems.value);

// 遍历(直接使用 allotVO,没有 .value)
allotVO.forEach((item) => {
  item.HospitalId = dept.HospitalId;
  // ... 其他赋值
});

简化建议:

你可以考虑使用 map 一步完成赋值和修改:

// 一步完成:复制数组并修改每一项
allotVO.value = selectedItems.value.map(item => ({
  ...item, // 保留原有属性
  HospitalId: dept.HospitalId,
  HospitalName: dept.HospitalName,
  HospitalShortName: dept.HospitalShortName,
  DeptId: dept.Id,
  DeptName: dept.DeptName
}));

这样更简洁,而且不会修改原始的 selectedItems.value

总结:

  • ref 需要 .valueallotVO.value.forEach
  • reactive 不需要 .valueallotVO.forEach
  • 推荐用 map 一步完成复制和修改