Skip to content

Vue3 入门(一) ​

本页对应 Vue3 入门,共 8 段视频,约 1 小时 18 分。

学习目标 ​

  • 能够说明 Vue3 的采用场景与组合式 API 的优势,并对比选项式 API 与组合式 API 在代码组织上的差异。
  • 能够使用 create-vue 创建 Vue3 项目,完成依赖安装与启动,并识别 package.json、vite.config.js、main.js、App.vue、index.html 等关键文件的作用。
  • 能够使用 <script setup> 编写组合式 API,并说明 setup 的执行时机、模板使用数据与方法的方式以及 this 的指向。
  • 能够使用 reactive 和 ref 创建响应式数据,正确区分二者的参数类型与访问/修改方式,并在模板与脚本中正确使用 ref 的 .value。
  • 能够使用 computed 基于响应式数据派生新值,验证依赖变化后的重新计算,并避免副作用和直接修改计算属性。
  • 能够使用 watch 侦听单个或多个数据源,配置 immediate 与 deep,并通过返回特定属性的方式实现精确侦听。

知识点 ​

为什么要学 Vue3 ​

为什么需要:转写稿先解决“刚学完 Vue2,为什么还要切 Vue3”的困惑:招聘岗位已明确提出 Vue3 要求,官方也把 Vue3 作为默认版本发布,执行 npm install vue 默认得到 Vue3,文档主推的也是 Vue3。
怎么想:Vue3 是现在也是将来的主流版本;同时 Vue3 支持 Vue2 绝大多数语法,过渡成本并没有想象中高。
怎么做:先建立“积极拥抱 Vue3”的认知,再从与日常开发最相关的组合式 API 入手体验。
易错点:不要把 Vue2 与 Vue3 对立起来。转写稿明确说,在 Vue3 环境里写 Vue2 选项式 API 也可以运行。

组合式 API 初体验 ​

为什么需要:同样一个计数器,Vue2 选项式 API 把数据和修改方法分散在不同选项里,功能一多就不利于集中维护。
怎么想:Vue3 的组合式 API 强调“同一功能的数据和方法放在一起”,形成集中式维护风格。
怎么做:转写稿用同一计数器对比两种写法。Vue2 写法如下:

js
export default {
  data() {
    return { count: 0 }
  },
  methods: {
    addCount() {
      this.count++
    }
  }
}

Vue3 则在 setup 中写:

js
import { ref } from 'vue'
export default {
  setup() {
    const count = ref(0)
    const addCount = () => {
      count.value++
    }
    return { count, addCount }
  }
}

易错点:setup 中不再通过 this 访问组件实例,打印 this 得到的是 undefined;ref 在脚本中访问和修改要加 .value。

用 create-vue 创建项目 ​

为什么需要:Vue2 常用 vue-cli,底层是 webpack;Vue3 的新脚手架是 create-vue,底层切换为 Vite。
怎么想:先确认 Node 版本大于 16.0,再执行创建命令;创建时按项目需要选择 TS、Router、Pinia、ESLint 等选项。
怎么做:转写稿中的命令是:

bash
node -v
npm create vue@latest

进入项目后安装依赖并运行:

bash
npm install
npm run dev

易错点:转写稿里“waitweight”应纠正为 Vite,“create view”应纠正为 create-vue;创建选项里若想选 ESLint,需要切换到 yes 再回车。

熟悉项目目录和关键文件 ​

为什么需要:新项目要先知道入口、配置和根组件在哪里,否则后续调试没有方向。
怎么想:先看包文件确认依赖,再看 vite.config.js 确认构建配置,最后看 src/main.js 和根组件。
怎么做:转写稿指出,main.js 中用 createApp 创建应用实例,再挂载到 #app:

js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

根组件中 script setup 是组合式 API 的开关;模板不再要求唯一根元素。
易错点:createApp 与 Vue2 的 new Vue 作用类似,但写法不同;vite.config.js 是项目配置文件,不是业务代码。

setup 入口 ​

