Vue 修飾符有哪些
Vue 修飾符是 template 裡很常見的語法糖,例如 @click.stop、@submit.prevent、v-model.trim。它們的目的不是增加新能力,而是把常見的 DOM 事件處理、表單處理、屬性綁定行為,用更宣告式的方式寫在模板上。
一句話回答:Vue 修飾符可以分成事件修飾符、鍵盤修飾符、滑鼠修飾符、v-model 修飾符、v-bind 修飾符與自訂 v-model 修飾符;底層通常會在編譯階段轉成事件包裝函數、事件選項、props 或 model modifiers。
一、 必考觀念
1. 修飾符是什麼?
修飾符是接在指令後面的特殊後綴:
<button @click.stop="handleClick">Click</button>
<form @submit.prevent="submit">Submit</form>
<input v-model.trim="username" />它讓模板更專注於「這個事件或綁定應該具備什麼行為」,避免把大量樣板程式塞進 methods。
例如:
<form @submit.prevent="submit">
...
</form>等價心智模型:
function onSubmit(event) {
event.preventDefault()
submit(event)
}2. 常見修飾符分類
| 類型 | 例子 | 用途 |
|---|---|---|
| 事件修飾符 | .stop、.prevent、.self、.once、.capture、.passive | 控制 DOM 事件行為 |
| 鍵盤修飾符 | .enter、.esc、.tab、.delete | 限制特定鍵盤事件才觸發 |
| 系統鍵修飾符 | .ctrl、.shift、.alt、.meta、.exact | 限制組合鍵 |
| 滑鼠修飾符 | .left、.right、.middle | 限制滑鼠按鍵 |
v-model 修飾符 | .lazy、.number、.trim | 控制表單同步行為 |
v-bind 修飾符 | .prop、.attr、.camel | 控制 attribute / property 綁定 |
| 自訂 model 修飾符 | v-model.capitalize | 傳給子元件自行處理 |
二、 事件修飾符
1. .stop
阻止事件冒泡。
<div @click="parentClick">
<button @click.stop="buttonClick">Click</button>
</div>等價於:
function onClick(event) {
event.stopPropagation()
buttonClick(event)
}適合場景:卡片點擊進詳情,但卡片內的按鈕有自己的操作,不希望觸發外層卡片點擊。
2. .prevent
阻止瀏覽器預設行為。
<form @submit.prevent="submit">
...
</form>等價於:
event.preventDefault()常用於表單提交、阻止 <a> 原生跳轉。
3. .self
只有事件目標是元素本身時才觸發,不包含子元素冒泡上來的事件。
<div class="modal-mask" @click.self="close">
<div class="modal">
...
</div>
</div>點遮罩關閉,點 modal 內容不關閉。
4. .once
事件只觸發一次。
<button @click.once="init">Init</button>這通常會轉成事件 listener option 或等價的一次性處理。
5. .capture
使用事件捕獲階段。
<div @click.capture="captureClick">
<button @click="buttonClick">Click</button>
</div>一般事件流程是 capture -> target -> bubble。.capture 讓 handler 在捕獲階段執行。
6. .passive
告訴瀏覽器這個 listener 不會呼叫 preventDefault()。
<div @scroll.passive="onScroll" />常用於 scroll/touch 事件,讓瀏覽器可以更放心地做滾動優化。
IMPORTANT
不要同時使用 .passive 和 .prevent。.passive 表示不會阻止預設行為,.prevent 則是要阻止預設行為,語意衝突。
7. 修飾符順序會影響結果
Vue 會按照你寫的順序產生對應處理。
<button @click.stop.prevent="submit" />表示先 stop,再 prevent。
通常差異不大,但像 .self 和 .prevent 組合時要小心:
<!-- 只阻止元素自身點擊的預設行為 -->
<a @click.self.prevent="handle" />
<!-- 先 prevent,再判斷 self -->
<a @click.prevent.self="handle" />面試時可以補一句:修飾符不是純標籤,順序可能影響生成後的邏輯。
三、 鍵盤與系統鍵修飾符
1. 鍵盤修飾符
常見鍵盤修飾符:
<input @keyup.enter="submit" />
<input @keyup.esc="cancel" />
<input @keydown.tab="handleTab" />
<input @keyup.delete="remove" />常見別名:
| 修飾符 | 說明 |
|---|---|
.enter | Enter |
.tab | Tab |
.delete | Delete 或 Backspace |
.esc | Escape |
.space | Space |
.up | ArrowUp |
.down | ArrowDown |
.left | ArrowLeft |
.right | ArrowRight |
它的心智模型是:
function onKeyup(event) {
if (event.key !== 'Enter') {
return
}
submit(event)
}2. 系統鍵修飾符
系統鍵包含:
<button @click.ctrl="selectMultiple">Select</button>
<button @click.shift="selectRange">Select Range</button>
<button @click.meta="openCommand">Command</button>常見系統鍵:
| 修飾符 | 對應 |
|---|---|
.ctrl | Ctrl |
.shift | Shift |
.alt | Alt |
.meta | macOS Command / Windows Win |
例如:
<input @keyup.ctrl.enter="submit" />代表 Ctrl + Enter 時才提交。
3. .exact
.exact 用來限制「只能有指定的系統鍵」。
<!-- Ctrl 被按下即可,其他系統鍵也可同時存在 -->
<button @click.ctrl="save">Save</button>
<!-- 只有 Ctrl 被按下才觸發,不能同時按 Shift / Alt / Meta -->
<button @click.ctrl.exact="save">Save</button>
<!-- 沒有任何系統鍵被按下才觸發 -->
<button @click.exact="normalClick">Click</button>四、 滑鼠修飾符
滑鼠按鍵修飾符:
<button @click.left="leftClick">Left</button>
<button @click.right="rightClick">Right</button>
<button @click.middle="middleClick">Middle</button>| 修飾符 | 說明 |
|---|---|
.left | 滑鼠左鍵 |
.right | 滑鼠右鍵 |
.middle | 滑鼠中鍵 |
右鍵通常也會搭配 .prevent 阻止預設選單:
<div @contextmenu.prevent="openMenu" />五、 v-model 修飾符
1. .lazy
預設 v-model 在文字輸入時使用 input 事件,使用者每輸入一次就同步。
<input v-model="keyword" />.lazy 改成在 change 時同步,通常是失焦或確認後。
<input v-model.lazy="keyword" />適合不想每個字都更新的場景。
2. .number
嘗試把輸入值轉成 number。
<input v-model.number="age" />要注意:它不是完整驗證。空字串、非法數字、特殊輸入仍要自己處理。
3. .trim
自動去掉字串前後空白。
<input v-model.trim="username" />適合帳號、關鍵字、email 這類常見輸入。
4. 自訂元件 v-model modifiers
Vue 也支援自訂 v-model 修飾符:
<BaseInput v-model.capitalize="name" />子元件可以讀到 modifiers,並自行決定如何處理。
在 Vue 3.4+,常見寫法是搭配 defineModel:
<script setup lang="ts">
const [model, modifiers] = defineModel<string>()
function update(value: string) {
if (modifiers.capitalize) {
model.value = value.charAt(0).toUpperCase() + value.slice(1)
return
}
model.value = value
}
</script>如果不用 defineModel,也可以透過 modelModifiers 這類 props 設計處理。
延伸讀:v-model 雙向綁定的原理。
六、 v-bind 修飾符
1. .prop
強制作為 DOM property 綁定。
<div :text-content.prop="message" />一般情況 Vue 會自動判斷 attribute/property,但 .prop 可以明確指定。
2. .attr
強制作為 attribute 綁定。
<div :some-prop.attr="value" />適合你想明確輸出 HTML attribute,而不是設定 DOM property 的場景。
3. .camel
把 kebab-case attribute 名轉成 camelCase。
<svg :view-box.camel="viewBox" />在 DOM 模板或特殊 attribute 場景中可能用到。SFC template 裡通常比較少需要手動使用。
七、 底層原理
1. 事件修飾符如何實現?
Vue compiler 會把事件修飾符轉成對應 helper。
概念上:
<button @click.stop.prevent="submit">Submit</button>會變成類似:
withModifiers(submit, ['stop', 'prevent'])執行時 wrapper 會先處理:
event.stopPropagation()
event.preventDefault()再呼叫你的 submit。
2. 鍵盤修飾符如何實現?
鍵盤修飾符會變成 key guard。
<input @keyup.enter="submit" />概念上:
withKeys(submit, ['enter'])只有符合指定 key 時才執行 handler。
3. .once、.capture、.passive 如何實現?
這類修飾符更接近 addEventListener 的 options:
el.addEventListener('click', handler, {
once: true,
capture: true,
passive: true,
})Vue 會透過事件名稱或 patch event 邏輯把它們轉成對應 listener options。
4. v-model 修飾符如何實現?
原生表單上的 v-model.trim、.number、.lazy 會影響事件與取值處理。
自訂元件上的修飾符則會傳給子元件,讓子元件決定怎麼處理。
所以修飾符不只有一種實現方式,要看它修飾的是 v-on、v-model 還是 v-bind。
八、 追問題庫
Q1:.stop 和 .prevent 差在哪?
.stop 是阻止事件冒泡,對應 event.stopPropagation()。
.prevent 是阻止預設行為,對應 event.preventDefault()。
例如表單提交通常用 .prevent,內層按鈕不想觸發外層點擊通常用 .stop。
Q2:.self 和 .stop 差在哪?
.stop 會阻止事件繼續往外冒泡。
.self 不阻止冒泡,只是限制 handler 只有在 event.target === event.currentTarget 時才執行。
Q3:為什麼 .passive 不應該和 .prevent 一起用?
因為 .passive 告訴瀏覽器這個 listener 不會阻止預設行為,.prevent 卻要阻止預設行為。兩者語意衝突。
Q4:v-model.number 一定會得到 number 嗎?
不一定。
.number 會嘗試轉型,但它不是完整驗證。表單輸入仍可能有空字串或無法轉換的值。重要資料仍應做顯式驗證。
Q5:Vue 2 的 .native 還能用嗎?
Vue 2 常見 .native 用來監聽子元件根元素的原生事件。
Vue 3 移除了 .native。如果事件沒有被子元件宣告在 emits 裡,通常會作為 fallthrough listener 傳到子元件根元素。實務上更推薦明確定義 emits,讓元件事件 API 清楚。
Q6:.sync 還能用嗎?
Vue 2 的 .sync 常用於父子雙向更新。
Vue 3 移除 .sync,改用更統一的 v-model:propName:
<Dialog v-model:open="opened" />這本質上是:
<Dialog
:open="opened"
@update:open="opened = $event"
/>九、 實作題
題目:解釋這段模板中的修飾符
<template>
<form @submit.prevent="submit">
<input
v-model.trim="username"
@keyup.enter.exact="submit"
/>
<button
type="button"
@click.stop.once="send"
>
Send
</button>
</form>
</template>可以這樣回答:
@submit.prevent:阻止表單預設提交刷新頁面,改由submit處理。v-model.trim:同步輸入值時去掉前後空白。@keyup.enter.exact:只有按 Enter 且沒有其他系統鍵時才提交。@click.stop.once:點擊按鈕時阻止事件冒泡,且send只觸發一次。
十、 資深視角
1. 修飾符是模板可讀性工具
修飾符讓常見事件行為直接出現在模板上:
@submit.prevent
@click.stop
@keyup.enter讀者不用跳到 methods 裡才知道有沒有 preventDefault()、stopPropagation()。這是它最大的價值。
2. 不要把複雜邏輯塞進修飾符組合
修飾符適合處理通用、簡單、可預期的 DOM 行為。
如果條件變複雜,應該回到明確函數:
<button @click="handleClick">Click</button>function handleClick(event: MouseEvent) {
if (shouldIgnore(event)) {
return
}
submit()
}3. 理解修飾符能幫你理解 compiler
修飾符不是 runtime 魔法。很多修飾符會在 compiler 階段被轉成 helper、事件選項或 props。
理解這點後,就更容易接上:Vue Compiler 的實現原理。
總結
| 類型 | 常見修飾符 |
|---|---|
| 事件 | .stop、.prevent、.self、.once、.capture、.passive |
| 鍵盤 | .enter、.tab、.delete、.esc、.space、.up、.down、.left、.right |
| 系統鍵 | .ctrl、.shift、.alt、.meta、.exact |
| 滑鼠 | .left、.right、.middle |
v-model | .lazy、.number、.trim、自訂 modifiers |
v-bind | .prop、.attr、.camel |
一句完整的面試回答可以是:
Vue 修飾符是模板指令的語法糖,常見類型有事件修飾符、鍵盤修飾符、系統鍵修飾符、滑鼠修飾符、
v-model修飾符和v-bind修飾符。事件修飾符像.stop、.prevent會被轉成事件包裝邏輯;.once、.capture、.passive接近 addEventListener options;鍵盤修飾符會生成 key guard;v-model.trim、.number、.lazy會影響表單取值與同步時機。它們的核心價值是讓常見 DOM 行為以宣告式方式留在模板中。