Vue3项目记录

一、Vue 绑定属性的核心问题

(一)核心问题

绑定属性时,即使绑定的值是常量 false,也需要使用 : 前缀。关键认知:: 的作用是区分字符串 vs JavaScript 值,而非 "固定值 vs 变量"。

(二)关键对比

1. 不用 :(HTML 属性)

ini 复制代码
<el-form hide-required-asterisk="false">
  • 浏览器解析结果:props.hideRequiredAsterisk = "false"(字符串类型)
  • JavaScript 中逻辑:非空字符串均为 truthy,if ("false") 会执行,最终等效于 true

2. 用 :(JavaScript 表达式)

ruby 复制代码
<el-form :hide-required-asterisk="false">
  • Vue 解析结果:props.hideRequiredAsterisk = false(布尔类型)
  • JavaScript 中逻辑:if (false) 不会执行,符合预期效果

(三)实际测试验证

代码写法 解析结果 是否正确
<el-form hide-required-asterisk="false"> 等效于 :hide-required-asterisk="'false'"
<el-form :hide-required-asterisk="'false'"> 等效于 :hide-required-asterisk="true"
<el-form :hide-required-asterisk="false"> 解析为布尔值 false

(四): 的真正作用

告诉 Vue:"把引号里的内容当作 JavaScript 代码执行,而非字符串"。

(五)完整使用示例

