在 Vue 的世界裡,@ 符號如同我們日常生活中的耳朵,隨時靈敏地捕捉著周遭的聲音。今天,就讓我們一起探索 Vue 是如何巧妙地管理 DOM 事件的吧!🎧✨
前言沒有梗,就請語言模型寫。
備註一下:但今天不會帶大家走太多 DOM 事件本身的範例,主要是以 Vue 提供的功能和概念為主~![]()
![]()
![]()
官方文件:我們可以使用 v-on 指令 (簡寫為 @) 來監聽 DOM 事件,並在事件觸發時執行對應的 JavaScript。
v-on:事件名稱="事件處理器"
// 簡寫
@事件名稱="事件處理器"
"" 中的參數為:事件處理器(通常叫做 handler),有兩種用法:
foo()、count++。method 名稱,不直接傳遞參數或表達式。method 才會被呼叫。event。foo、foo.bar、foo['bar']。官方文件:模板編譯器會通過檢查 v-on 的值是否是合法的 JavaScript 標識符或屬性訪問路徑來斷定是何種形式的事件處理器。
(聽起來真的超級抽象的,我們看看範例~)
<script setup>
import { ref } from "vue";
const count = ref(1);
</script>
<template>
  <h3>目前數字:{{ count }}</h3>
  <button @click="count++">點擊就馬上+1</button>
</template>

<script setup>
function warn(message) {
  alert(message);
}
</script>
<template>
  <button @click="warn('早點睡覺!')">我是按鈕請點我</button>
</template>

以上兩個範例:
handler 參數為 count++,是一個簡易的表達式,當點擊按鈕時,這個「表達式會和事件一起」執行。handler 參數為 warn('早點睡覺!'),'早點睡覺!' 是自定義的參數,當點擊按鈕時,這個「函式及參數會和事件一起」執行。<script setup>
import { ref } from "vue";
const greetMessage = ref("哈囉哈囉哈囉");
const greet = function (event) {
  alert(greetMessage.value);
  if (event) {
    alert(event.target.innerHTML);
  }
};
</script>
<template>
  <button @click="greet">我是按鈕請點我</button>
</template>
這邊要注意的是:
事件處理器綁定了一個 method「greet」,當按下按鈕後,這個方法會單獨被呼叫、執行,並非內聯的與事件一起執行。
而它會自動傳遞原生的 DOM 物件作為參數,因此可以在 method 裡面直接取用 event。
if (event) {
  alert(event.target.innerHTML);
}
event 代表了當前的事件的 DOM 物件,我們可以 .target.innerHTML 拿到 <button @click="greet">我是按鈕請點我</button> 的 innerHTML「我是按鈕請點我」,並呈現於 alert。
看看呈現:
我們來比較一下兩者:
| handler | handler 的值 | 執行時機 | 原生 DOM 事件傳遞 | 使用情境 | 
|---|---|---|---|---|
| 內聯事件處理器 | 表達式 | 事件觸發時,立即執行 | 需要寫 $event 參數或使用箭頭函式 | 
簡單的操作/不需要重複使用的情況 | 
| 方法事件處理器 | method 名稱 | 
事件觸發後,呼叫該 method | 
自動傳遞事件物件 | 需要重複使用/複雜的邏輯處理 | 
剛剛有提到內聯事件處理器的特點:
不會自動傳遞該事件的 DOM 元素作為參數,但可以以手動傳參數/箭頭函式來取得。
也就是以下兩種方式:
$event 參數handler 定義為箭頭函式看範例會比較清楚:
<script setup>
function warn(message, event) {
  alert(message);
  if (event) {
    alert(event.target.innerHTML);
  }
}
</script>
<template>
  <li>於表達式傳入 $event 參數寫法:</li>
  <button @click="warn('早點睡覺!', $event)">我是按鈕請點我</button>
  <li>handler 寫箭頭函式:</li>
  <button
    @click="
      (event) => {
        warn('早點睡覺!', event);
      }">我是按鈕請點我
  </button>
