本文 AI 產出,尚未審核

Vue3 教學:模板語法中的屬性縮寫(:, @


簡介

在 Vue 3 的單檔組件(.vue)裡,**模板(template)**是與使用者互動的第一層介面。若沒有良好的模板寫法,程式碼很快就會變得冗長且難以維護。Vue 為了讓模板更簡潔,提供了兩個常用的 屬性縮寫

  • :v-bind(綁定屬性或動態值)
  • @v-on(綁定事件)

這兩個縮寫不僅能減少鍵入次數,還能提升可讀性,讓開發者專注於 「做什麼」 而非 「怎麼寫」。本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,最後帶入實務應用,完整掌握屬性縮寫的使用方法。


核心概念

1. :(v‑bind)—— 動態綁定屬性

v-bind 用於把 JavaScript 表達式的值綁定到 HTML 屬性上。縮寫 : 只是一個語法糖,功能完全相同。

<!-- 完整寫法 -->
<img v-bind:src="imageUrl" v-bind:alt="imageAlt">

<!-- 縮寫寫法 -->
<img :src="imageUrl" :alt="imageAlt">
  • 靜態屬性 vs 動態屬性
    • 靜態屬性(寫死的字串)直接寫在標籤上即可。
    • 動態屬性需要透過 :v-bind,讓 Vue 在渲染時把資料變更同步到 DOM。

1.1 綁定 class 與 style

Vue 允許以物件或陣列形式綁定 classstyle,縮寫寫法同樣適用。

<div :class="{ active: isActive, disabled: isDisabled }"></div>

<div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>

1.2 綁定自訂屬性(props)

在子組件上傳遞資料時,常會使用 : 直接綁定。

<!-- 父層 -->
<my-button :label="btnLabel" :disabled="isBtnDisabled"></my-button>

2. @(v‑on)—— 事件監聽

v-on 用於在模板中監聽 DOM 事件或自訂事件。縮寫 @ 讓事件綁定更為簡潔。

<!-- 完整寫法 -->
<button v-on:click="handleClick">Click Me</button>

<!-- 縮寫寫法 -->
<button @click="handleClick">Click Me</button>
  • 事件修飾符.stop.prevent.once.capture…)同樣可以與 @ 結合。
<form @submit.prevent="onSubmit">
  <input @keyup.enter="onEnter" />
</form>

2.1 監聽自訂事件

子組件透過 emit 發出事件,父層使用 @ 監聽。

<!-- 子組件 MyModal.vue -->
<template>
  <div class="modal">
    <button @click="$emit('close')">關閉</button>
  </div>
</template>

<!-- 父層使用 -->
<my-modal @close="showModal = false"></my-modal>

3. 同時使用 :@

在同一個標籤上綁定屬性與事件時,兩者可以自由混用,保持語意清晰。

<my-input
  :value="searchQuery"
  @input="searchQuery = $event"
  @focus="onFocus"
  placeholder="搜尋關鍵字"
></my-input>

程式碼範例

以下提供 5 個實用範例,說明屬性縮寫在不同情境下的寫法與注意點。

範例 1:動態圖片切換

<template>
  <div>
    <img :src="currentImg" :alt="`圖片 ${index + 1}`" />
    <button @click="nextImg">下一張</button>
  </div>
</template>

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

const images = [
  'https://picsum.photos/id/1015/400/200',
  'https://picsum.photos/id/1016/400/200',
  'https://picsum.photos/id/1018/400/200'
]
const index = ref(0)
const currentImg = computed(() => images[index.value])

function nextImg() {
  index.value = (index.value + 1) % images.length
}
</script>

重點:srcalt 能即時反映 index 的變化;@click 觸發切換邏輯。


範例 2:條件式 class 與事件修飾

<template>
  <button
    :class="[{ primary: isPrimary }, 'rounded']"
    @click.stop="togglePrimary"
  >
    {{ isPrimary ? '主題模式' : '一般模式' }}
  </button>
</template>

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

const isPrimary = ref(false)
function togglePrimary() {
  isPrimary.value = !isPrimary.value
}
</script>

<style scoped>
.primary {
  background-color: #42b983;
  color: white;
}
.rounded {
  border-radius: 8px;
}
</style>

說明: 以陣列方式混合靜態與動態 class;@click.stop 防止事件冒泡。


範例 3:表單驗證的 v-model@submit.prevent

<template>
  <form @submit.prevent="onSubmit">
    <input
      type="email"
      v-model="email"
      :class="{ error: emailError }"
      placeholder="請輸入 Email"
    />
    <span v-if="emailError" class="msg">Email 格式不正確</span>
    <button type="submit">送出</button>
  </form>
</template>

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

const email = ref('')
const emailError = ref(false)

function onSubmit() {
  const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  emailError.value = !pattern.test(email.value)
  if (!emailError.value) {
    alert(`送出成功:${email.value}`)
  }
}
</script>

<style scoped>
.error {
  border: 1px solid red;
}
.msg {
  color: red;
  font-size: 0.9rem;
}
</style>

關鍵@submit.prevent 取代了 event.preventDefault(),讓表單提交行為更直觀。