场景 1:传递字符串(无需 :

ini 复制代码
<el-input placeholder="请输入">
  • 解析结果:placeholder = "请输入"(字符串类型)

场景 2:传递数字(需要 :

ini 复制代码
<el-input :maxlength="100">
  • 解析结果:maxlength = 100(数字类型,非字符串 "100")

场景 3:传递布尔值(需要 :

ruby 复制代码
<el-form :hide-required-asterisk="false">
  • 解析结果:hideRequiredAsterisk = false(布尔类型)

场景 4:传递对象(需要 :

ini 复制代码
<el-form :model="{ name: 'test' }">
  • 解析结果:model = { name: 'test' }(对象类型)

场景 5:传递变量(需要 :

ruby 复制代码
<el-form :hide-required-asterisk="isReadOnly">
  • 解析结果:hideRequiredAsterisk = isReadOnly(变量对应的值)

(六)代码结论

ruby 复制代码
<el-form :hide-required-asterisk="false">
  • false 是固定值,此表述正确
  • 必须使用 :,原因是要传递布尔类型(JavaScript 值),而非字符串
  • 使用 : 的核心依据是值的类型,而非 "是否会变化"

(七)总结

: 的核心作用是区分 "字符串" 与 "JavaScript 代码执行结果",而非 "固定值 vs 变量"。本质:: 表示 "这是 JavaScript 代码,请执行它"。


二、computed/useMemo 触发差异(Vue3/React 响应式本质区别)

(一)核心问题

Vue3 中 computed 函数是否会在 "依赖更新" 和 "视图渲染" 时多次触发?为何与 React useMemo 行为不同?这一差异的本质是框架响应式设计理念的区别吗?

(二)核心结论

Vue3 computed 函数仅在依赖数据变化时重新执行,视图渲染时若依赖未变则复用缓存,不会额外触发;其与 React useMemo 的行为差异,核心是 Vue "响应式 getter 驱动" 与 React "声明式依赖数组驱动" 的设计理念不同,而非 "两次触发" 的差异。

(三)框架响应式本质差异(Vue3 vs React)

1. Vue3 Computed 工作原理

  • 核心定位:computed 是 "响应式的 getter",与响应式数据(ref/reactive)深度绑定。

  • 触发逻辑:

    1. 当依赖的响应式数据(如 snapshotData.value)发生变化时,computed 函数会自动重新执行。
    2. 模板中读取 {{ formatAmount }} 时,仅当依赖已变化,才会触发重新计算;依赖未变则直接复用缓存结果。
  • 代码示例:

javascript 复制代码
const formatAmount = computed(() => {
  console.log("snapshotData.value", snapshotData.value); // 仅依赖变化时打印
  return snapshotData.value ? `+${snapshotData.value.amount}` : "+0";
});

2. React useMemo 工作原理

  • 核心定位:useMemo 是 "声明式的缓存计算工具",依赖显式配置的依赖数组。

  • 触发逻辑:

    1. 仅在 "依赖数组中的值变化" 或 "组件首次渲染" 时,执行计算函数。
    2. JSX 中使用 {formatAmount} 仅为读取缓存值,无论视图如何渲染,只要依赖未变,都不会重新执行计算函数。
  • 代码示例:

javascript 复制代码
const formatAmount = useMemo(() => {
  console.log("snapshotData", snapshotData); // 仅依赖数组变化时打印
  return snapshotData ? `+${snapshotData.amount}` : "+0";
}, [snapshotData]); // 显式依赖数组

(四)关键特性对比表

特性 Vue3 Computed React useMemo
核心定位 响应式 getter 声明式缓存计算工具
触发时机 依赖响应式数据变化时 依赖数组变化 / 组件首次渲染时
视图使用时 依赖已变则重新计算,否则复用缓存 仅读取缓存值,不触发重新计算
依赖配置 自动追踪响应式依赖,无需手动配置 需显式声明依赖数组
内部打印行为 依赖变化时打印(与计算执行同步) 依赖数组变化时打印(仅执行一次)

(五)"打印多次" 的真实原因

并非 "依赖更新 + 视图渲染" 两次触发,而是:

  1. 初始渲染时,依赖数据(如 snapshotData.value)为初始值(如 null),computed 执行一次并打印。
  2. 业务操作后(如提交表单),依赖数据更新(如变为 { amount: 100 }),computed 再次执行并打印。
  3. 两次打印均是 "依赖变化" 导致的计算执行,与视图渲染本身无直接关联。

(六)优化建议(避免不必要的打印 / 计算)

  1. 调试场景:使用 Vue3 的 watchEffect 专门监听数据变化,替代 computed 内打印。
javascript 复制代码
watchEffect(() => {
  console.log("snapshotData 变化了:", snapshotData.value); // 仅监听变化打印
});
  1. 业务场景:在数据更新的源头(如提交函数、赋值逻辑)打印,明确数据变更时机。
ini 复制代码
const handleSubmit = () => {
  snapshotData.value = { amount: formData.amount };
  console.log("快照数据更新:", snapshotData.value); // 源头打印更精准
};
  1. 生产环境:移除 computed 内的调试打印,避免冗余执行。

(七)总结

  • 差异本质:Vue3 是 "响应式驱动",computed 自动追踪依赖、依赖变则计算;React 是 "声明式驱动",useMemo 仅按依赖数组变化执行计算,二者是框架设计理念的差异,无优劣之分。
  • 关键认知:Vue3 computed 不会因 "单纯视图渲染" 额外触发,多次执行均源于依赖变化;这一特性是 Vue 响应式系统的体现,而非设计缺陷。

三、Vue3 reactive

(一)核心定义

reactive 是 Vue 3 Composition API 中用来创建响应式对象的核心函数,作用是让数据具备 "变化自动触发视图更新" 的特性。

(二)基本概念

1. 什么是响应式?

响应式意味着:当数据变化时,使用这些数据的地方(如模板、计算属性等)会自动更新

php 复制代码
import { reactive } from "vue";

// 创建响应式对象
const state = reactive({
  count: 0,
  message: "Hello"
});

// 数据修改后,依赖该数据的视图自动更新
state.count++;

2. 实际代码应用(金额调整组件)

javascript 复制代码
const formData = reactive({
  adjustType: 1,        // 调整类型(+/-)
  amount: undefined,    // 金额
  remark: ""           // 说明
});
  • 表单绑定 v-model="formData.amount" 时,用户输入会自动同步到 formData.amount
  • 确认弹窗中 {{ formatAmount }} 依赖 formData,会随数据变化自动更新。

(三)响应式工作原理

xml 复制代码
<template>
  <!-- 1. 显示数据:依赖 formData.amount -->
  <div>金额:{{ formData.amount }}</div>
  
  <!-- 2. 修改数据:v-model 绑定响应式属性 -->
  <input v-model="formData.amount" />
</template>

<script setup>
import { reactive } from "vue";

const formData = reactive({
  amount: 0
});

// 3. 输入框值改变 → formData.amount 自动更新 → 模板显示同步更新
</script>

(四)reactive vs 普通对象

类型 代码示例 响应式效果
普通对象 const formData = { amount: 0 }; formData.amount = 300; ❌ 模板不会更新
响应式对象 const formData = reactive({ amount: 0 }); formData.amount = 300; ✅ 模板自动更新

(五)reactive 的核心特点

  1. 仅支持对象类型

    • 支持:对象、数组、Map 等复杂类型(reactive({ count: 0 })reactive([1,2,3]))。
    • 不支持:数字、字符串等基本类型(reactive(0) 无效,需用 ref)。
  2. 深层响应式嵌套对象的属性同样具备响应式,修改任意层级属性都会触发更新:

php 复制代码
const state = reactive({
  user: {
    name: "张三",
    address: { city: "上海" }
  }
});
state.user.address.city = "北京"; // ✅ 触发响应式更新
  1. 直接访问属性 无需 .value,直接读写属性即可:
ini 复制代码
const formData = reactive({ amount: 300 });
console.log(formData.amount); // 300(直接访问)
formData.amount = 500;        // 直接赋值修改

(六)reactive vs ref 对比

特性 reactive ref
适用类型 对象、数组等复杂类型 任何类型(基本类型、对象)
访问方式 直接访问:state.count 脚本中需 .valuecount.value
模板中使用 {{ state.count }} {{ count }}(自动解包,无需 .value
解构特性 ❌ 直接解构会失去响应式 ✅ 配合 toRefs 可保持响应式

代码示例对比

ini 复制代码
import { reactive, ref } from "vue";

// reactive 用法(对象)
const formData = reactive({ amount: 0 });
formData.amount = 300;

// ref 用法(基本类型)
const count = ref(0);
count.value = 300;

(七)实际应用场景

  1. 表单数据管理(如金额调整组件)
php 复制代码
const formData = reactive({ adjustType: 1, amount: undefined, remark: "" });
  1. 组件状态管理
php 复制代码
const state = reactive({ user: null, isLoading: false, error: null });
state.isLoading = true; // 状态变化触发视图更新
  1. 列表数据处理
php 复制代码
const todoList = reactive({ items: [], filter: "all" });
todoList.items.push({ id: 1, text: "学习 Vue 3" }); // 列表更新自动渲染

(八)注意事项(避免失去响应式)

  1. 禁止直接解构

    • 错误:const { count } = reactive({ count: 0 }); count++(失去响应式)。
    • 正确:使用 toRefs 保持响应式:
ini 复制代码
import { toRefs } from "vue";
const state = reactive({ count: 0 });
const { count } = toRefs(state);
count.value++; // ✅ 正常触发更新
  1. 不能整体替换对象

    • 错误:let state = reactive({ count: 0 }); state = reactive({ count: 100 })(原响应式关联失效)。
    • 正确:修改属性或使用 Object.assign
ini 复制代码
state.count = 100; // 直接修改属性
Object.assign(state, { count: 100 }); // 合并更新

(九)总结

reactive 的核心价值是为对象类型数据添加 "自动响应式" 能力:

  1. ✅ 数据变化 → 视图自动同步,无需手动操作 DOM。
  2. ✅ 适配表单、状态、列表等多种业务场景。
  3. ✅ 深层响应式设计,嵌套对象无需额外处理。
  4. ⚠️ 注意避免 "解构" 和 "整体替换",防止失去响应式。
  5. ⚠️ 基本类型需用 refreactive 仅适用于复杂对象类型。
相关推荐
yannick_liu1 小时前
wangeditor自定义扩展设置图片宽高
前端
yigenhuochai2 小时前
Trae Solo 开发体验:从零到完整考试备考平台的奇妙之旅
前端·trae
夏目友人爱吃豆腐2 小时前
uniapp源码解析(Vue3/Vite版)
前端·vue.js·uni-app
JarvanMo2 小时前
Dart 3.10中的新的lint规则
前端
爱心发电丶2 小时前
基于UniappX开发电销APP,实现通话录音上传、通时通次
前端
sxjk19872 小时前
华为IMS系统主要接口备忘
运维·服务器·前端·核心网
T***u3332 小时前
前端Server Components性能分析 Server Components架构原理
前端
Q***f6352 小时前
前端动画性能优化,60fps实现技巧
前端
艾莉丝努力练剑2 小时前
【自动化测试实战篇】Web自动化测试实战:从用例编写到报告生成
前端·人工智能·爬虫·python·pycharm·自动化·测试