为什么需要:组合式 API 是一系列函数,需要固定书写位置,setup 就是入口。
怎么想:转写稿通过打印验证:setup 会自动执行,并且早于 beforeCreate。
怎么做:普通写法中,变量和方法必须用对象 return 出去,模板才能使用;更常用的是语法糖:

vue
<script setup>
import { ref } from 'vue'
const message = ref('hello')
const logMessage = () => console.log(message.value)
</script>

易错点:普通 setup 忘记 return,模板拿不到数据;script setup 中不需要 export default、不需要再写 setup、也不需要手动 return。

reactive 与 ref ​

为什么需要:Vue2 用 data 生成响应式数据;Vue3 组合式 API 用 reactive、ref 生成。
怎么想:reactive 接收对象类型参数,返回响应式对象;ref 既支持简单类型也支持对象类型,但脚本中要通过 .value 访问。
怎么做:

js
import { reactive, ref } from 'vue'
const state = reactive({ count: 0 })
const count = ref(0)

模板中 ref 可直接写 count,脚本中修改写 count.value++。
易错点:reactive 不能处理简单类型;ref 忘记 .value 会改不到响应式数据。转写稿建议实际开发优先用 ref。

computed ​

为什么需要:基于现有响应式数据计算新数据,依赖变化时自动重新计算。
怎么想:思想与 Vue2 一致,只是改为函数调用。
怎么做:

js
import { computed, ref } from 'vue'
const list = ref([1,2,3,4,5,6,7,8])
const computedList = computed(() => {
  return list.value.filter(item => item > 2)
})

易错点:计算属性中不应有副作用,如发请求、改 DOM;默认只读,不要直接修改计算属性值。

watch 基本使用与 immediate ​

为什么需要:需要监听数据变化后执行回调,例如输入关键词变化后请求后端。
怎么想:watch 第一个参数是要侦听的响应式数据,第二个是回调;ref 作为第一个参数不需要加 .value。
怎么做:

js
import { ref, watch } from 'vue'
const count = ref(0)
watch(count, (newValue, oldValue) => {
  console.log(newValue, oldValue)
}, { immediate: true })

侦听多个数据时,第一个参数写成数组,回调的新值、老值也对应为数组。
易错点:immediate 要放在第三个对象参数里;多个数据侦听时新值与老值顺序要对应。

watch 深度侦听与精确侦听 ​

为什么需要:watch 侦听对象时默认是浅层侦听,直接改嵌套属性不会触发回调。
怎么想:开启 deep 可以递归侦听,但有性能损耗;若只关心某个属性,应使用精确侦听。
怎么做:精确侦听写法是第一个参数传函数并 return 目标属性:

js
watch(() => state.age, () => {
  console.log('age变化了')
})

易错点:不要一上来就开 deep;转写稿建议绝大多数情况下尽量不开启 deep,优先精确侦听。

从招聘与官方默认版本看:为什么现在要体验 Vue3 ​

为什么需要:转写稿提到,很多招聘岗位已经明确要求 Vue3;同时官方已把 Vue3 作为默认版本发布,执行 npm install vue 拉到的就是 Vue3,官方文档也主推 Vue3。学习 Vue3 不是“另起炉灶”,而是顺着现有 Vue2 知识升级。

怎么想:先不急着铺开所有新特性,本节只抓一个每天都会写、最影响开发体验的点——组合式 API。用熟悉的 Counter 案例做 A/B 对比:先写 Vue2 的选项式 API,再写 Vue3 的组合式 API。

怎么做:在已经搭好的 Vue3 开发环境里,先保留 Vue2 写法跑通,再替换成组合式写法。转写稿特别说明:Vue3 为了从 Vue2 平滑过渡,支持 Vue2 绝大多数语法,所以“在 Vue3 环境里写 Vue2 代码”也能运行。

易错点:不要把“能在 Vue3 里写 Vue2 语法”误解成“组合式 API 就是选项式 API”。两者是不同组织方式;转写稿里的“vivo3”应写作 Vue3,“set up”应写作 setup。

先写选项式 API 的 Counter:理解旧写法 ​