範例 4:子組件向父層傳遞資料(自訂事件)

<!-- ChildCounter.vue -->
<template>
  <button @click="increment">+ {{ count }}</button>
</template>

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

const emit = defineEmits(['update'])
const count = ref(0)

function increment() {
  count.value++
  emit('update', count.value)   // 向父層傳遞最新值
}
</script>
<!-- Parent.vue -->
<template>
  <h2>目前計數:{{ total }}</h2>
  <ChildCounter @update="total = $event" />
</template>

<script setup>
import { ref } from 'vue'
import ChildCounter from './ChildCounter.vue'

const total = ref(0)
</script>

說明:父層使用 @update 直接接收子層傳遞的參數,省去繁瑣的 $event 變數命名。


範例 5:使用 :v-bind 目標屬性(SVG)

<template>
  <svg width="120" height="120" viewBox="0 0 120 120">
    <circle
      :cx="centerX"
      :cy="centerY"
      :r="radius"
      :stroke="color"
      stroke-width="4"
      fill="none"
    />
  </svg>
  <input type="range" min="10" max="50" v-model="radius" />
</template>

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

const centerX = 60
const centerY = 60
const radius = ref(30)
const color = ref('#ff5722')
</script>

重點:即使是 SVG 屬性,: 仍能正確綁定,使圖形隨 radius 變化而即時更新。


常見陷阱與最佳實踐

陷阱 說明 建議的解決方式
忘記加引號 :src=imageUrl 會被解析為 屬性名稱 而非綁定表達式,導致錯誤。 必須寫成 :src="imageUrl"(包含雙引號)。
使用保留字作屬性 Vue 內建指令如 classstyle 已有特殊處理,若使用 :class 時不小心寫成 :class="class" 會產生衝突。 改用不同變數名稱(classNamecustomClass),或直接使用物件語法。
事件名稱大小寫不一致 在 HTML 中屬性名不區分大小寫,@myEvent 會被轉成 myevent,子組件若 $emit('myEvent'),父層無法接收。 使用 kebab-case@my-event)或 全部小寫,保持一致。
過度使用縮寫 雖然縮寫簡潔,但過度濫用會讓新手難以辨識 v-bindv-on 的功能。 在較複雜的模板或教學文件中,適度保留完整寫法提升可讀性。
忘記 .prevent.stop 表單提交或點擊冒泡時,若未加修飾符會導致意外行為。 依需求加入 @submit.prevent@click.stop 等修飾符。

最佳實踐

  1. 保持一致的命名風格:建議在整個專案中統一使用 :@ 的縮寫,並採用 kebab-case 事件名稱。
  2. 適度加入註解:在較複雜的綁定(如動態 classstyle)旁加上簡短註解,方便團隊成員快速理解。
  3. 分離邏輯與模板:僅在模板裡使用簡單表達式,較複雜的計算或資料轉換請放到 computedmethods 中,保持模板乾淨。
  4. 善用 TypeScript:若使用 Vue 3 + TS,為 propsemit 定義類型,能在編譯階段捕捉錯誤,減少屬性縮寫的誤用。

實際應用場景

1. 動態表單生成

在大型企業內部系統,表單欄位往往依據後端配置動態產生。透過 : 可把欄位的 typeplaceholderrequired 等屬性直接綁定到 JSON 配置,減少硬編碼。

<div v-for="field in formConfig" :key="field.id">
  <input
    :type="field.type"
    :placeholder="field.placeholder"
    :required="field.required"
    v-model="formData[field.name]"
  />
</div>

2. 互動式圖表與視覺化

在使用 echartsd3 或原生 SVG 時,常需要根據使用者操作即時改變屬性(顏色、座標、大小)。: 能把資料驅動的屬性直接映射到圖形上,讓 UI 變化即時且流暢。

3. 複雜的父子通訊

大型專案的元件樹結構深,子層往往需要向上回報多個事件(如表單驗證結果、選取狀態)。使用 @ 加上自訂事件名稱,可讓父層清晰地監聽每個子層行為,保持單向資料流的概念。

4. 多語系切換

語系文字往往放在 i18n 物件中,使用 : 直接綁定文字來源,讓切換語系時不必手動更新每個字串。

<h1 :title="$t('page.title')">{{ $t('page.heading') }}</h1>

總結

  • 屬性縮寫 :v-bind)與 @v-on)是 Vue 3 模板語法的核心工具,能讓屬性與事件的綁定變得簡潔且易於維護。
  • 正確使用縮寫能提升 可讀性開發效率,並保持 單向資料流 的設計原則。
  • 在使用過程中要留意 引號、命名衝突、大小寫 等常見陷阱,並遵循 一致的命名風格分離邏輯與模板 的最佳實踐。
  • 無論是 動態表單互動圖表父子通訊多語系切換,屬性縮寫都是讓 Vue 應用更具彈性與可擴充性的關鍵技巧。

掌握了這兩個縮寫,你就可以在 Vue 3 中寫出 乾淨、易懂、具備高度互動性的 UI,為專案的可維護性奠定堅實基礎。祝你在 Vue 的世界裡玩得開心,寫出更好的程式碼!