Skip to content

宣告式渲染與響應式心智

重新認識 Vue.js: 008 天絕對看不完的 Vue.js 3.x 指南

上一章我們已經用 Vite 建立好第一個 Vue 專案。接下來,先把畫面與資料之間的關係看清楚。先別急著找 DOM:用 Vue 時,我們更常做的是修改資料,剩下的畫面更新交給 Vue。

從資料驅動畫面開始

在傳統 DOM 操作中,我們常會先找到某個元素,再把文字塞進去。Vue 的寫法反過來:我們在 <script setup> 準備資料,在 <template> 描述畫面要如何呈現資料。

請打開 CH1 建好的 create-vue 專案,先把 src/App.vue 改成下面這個最小範例:

vue
<script setup>
const message = 'Hello Vue!'
</script>

<template>
  <main class="app">
    <h1>{{ message }}</h1>
  </main>
</template>

<style scoped>
.app {
  padding: 2rem;
}
</style>

{{ message }} 稱為文字插值。Vue 會讀取 message 的值,並把它顯示在畫面上。這裡還沒有任何互動,不過已經是接下來會反覆看到的分工:資料準備在 <script setup>,畫面則寫在 <template>

讓資料變成響應式

如果資料會改變,就要讓 Vue 追蹤它。Composition API 裡最常用的起點是 ref()

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

const count = ref(0)

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

<template>
  <main class="app">
    <p>目前數字:{{ count }}</p>
    <button type="button" @click="increment">
      加一
    </button>
  </main>
</template>

<style scoped>
.app {
  padding: 2rem;
}
</style>

ref(0) 會建立一個可被 Vue 追蹤的響應式資料。按下按鈕時,increment() 修改 count.value,Vue 會自動把畫面上的 {{ count }} 更新成新的值。

常見錯誤:忘記 .value

<script setup> 裡,ref 的值要透過 .value 存取:

js
const count = ref(0)

count++          // 錯誤:count 是 const,重新指派會拋出 TypeError
count.value++    // 正確:這是在改 ref 裡面的值

要注意的是,count++ 並不是「改到 ref 裡面的值」,而是試圖把 count 這個變數重新指派成別的東西。因為我們用 const 宣告,JavaScript 會直接拋出錯誤,這反而是好事:錯誤訊息會提醒我們忘了 .value

但在 <template> 裡,Vue 會自動解包 ref,所以畫面上寫 {{ count }} 即可,不需要寫成 {{ count.value }}

小提醒:還有一個 reactive()

Vue 也提供 reactive() 建立響應式物件。本章先統一使用較容易追蹤資料來源的 ref();兩者的差異與選擇方式,CH3 說明響應式系統時會完整比較。

模板自動解包

模板自動解包是初學者最容易混淆的地方。我們可以用一句話記住:

  • <script setup> 裡操作 ref:要寫 .value
  • <template> 裡顯示或綁定 ref:直接寫變數名稱。

不過自動解包有個前提:它只適用於模板可以直接看到的頂層變數,也就是像本章這樣直接在 <script setup> 頂層宣告的 ref。如果 ref 被包在一般物件的屬性裡,模板運算式就不會自動解包它。本章的範例都是頂層宣告,可以放心套用這個規則;巢狀結構的細節,我們留到 CH3 討論響應式系統時再展開。

下面這個範例同時使用 ref 與模板插值:

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

const name = ref('Kuro')

function rename() {
  name.value = 'Vue Reader'
}
</script>

<template>
  <main class="app">
    <p>Hi, {{ name }}!</p>
    <button type="button" @click="rename">
      換名字
    </button>
  </main>
</template>

<style scoped>
.app {
  padding: 2rem;
}
</style>

按下按鈕後,我們沒有直接操作 DOM,也沒有自己去找 <p> 標籤。只要資料改變,畫面就會跟著資料重新呈現。

Vue 的更新流程

可以先用這張圖建立直覺:

這張圖先記住一件事:我們修改的是狀態,Vue 負責安排畫面更新。資料可能來自按鈕,也可能來自 API 或計時器;Vue 會批次處理這些變化,最後只更新必要的 DOM。

接下來要介紹的模板、事件與 computed,都是建立在這個資料驅動畫面的觀念上。