vue
<script>
export default {
  data(){
    return {
      count:0
    }
  },
  methods:{
    addCount(){
      this.count++
    }
  }
}
</script>

为什么需要:这是大家熟悉的 Vue2 选项式 API。先写它,是为了给后面的对比建立参照:数据放在 data,方法放在 methods。

怎么想:同一个计数功能被拆到不同选项里。转写稿把它概括为“分散式维护”:数据 count 在一处,修改它的 addCount 在另一处。

怎么做:data 返回 count: 0;methods 里写 addCount,通过 this.count++ 自增;模板中用插值显示 count,用事件绑定触发 addCount。转写稿的调试结果是:点击按钮,数字正常自增。

易错点:选项式 API 里访问数据要借助 this;转写稿中“rase/ra”这类同音转写应纠正为 this。另外,这段代码虽然写在 Vue3 项目里能跑,但它不是本节要体验的组合式 API。

再写组合式 API 的 Counter:用 ref 和 script setup ​

vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = ()=> count.value++
</script>

为什么需要:组合式 API 允许用函数调用的方式组织组件逻辑。转写稿说,script setup 像一个“开关”,写在 script 标签上以后,内部就可以写组合式 API。

怎么想:Counter 的需求没变:需要一个响应式数据 count,还需要一个修改它的方法 addCount。变化的是组织方式:同一功能的数据和方法放在一起。

怎么做:从 vue 导入 ref;用 const count = ref(0) 生成响应式数据;用箭头函数写 addCount,在脚本中通过 count.value++ 修改;模板中直接使用 count,事件绑定 addCount。转写稿的调试结果是:点击后同样能自增,效果与选项式写法一致。

易错点:转写稿里的“re”应纠正为 ref。ref 生成的响应式数据在脚本区域访问或修改时要加 .value,模板中直接写变量名即可;script setup 中不再写 export default,也不需要手动 return,这些是语法糖带来的简化。转写稿还提醒:setup 里打印 this 得到的是 undefined,不要沿用选项式 API 的 this.count 思路。

对比两种写法:代码量变少与集中式维护 ​

为什么需要:只看“能跑”不够,还要看写法带来的维护差异。转写稿给出的两个特点是:代码量变少;分散式维护变成集中式维护。

怎么想:选项式 API 按“数据、方法、计算属性”等选项分块;组合式 API 按“功能”聚合。Counter 很小,差异还不明显;功能一多,集中式组织更容易把一件事的相关代码放在一起看。

怎么做:对照两段代码:左边选项式 API 需要 data、methods、this;右边组合式 API 只保留 ref、变量和函数。转写稿还通过官方在线编译工具说明:script setup 是语法糖,编译后仍会回到 setup 和 return 的复杂形态,底层并不是“魔法”。

易错点:不要只记“代码少”。真正要理解的是组织方式变化;也不要把 script setup 当成新生命周期,它只是组合式 API 的书写入口和语法糖。

调试与验证:从点击自增看响应式是否生效 ​

为什么需要:组合式 API 的写法变了,必须用实际点击验证响应式是否生效,而不是只看代码像不像。

怎么想:先跑通最小闭环:显示初始值 0 → 点击按钮 → 数字加 1。转写稿的验证过程就是不断点击,观察视图是否更新。

怎么做:确认 ref 已导入;确认 addCount 中写的是 count.value++;确认模板事件绑定到了 addCount。如果点击无变化,优先检查是否漏了 .value、是否误用了 this、是否把普通值当成了响应式数据。

易错点:转写稿中“奥迪Y”应纠正为 undefined;“vi/Vue”等同音字要统一为 Vue。组合式 API 的入口是 setup,脚本中改 ref 要 .value,模板中不用 .value,这是本节最值得先记住的边界。

为什么现在要学 Vue3 ​

Vue3更多优势示意图