</template>
<button @click="warn('早點睡覺!', $event)"> 我是按鈕請點我</button>:$event 參數寫法的語法,其中在 warn() 傳了 $event 參數。handler 定義為箭頭函式的語法,整個 handler 包成一個箭頭函式,並在原本的函式中傳遞 event 參數。<button
  @click="
    (event) => {
      warn('早點睡覺!', event);
    }">我是按鈕請點我
</button>
來看看兩者在瀏覽器上的呈現:
剛剛介紹了兩個事件處理器,在範例中我們演示了:在表達式內同時處理了邏輯和 DOM 元素的控制,而這在某些情境可能會變得難維護。
而「事件修飾符」是 Vue 提供的簡便工具,可以讓我們分開操作和修飾那些原本比較複雜的功能。
是指令的後綴,用 . 符號表示。
包含:
- .stop:停止傳遞事件,阻止冒泡行為。
 - .prevent:停止元素的預設行為。
 - .self:只有事件來自綁定元素本身時才觸發,避免來自子元素的觸發行為。
 - .capture:設置事件為捕獲模式。
 - .once:確保事件處理器只會觸發一次。
 - .passive:不呼叫 preventDefault()。
 
事件修飾符可以連續使用。
<a @click.stop.prevent="doThat"></a>
handler
可以不指定事件處理器。
<form @submit.prevent></form>
由於修飾符是按照順序執行的,因此排列的邏輯會影響作用範圍。
我們看看例子:
.prevent 先於 .self:@click.prevent.self
step1:阻止所有觸發元素的預設行為。
step2:只有當事件來自綁定元素本身時才觸發。
.self 先於 .prevent:@click.self.prevent
step1:只有當事件來自綁定元素本身時才觸發。
step2:阻止所有觸發元素的預設行為。
如果!
我們有個父元素包裹著子元素的情境(目前都尚未加修飾符):
<template>
  <div @click="parentClick" class="parent">
    父元素
    <a href="https://www.example.com" @click="childClick" class="child"
      >點擊這裡</a>
  </div>
</template>
<script setup>
function parentClick() {
  alert("父元素被觸發!");
  console.log("父元素被觸發!");
}
function childClick(event) {
  alert("子元素被觸發!");
  console.log("子元素被觸發!");
}
</script>
<div>:@click 事件會觸發 parentClick,跳出 alert、印出文字。<a>:@click 事件會觸發 childClick,跳出 alert、印出文字。@click 事件。我們來看一下效果:
分析一下:
parentClick。childClick,經由事件傳遞(向上冒泡),執行 父元素的 @click 事件,執行自己的預設行為跳轉連結。那麼我們對父元素設置兩個情境:
.prevent先於.self:.self先於.prevent:
直接來執行:
.prevent 先於 .self

parentClick。childClick,經由事件傳遞(向上冒泡),執行 父元素的 @click.prevent.self 事件。.prevent 先阻止了元素的預設行為(這個標記會影響子元素和父元素),然後 .self 檢查事件是否來自於本身元素。
因為事件是由子元素觸發的,所以 @click.prevent 不會影響到父元素的行為,父元素的預設行為不會被阻止,子元素的會。
.self 先於 .prevent

parentClick。childClick,經由事件傳遞(向上冒泡),執行 父元素的 @click.self.prevent 事件。.self 先檢查事件是否來自於本身元素,因為事件是由子元素觸發的,所以父元素事件先被標記不執行。.prevent 因為在 .self 後面,所以在 .self 時,就限制的作用範圍,阻止事件也只能阻止父元素自己!因此不會影響到子元素。好繞⋯⋯但這也代表了在使用時要特別注意「事件傳遞」和「修飾符」順序的相互影響!
官方文件:在監聽鍵盤事件時,我們經常需要檢查特定的按鍵。Vue 允許在 v-on 或 @ 監聽按鍵事件時添加按鍵修飾符。
也就是:我們可以利用修飾符直接控制我們想要監聽的特定按鍵,不需要手動在 handler 中檢查按鍵的 keyCode 或 key 屬性。
官方文件:Vue 為一些常用的按鍵提供了別名:
包含:
- .enter
 - .tab
 - .delete (捕獲“Delete”和“Backspace”兩個按鍵)
 - .esc
 - .space
 - .up
 - .down
 - .left
 - .right
 
