iT邦幫忙

2024 iThome 鐵人賽

DAY 22
1
Modern Web

欸你是要進 Vue 了沒?系列 第 22

欸你是要進 Vue 了沒? - Day22:Vue 事件處理之 v-on @我知道你什麼事都聽到了

  • 分享至 

  • xImage
  •  

在 Vue 的世界裡,@ 符號如同我們日常生活中的耳朵,隨時靈敏地捕捉著周遭的聲音。今天,就讓我們一起探索 Vue 是如何巧妙地管理 DOM 事件的吧!🎧✨

前言沒有梗,就請語言模型寫。

備註一下:但今天不會帶大家走太多 DOM 事件本身的範例,主要是以 Vue 提供的功能和概念為主~
/images/emoticon/emoticon25.gif/images/emoticon/emoticon25.gif/images/emoticon/emoticon25.gif

定義

官方文件:我們可以使用 v-on 指令 (簡寫為 @) 來監聽 DOM 事件,並在事件觸發時執行對應的 JavaScript。

語法

v-on:事件名稱="事件處理器"

// 簡寫
@事件名稱="事件處理器"

"" 中的參數為:事件處理器(通常叫做 handler),有兩種用法:

  1. 內聯事件處理器(Inline handlers):
  • 直接寫出執行的表達式(通常是函式呼叫和參數)。
  • 事件觸發時,函式和參數會「一起在事件中執行」。
  • 不會自動傳遞該事件的 DOM 元素作為參數,但可以以手動傳入參數/箭頭函式來取得。
  • 範例:foo()count++
  1. 方法事件處理器(Method handlers):
  • 綁定 method 名稱,不直接傳遞參數或表達式。
  • 不會立即執行,事件觸發後,method 才會被呼叫。
  • 會自動傳遞該事件的 DOM 元素作為參數,通常命名為 event
  • 範例:foofoo.barfoo['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>

以上兩個範例:

  1. 範例一:handler 參數為 count++,是一個簡易的表達式,當點擊按鈕時,這個「表達式會和事件一起」執行。
  2. 範例二:handler 參數為 warn('早點睡覺!')'早點睡覺!' 是自定義的參數,當點擊按鈕時,這個「函式及參數會和事件一起」執行。
    這兩個範例都「沒有傳遞原生 DOM 事件」,專注於執行內部的邏輯和自定義參數,沒有使用原生 DOM 物件。

事件處理器範例

<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>

這邊要注意的是:
事件處理器綁定了一個 methodgreet」,當按下按鈕後,這個方法會單獨被呼叫、執行,並非內聯的與事件一起執行。
而它會自動傳遞原生的 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>
  1. <button @click="warn('早點睡覺!', $event)"> 我是按鈕請點我</button>
    是於表達式傳入 $event 參數寫法的語法,其中在 warn() 傳了 $event 參數。
  2. 以下這是 handler 定義為箭頭函式的語法,整個 hanlder 包成一個箭頭函式,並在原本的函式中傳遞 event 參數。
<button
  @click="
    (event) => {
      warn('早點睡覺!', event);
    }">我是按鈕請點我
</button>

來看看兩者在瀏覽器上的呈現:

事件修飾符

定義

剛剛介紹了兩個事件處理器,在範例中我們演示了:在表達式內同時處理了邏輯和 DOM 元素的控制,而這在某些情境可能會變得難維護。

而「事件修飾符」是 Vue 提供的簡便工具,可以讓我們分開操作和修飾那些原本比較複雜的功能。

語法

是指令的後綴,用 . 符號表示。

包含:

  • .stop:停止傳遞事件,阻止冒泡行為。
  • .prevent:停止元素的預設行為。
  • .self:只有事件來自綁定元素本身時才觸發,避免來自子元素的觸發行為。
  • .capture:設置事件為捕獲模式。
  • .once:確保事件處理器只會觸發一次。
  • .passive:不呼叫 preventDefault()。

特點

  1. 鏈式寫法

事件修飾符可以連續使用。

<a @click.stop.prevent="doThat"></a>
  1. 可不寫 handler

可以不指定事件處理器。

<form @submit.prevent></form>

需注意使用順序!

由於修飾符是按照順序執行的,因此排列的邏輯會影響作用範圍。

我們看看例子:

  1. .prevent 先於 .self
@click.prevent.self

step1:阻止所有觸發元素的預設行為。
step2:只有當事件來自綁定元素本身時才觸發。

  1. .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>
  1. 點擊父元素 <div>
  • @click 事件會觸發 parentClick,跳出 alert、印出文字。
  • 沒有預設行為。
  1. 點擊子元素 <a>
  • @click 事件會觸發 childClick,跳出 alert、印出文字。
  • 事件冒泡,所以會觸發父層的 @click 事件。
  • 預設行為是跳轉連結。

我們來看一下效果:

分析一下:

  1. 點擊父元素:執行 parentClick
  2. 點擊子元素:執行 childClick,經由事件傳遞(向上冒泡),執行 父元素的 @click 事件,執行自己的預設行為跳轉連結。

那麼我們對父元素設置兩個情境:

  1. .prevent 先於 .self
  2. .self 先於 .prevent

直接來執行:

  1. .prevent 先於 .self

  1. 點擊父元素:執行 parentClick
  2. 點擊子元素:執行 childClick,經由事件傳遞(向上冒泡),執行 父元素的 @click.prevent.self 事件。

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

  1. .self 先於 .prevent

  1. 點擊父元素:執行 parentClick
  2. 點擊子元素:執行 childClick,經由事件傳遞(向上冒泡),執行 父元素的 @click.self.prevent 事件。
    .self 先檢查事件是否來自於本身元素,因為事件是由子元素觸發的,所以父元素事件先被標記不執行。
    .prevent 因為在 .self 後面,所以在 .self 時,就限制的作用範圍,阻止事件也只能阻止父元素自己!因此不會影響到子元素。

好繞⋯⋯但這也代表了在使用時要特別注意「事件傳遞」和「修飾符」順序的相互影響!

按鍵修飾符

官方文件:在監聽鍵盤事件時,我們經常需要檢查特定的按鍵。Vue 允許在 v-on 或 @ 監聽按鍵事件時添加按鍵修飾符。

也就是:我們可以利用修飾符直接控制我們想要監聽的特定按鍵,不需要手動在 handler 中檢查按鍵的 keyCodekey 屬性。

常規按鍵修飾符

官方文件: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 事件一起使用時,該按鍵必須在事件發出時處於按下狀態。換句話說,keyup.ctrl 只會在你仍然按住 ctrl 但鬆開了另一個鍵時被觸發。若你單獨鬆開 ctrl 鍵將不會觸發。

和常規按鍵一起使用時:例如,keyup.enter 會在你 鬆開 Enter 鍵時觸發。
和系統按鍵一起使用時:例如,keyup.ctrl 需要按住 Ctrl 鍵 + 其他鍵 + 鬆開另一個按鍵時 才會觸發。單獨鬆開 Ctrl 鍵,是不會觸發這個事件的。

.exact 修飾符

官方文件:.exact 修飾符允許精確控制觸發事件所需要的系統修飾符的組合。

exactly,翻譯:精確地;確切地;完全準確地。
也就是,只有當事件「確實」來自於這個元素本身時,才會觸發事件處理器。
可以避免因為子元素的點擊或事件冒泡而執行不必要的事件處理。

我們看看例子:

@click.ctrl="onClick"

事件的觸發條件:按下 Ctrl 鍵 + 點擊按鈕,觸發 onClick
注意:即使同時按下其他鍵,事件也會觸發。

@click.ctrl.exact="onCtrlClick"

事件的觸發條件:按下 Ctrl 鍵 && 沒有按下其他鍵 + 點擊按鈕,觸發 onClick
注意:如果同時按下 Ctrl + Alt + 點擊按鈕,事件不會觸發。因為 .exact 限制了只有純粹的 Ctrl + 點擊才會觸發。

@click.exact="onCtrlClick"

事件的觸發條件:沒有按下任何修飾符 + 點擊按鈕,觸發 onClick
注意:.exact 限制了只有純粹的點擊才觸發。

鼠標按鍵修飾符

用來控制:特定的滑鼠按鍵觸發時,才會執行對應的事件處理器。

  • .left:點擊左鍵時,hanlder 會被觸發。
  • .right:點擊右鍵時,hanlder 會被觸發。
  • .middle:點擊中間鍵/滾輪時,hanlder 會被觸發。

小結

今天這篇是事件工具包的介紹,對事件還不是很熟悉的關係,突然又發現自己的菜味很重 GG,但也代表可意識到還有很多東西可以學習(是吧是吧)。

偶們明天見(不講明天要做什麼嗎)
https://ithelp.ithome.com.tw/upload/images/20241006/201691399Y4mK3dGhQ.jpg

沒看海綿寶寶,第一次用派星機的我

範例 code ⬇️

https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day22

參考資料


上一篇
欸你是要進 Vue 了沒? - Day21:Vue 列表渲染之 v-for 和它の關鍵小夥伴 key && 虛擬 DOM
系列文
欸你是要進 Vue 了沒?22
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

1
jeremykuo
iT邦新手 5 級 ‧ 2024-10-06 19:59:27

那個小貝貝是在散發菜味嗎???
沒關係這是新鮮的菜味,不要放太久就行XDD

++ iT邦新手 5 級 ‧ 2024-10-06 20:15:37 檢舉

菜到妥協 到頭來還是無解

1
橘子
iT邦新手 5 級 ‧ 2024-10-06 21:40:28

被列為參考資料在下著實誠惶誠恐啊(つд⊂)
但使用派星機是一定要推的d(`・∀・)b

++ iT邦新手 5 級 ‧ 2024-10-06 22:03:41 檢舉

/images/emoticon/emoticon37.gif

++ iT邦新手 5 級 ‧ 2024-10-06 22:03:50 檢舉

派星機參考資料也是你那兒哈哈哈哈哈

我要留言

立即登入留言