先解决一个很现实的问题:我们已经学了较长时间的 Vue2,为什么还要切到 Vue3?转写稿里给了两个判断依据。第一,去招聘网站以“Vue3”为关键词搜索,会看到不少岗位已经明确要求 Vue3;不会 Vue3,可能错失机会。第二,看官方态度:Vue 官方已经把 Vue3 作为默认版本发布,执行 npm install vue 安装到本地的是 Vue3 版本,官方文档主推的也是 Vue3。也就是说,Vue3 是现在也是将来的主流版本。

怎么想:学习 Vue3 不是把 Vue2 全部推翻,而是先理解它带来的新写法,再通过对比体会好处。本节只聚焦一个每天都会写的点——组合式 API。

怎么做:用一个计数器案例,分别用 Vue2 的选项式 API 和 Vue3 的组合式 API 实现,再对比代码组织方式。

易错点:不要误以为学了 Vue3 就不能写 Vue2 语法。转写稿明确说,Vue3 为了从 Vue2 顺利过渡,支持 Vue2 里绝大多数语法,甚至可以继续用熟悉的 Vue2 语法写 Vue3 代码。

从计数器看组合式API:先写 Vue2 版本 ​

为什么需要:计数器虽小,但能同时展示“响应式数据、修改方法、模板绑定”三件事,最适合对比两种 API 风格。

怎么想:Vue2 的选项式 API 是“按选项分块”:数据放 data,方法放 methods,模板里绑定事件和插值。

怎么做:转写稿中的 Vue2 写法可还原为:

vue
<template>
  <button @click="addCount">{{ count }}</button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    addCount() {
      this.count++
    }
  }
}
</script>

运行后点击按钮,数字从 0 开始自增。转写稿中讲课时也验证了:点一下按钮,右侧结果正常变化,说明 Vue2 写法在当前 Vue3 环境里仍然可以运行。

易错点:Vue2 写法里修改数据要通过 this.count;不要把它和后面组合式 API 里 count.value 的写法混在一起。

用组合式API重写计数器 ​

为什么需要:组合式 API 是 Vue3 新引入的写法,需要先知道它写在哪里、数据怎么变成响应式、方法怎么定义。

怎么想:开发思想不变:仍然需要一个响应式数据 count,仍然需要一个自增方法。变化的是写法:在 <script setup> 中写组合式 API。

怎么做:从 Vue 中导入 ref,用 ref(0) 生成响应式数据;在脚本中修改时用 count.value++;模板中直接使用 count。

vue
<template>
  <button @click="addCount">{{ count }}</button>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)

function addCount() {
  count.value++
}
</script>

转写稿中的调试过程是:先注释掉 Vue2 代码,在上面写 <script setup>,导入 ref,执行 ref(0),再写自增方法,最后回到页面点击按钮。结果和 Vue2 版本一样,仍然可以自增,效果没有发生变化。

易错点:ref 生成的响应式数据在脚本区域访问或修改时要加 .value;模板中直接写变量名即可。初学时最容易在脚本里漏掉 .value。

组合式API带来的维护方式变化 ​

为什么需要:两种写法都能实现功能,真正的差别在代码组织和后续维护。

怎么想:Vue2 的选项式 API 中,同一个功能的数据和方法可能被分到 data、methods 等不同选项里,转写稿称之为“分散式维护风格”;Vue3 的组合式 API 把同一个功能相关的数据和方法放在一起,转写稿称之为“集中式维护风格”。

怎么做:写功能时先围绕业务点组织代码:这个功能需要哪些响应式数据、哪些方法,就把它们放在同一段逻辑里。对比两版计数器会发现,组合式 API 版本肉眼可见地代码量更少,功能相关代码更集中。

易错点:不要只把“代码少”当成唯一优势。更关键的是功能代码集中,后续阅读和修改时更容易定位。

Vue3的其他优势与迁移态度 ​

转写稿还列出几类优势,不需要在本节全部展开,但要知道它们存在:

  1. 维护性:除了组合式 API,还提供更好的 TypeScript 支持。
  2. 速度:重写算法、增强模板编译、提高组件初始化性能。
  3. 体积:引入良好的 Tree-shaking 支持,支持按需引入,最终打出的包更小。
  4. 响应式:Vue2 中动态给对象添加属性可能不是响应式的;Vue3 底层切换到 Proxy 后,这类问题不再是问题。