我們來以下列情境試試看修飾符功能:
設置一個 input,在其中按下 Enter 鍵再放開,會跳出 alert。
使用監聽事件+修飾符:@keyup.enter,表示:執行 keyup 事件、並監聽按下 Enter 鍵再放開
<script setup>
function handleKeyup(event) {
  if (event.key === "Enter") {
    alert("你按下了 Enter 鍵又放開!");
  }
}
</script>
<template>
  <input
    type="text"
    @keyup.enter="handleKeyup"
    placeholder="請按鍵盤上的 Enter 鍵再放開"
  />
</template>
@keyup.enter="handleKeyup":這裡使用了 .enter 修飾符指定:表示在 keyup 事件發生時,只有當按下的鍵是 Enter 鍵時才會觸發 handleKeyup。handleKeyup 函式中:會自動傳入的 DOM 物件,而我們檢查 event.key 是否等於 "Enter",如果是,則跳出 alert。
官方文件:你可以使用以下系統按鍵修飾符來觸發鼠標或鍵盤事件監聽器,只有當按鍵被按下時才會觸發。
- .ctrl
 - .alt
 - .shift
 - .meta
 
官方文件:請注意,系統按鍵修飾符和常規按鍵不同。與 keyup 事件一起使用時,該按鍵必須在事件發出時處於按下狀態。換句話說,keyup.ctrl 只會在你仍然按住 ctrl 但鬆開了另一個鍵時被觸發。若你單獨鬆開 ctrl 鍵將不會觸發。
和常規按鍵一起使用時:例如,keyup.enter 會在你 鬆開 Enter 鍵時觸發。
和系統按鍵一起使用時:例如,keyup.ctrl 需要按住 Ctrl 鍵 + 其他鍵 + 鬆開另一個按鍵時 才會觸發。單獨鬆開 Ctrl 鍵,是不會觸發這個事件的。
官方文件:.exact 修飾符允許精確控制觸發事件所需要的系統修飾符的組合。
exactly,翻譯:精確地;確切地;完全準確地。
也就是,只有當事件「確實」來自於這個元素本身時,才會觸發事件處理器。
可以避免因為子元素的點擊或事件冒泡而執行不必要的事件處理。
我們看看例子:
@click.ctrl="onClick"
事件的觸發條件:按下 Ctrl 鍵 + 點擊按鈕,觸發 onClick。
注意:即使同時按下其他鍵,事件也會觸發。
@click.ctrl.exact="onCtrlClick"
事件的觸發條件:按下 Ctrl 鍵 && 沒有按下其他鍵 + 點擊按鈕,觸發 onClick。
注意:如果同時按下 Ctrl + Alt + 點擊按鈕,事件不會觸發。因為 .exact 限制了只有純粹的 Ctrl + 點擊才會觸發。
@click.exact="onCtrlClick"
事件的觸發條件:沒有按下任何修飾符 + 點擊按鈕,觸發 onClick。
注意:.exact 限制了只有純粹的點擊才觸發。
用來控制:特定的滑鼠按鍵觸發時,才會執行對應的事件處理器。
今天這篇是事件工具包的介紹,對事件還不是很熟悉的關係,突然又發現自己的菜味很重 GG,但也代表可意識到還有很多東西可以學習(是吧是吧)。
偶們明天見(不講明天要做什麼嗎)
沒看海綿寶寶,第一次用派星機的我
https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day22
被列為參考資料在下著實誠惶誠恐啊(つд⊂)
但使用派星機是一定要推的d(`・∀・)b
![]()
派星機參考資料也是你那兒哈哈哈哈哈