怎么想:本节先用计数器体验组合式 API,其他优势先建立整体印象,后续再逐步学习。

怎么做:现阶段先接受“Vue3 支持 Vue2 大多数语法”的迁移态度,同时开始练习组合式 API 写法。

易错点:不要把 Vue3 的优势理解成“Vue2 完全不能用”。转写稿强调,Vue3 做了很多过渡努力,你甚至可以先继续使用熟悉的 Vue2 语法写 Vue3 代码;但既然 Vue3 是主流版本,就应积极拥抱 Vue3,逐步切换到组合式 API。

课件图示 ​

课件第20页:计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法 核

课件第7页:使用create-vue创建项目 1. 前提环境条件 已安装 16.0 或更高版

课件第18页:总结 总结 1. reactive和ref函数的共同作用是什么 ? 用函数调用的

课件第9页:项目目录和关键文件 关键文件: 1. vite.config.js - 项目的配

课件第14页:总结 总结 1. setup选项的执行时机? beforeCreate钩子之前

课件第32页:Vue3的生命周期API (选项式 VS 组合式) 选项式API 组合式API

课件第35页:总结 总结 1. 组合式API中生命周期函数的格式是什么? on + 生命周期名

课件第4页:Vue3更多的优势 ue 更快的速度 更优的数据响应式 更容易维护 更小的体积

代码示例 ​

示例 1:选项式 API 实现 Counter(Vue2 风格,在 Vue3 中依然可运行)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Vue3 - 选项式API 写计数器</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
  <div id="app">
    <button @click="addCount">{{ count }}</button>
  </div>

  <script>
    const { createApp } = Vue

    createApp({
      data() {
        return {
          count: 0
        }
      },
      methods: {
        addCount() {
          this.count++
        }
      }
    }).mount('#app')
  </script>
</body>
</html>

要点解释:

  • createApp({...}) 替代了 Vue2 的 new Vue({...}),作用同样是创建应用实例对象;.mount('#app') 把它挂载到 index.html 中 id 为 app 的节点上。
  • data() 返回的 count 是响应式数据,methods 里的 addCount 通过 this.count++ 修改它,视图随之更新。
  • 易错点一:data 必须是函数并返回对象,不能直接写成对象,否则多个实例会共享同一份数据。
  • 易错点二:选项式 API 的特点是「分散式维护」——数据在 data 里、方法在 methods 里,同一个功能的代码被拆成两块,这正是后面组合式 API 要解决的问题。
  • 补充:Vue3 为了从 Vue2 平滑过渡,支持 Vue2 的绝大多数语法,所以在 Vue3 环境下写选项式 API 完全没问题。

示例 2:组合式 API 实现同一个 Counter(ref + setup)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Vue3 - 组合式API 写计数器</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
  <div id="app">
    <button @click="addCount">{{ count }}</button>
  </div>

  <script>
    const { createApp, ref } = Vue

    createApp({
      setup() {
        // 1. 用 ref 生成响应式数据
        const count = ref(0)

        // 2. 提供修改它的方法
        const addCount = () => count.value++

        // 3. 必须 return 出去,模板才能使用
        return { count, addCount }
      }
    }).mount('#app')
  </script>
</body>
</html>

要点解释:

  • ref(0) 接收一个简单类型,返回一个响应式对象,它的值被包装在 .value 属性里;这是和 Vue2 data 最大的写法差异。
  • count.value++:在 JS 脚本里访问/修改 ref 数据必须加 .value,这是最容易踩的坑;而模板里 Vue 会自动解包,所以模板中写 &#123;&#123; count &#125;&#125; 而不是 &#123;&#123; count.value &#125;&#125;。
  • setup 中定义的变量和函数必须以对象形式 return 出去,否则模板里拿不到(转写稿中强调的「固定对象格式」)。
  • 对比示例 1 可见两个优势:代码量变少;同一个功能的「数据 + 方法」写在一起,从「分散式维护」变成「集中式维护」。
  • 在真实的 create-vue 项目中,用 <script setup> 语法糖可以进一步省掉 export default、setup、return 三样东西,也就是笔记里给出的写法:
vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = ()=> count.value++
</script>

示例 3:组合式 API 综合运用(ref / reactive / computed / watch)

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Vue3 - 组合式API 综合</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
  <div id="app">
    <p>原始数组:{{ list }}</p>
    <p>计算属性数组:{{ computedList }}</p>

    <p>count:{{ count }}</p>
    <button @click="count++">count 自增</button>

    <p>state.count:{{ state.count }}</p>
    <button @click="state.count++">state.count 自增</button>
  </div>

  <script>
    const { createApp, ref, reactive, computed, watch } = Vue

    createApp({
      setup() {
        // 1. ref:支持简单类型
        const list = ref([1, 2, 3, 4, 5, 6, 7, 8])
        const count = ref(0)

        // 2. reactive:只接收对象类型
        const state = reactive({ count: 0 })

        // 3. computed:基于现有响应式数据计算得到新数据
        const computedList = computed(() => list.value.filter(item => item > 2))

        // 4. watch:侦听 ref,第一个参数不加 .value
        watch(count, (newVal, oldVal) => {
          console.log('count 变化了', newVal, oldVal)
        })

        // 5. watch:精确侦听 reactive 对象里的某个属性,用 getter 形式
        watch(() => state.count, (newVal, oldVal) => {
          console.log('state.count 变化了', newVal, oldVal)
        })

        // 模拟依赖数据变化,验证 computed 会重新计算
        setTimeout(() => {
          list.value.push(9, 10)
        }, 3000)

        return { list, count, state, computedList }
      }
    }).mount('#app')
  </script>
</body>
</html>

要点解释:

  • reactive({ count: 0 }) 只能接收对象类型参数(对象、数组等),返回响应式对象;访问时直接 state.count,不需要 .value。传简单类型给 reactive 是无效的,这是最常见的错误。
  • computed(() => list.value.filter(...)) 必须 return 计算结果;里面访问 ref 数据要加 .value。计算属性只负责「算」,不要在里做请求、改 DOM 这类副作用,也不要直接给它赋值(默认只读)。
  • watch(count, ...):第一个参数是 ref 时不要加 .value,Vue 会自动处理;回调的 newVal 是新值、oldVal 是旧值。
  • watch(() => state.count, ...):这是「精确侦听」写法。如果直接写 watch(state, ...) 去侦听对象,默认是浅层侦听,直接改 state.count 不会触发回调,必须再补第三个参数 { deep: true };但 deep 会递归遍历整个对象,有性能损耗,所以能用 getter 精确侦听就尽量不开 deep。
  • 若需要「一进页面就先执行一次回调」,给 watch 补第三个参数 { immediate: true }。
  • 易错点汇总:ref 在脚本里漏写 .value;setup 里漏 return;reactive 传了基本类型;模板里多写了 .value(模板会自动解包)。

常见错误 ​

  1. 现象:在 <script setup> 里写 count++ 后页面数字不动。原因:ref 返回的是包装对象,脚本中操作的是对象本身而不是值。修法:脚本里统一写 count.value++;模板里仍写 count,不要加 .value。
  2. 现象:watch(count.value, cb) 报错或永远不触发。原因:watch 的第一个参数要传“数据源”,传 ref 本身才会被自动解包处理,传 .value 等于传了一个普通值。修法:写成 watch(count, cb);只有 getter 写法里才在函数体内取 .value。
  3. 现象:reactive(0) 或 reactive('abc') 后视图毫无反应,控制台有警告。原因:reactive 只接受对象类型参数,简单类型无法被代理。修法:基本类型一律用 ref;确实需要对象代理再用 reactive。
  4. 现象:把 reactive 生成的 state 整体重新赋值成新对象后,后续修改不再更新视图。原因:变量被换成了普通对象,原来的代理链路断了。修法:改属性而不是换引用,如 state.count++;或改用 ref 存对象,脚本中通过 state.value.xxx 修改。
  5. 现象:修改 state.count 时 watch(state, cb) 的回调不执行。原因:侦听对象默认是浅层,直接改嵌套属性不触发。修法:优先用 getter 精确侦听 watch(() => state.count, cb);确实要整体侦听再补 { deep: true },并意识到递归遍历的性能代价。
  6. 现象:非 <script setup> 的 setup() 里定义了变量,模板渲染时报“属性未定义”。原因:setup 必须返回一个对象,模板才能访问其中成员。修法:return { count, addCount };或直接改用 <script setup> 语法糖省掉 return。
  7. 现象:computed 里发请求或改 DOM,出现重复请求甚至死循环。原因:computed 的职责是纯计算,副作用会被反复触发。修法:计算只保留纯函数逻辑,请求、DOM 操作、日志等移到 watch 或事件回调中。
  8. 现象:给 computed 结果直接赋值,控制台提示只读写入失败。原因:默认只有 getter,是只读的。修法:绝大多数场景不要写计算属性,改为修改源数据;确需可写时显式提供 get/set。
  9. 现象:npm create vue@latest 执行失败或中途报错。原因:本地 Node 版本低于 16,新工具链依赖较新的运行时特性。修法:先 node -v 确认版本,升级 Node 后重试。

练习 ​

  1. 计数器改造:用 <script setup> + ref 实现计数,新增“重置为 0”按钮。完成后回答:为什么脚本里必须写 .value,而模板里不用?如果换成 reactive({ count: 0 }),重置逻辑要不要改?
  2. 表单对象:用 reactive 定义 { username: '', age: 0 },实现输入框双向同步,并额外做一个“整体替换表单”的按钮。运行后观察视图是否还更新,写出两种修复方案并比较优劣。
  3. 购物车总价:给定 ref 数组 [{ price, num }, ...],用 computed 算出总价并渲染。再故意在 computed 里加一句 console.log 和一个模拟请求,说明为什么这是错误用法,应该把这部分逻辑挪到哪里。
  4. 搜索侦听:实现“输入关键词即触发查询”的功能,要求页面初次加载就先查一次。分别用 immediate 和“手动调用一次 + watch”两种写法实现,比较代码量;再说明如果只关心 keyword 而不关心对象其他字段,应该用 getter 还是 deep。
  5. 项目结构排查:用 create-vue 新建一个项目,打开 index.html、main.js、vite.config.js,分别指出:挂载点在哪里、应用实例在哪一步创建、项目构建配置写在哪。再用一句话说明 setup 与 beforeCreate 的执行先后关系,并用 console.log 验证。

原视频对照 ​

#视频时长
1认识Vue307:23
2使用create-vue创建项目06:51
3熟悉项目目录和关键文件08:46
4组合式API入口-setup10:48
5组合式API-reactive和ref函数13:08
6组合式API-computed08:37
7组合式API-watch-基本使用和立即执行13:36
8组合式API-watch-深度侦听和精确侦听09:07

小结 ​

  • 新项目默认走 <script setup> 路线,样板代码最少,也是后续项目的主写法。
  • ref 的取值规则要背死:脚本里 .value,模板里不加,watch 传 ref 本身。
  • 基本类型只能靠 ref;reactive 只接对象,且不要整体替换引用,否则会丢响应性。
  • 两个响应式 API 二选一时,优先 ref,它能覆盖 reactive 的使用场景且更灵活。
  • computed 只负责“由现有数据算出新数据”,任何请求、DOM 操作、日志都属于副作用,应交给 watch。
  • watch 默认浅层,优先用 getter 精确侦听;deep 是兜底手段,开启前先想清楚性能成本。
  • setup 中拿不到 this,它执行在 beforeCreate 之前,所有能力靠显式导入的函数获得。
  • 项目三件套要能对上号:index.html 提供挂载点,main.js 用 createApp().mount() 完成挂载,vite.config.js 管构建配置;前置条件是 Node ≥ 16。