iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
Vue.js

這是我的 Vue.js 筆記,不知道有沒有機會幫到你系列 第 15

我的 Vue.js 筆記(15) - 前言

  • 分享至 

  • xImage
  •  

前言

今天來聊聊 Vue 中事件的寫法。

基本語法

如果你有看過怎麼在 HTML 寫事件,那你對於 Vue 提供的事件語法應該會很熟悉。

<div onclick="functionToExecute()"></div>

基礎語法結構會是: v-on:[事件名稱] ,例如 v-on:click="func()"v-on:keydown="func()"
v-on 四個字元太多字,也可以把這四個字省略成 @。 例如 @click="func()"@keydown="func()"

在模板上看起來會長這樣:

<button @click="plus()">+</button>

事件的參數

說到事件,不得不提到事件的參數,在 方法 的篇章已經有聊到 v-on 指令常會搭配 「方法」一起使用。

當時沒有講到的是, v-on 綁定的 method 支援一個特殊的參數 $event,可以讓我們取得事件的 event 物件。

這個物件在傳統 JS 來說可能會寫個 e 來接這個參數,像這樣:

const $btn = document.getElementById("btn");
$btn.addEventListener("click", function (e) {
  console.log(e);
});

而如果是 v-on 指令,則可以這樣寫:

<div id="app">
  <!-- 一定要是 $event 不能是其他值  -->
  <a href="https://google.com.tw" @click="plus($event)">{{data}}</a>
</div>
Vue.createApp({
  setup() {
    const data = Vue.ref(0);
    const plus = (e) => {
      //模板有寫 $event 這裡就能抓到了
      e.preventDefault();
      data.value++;
    };
    return { data, plus };
  },
}).mount("#app");

不過如果方法中需要帶其他參數,就要記得,模板寫的參數位置,跟方法中的參數位置必須一樣:

<div id="app">
  <!-- 因為在實體中寫的參數,第一個是接「事件參數」,第二個是某個資料值,所以兩者順序不能換 -->
  <a href="https://google.com.tw" @click="plus($event , 5)">{{data}}</a>
</div>
Vue.createApp({
  setup() {
    const data = Vue.ref(0);
    const plus = (e, value) => {
      //模板有寫 $event 這裡就能抓到了
      e.preventDefault();
      data.value = value;
    };
    return { data, plus };
  },
}).mount("#app");

修飾子

常見通用修飾子

針對一些特殊的事件操作,Vue 支援一些特殊的修飾子。

.stop
.prevent
.capture
.self
.once

一個一個來介紹

.stop

他就是 .stopPropagation() ,阻擋事件冒泡用的。

我們都像是這種 HTML 結構,如果在 .inner 綁點擊事件,點了他之後,同時也會讓 .outer 也觸發點擊事件。
一般我們就會使用 e.stopPropagation() 來阻擋事件冒泡。

<div class="outer">
  這是外面
  <div class="inner">這是裡面</div>
</div>

因為很常用,所以 Vue 提供了 .stop 語法糖讓我們使用,用法就是直接在 event 名稱接 .stop 即可。

<div id="app">
  <div class="outer" @click="console.log('outer')">
    這是外面
    <div class="inner" @click.self="console.log('inner')">這是裡面</div>
  </div>
</div>

.prevent

如果你懂 JS ,可能也不用多說什麼了,這個修飾子就是 e.preventDefault() ,阻擋預設行為用的。

例如上面在講 $event 的範例,methods 接了 a 標籤的點擊事件後,做了 e.preventDefault() 的行為。

事實上在 Vue 中可以直接這樣寫:

<a href="https://google.com.tw" @click.prevent="console.log('hello!!!')"
  >點我啊</a
>

而且 Vue 的事件就像 jQuery 語法一樣,是可以接續著寫下去的:

<a href="https://google.com.tw" @click.stop.prevent="console.log('hello!!!')"
  >點我啊</a
>

.capture

我們再把這個結構請出來用:

<div class="outer">
  這是外面
  <div class="inner">這是裡面</div>
</div>

一般來說,如果沒有做任何設定,點擊 inner 時,會先觸發 inner 的 click ,才會觸發 outer 的 click 事件。
這是預設的 JS 事件冒泡的機制。

不過如果我們在「外層」加一個 .capture,那整個操作行為就會反過來,變成先觸發 outer ,才觸發 inner

<div class="outer" @click.capture="console.log("hello!")">
    這是外面
    <div class="inner"  @click="console.log('裡面!')">
        這是裡面
    </div>
</div>

.self

self 中文是 :自己。

所以當事件加上這個修飾子,就會限定只點自己才有效。

剛剛在 .stop 的地方有講到事件冒泡,點擊內層結構也會觸發外層結構的事件。

以常見的「燈箱效果」來說,如果這個結構是一個燈箱效果,外面那層是整個黑幕,裡面才是實際的燈箱,當燈箱跳出來的時候,我們希望點擊黑幕才觸發關閉事件,點到內容不做任何事,那我們就可以直接在外面那層加上 .self

<div class="outer">
  這是外面
  <div class="inner">這是裡面</div>
</div>

好啦...我知道我說得很清楚,你卻聽得很模糊,直接進去看程式,試試看把 .self 拿掉,打開燈箱,然後點點看「這是裡面」,看會有什麼變化吧。

可能有人會把 .self 跟 .stop 搞混,會以為 在內層設定 .self 可以阻止冒泡。
這裡必須強調 .self 不是拿來阻止冒泡行為的!!!!

.once

這個就跟 v-once 的概念很像, v-once 是資料綁到 模板 之後,資料怎麼更動後都不會再重新渲染。
.once 修飾子,就是讓事件只觸發一次,然後就不會再有然後了。

.oncev-once 不太一樣的地方是,之前講 v-once 的時候,示範畫面沒有異動,但資料還是有被異動。

不過 .once 控制的是「事件」,換言之是讓那個 function 只觸發一次,所以如果裡面有改動資料,就也只會改動那一次,之後怎麼執行事件,事件的函式就是不會再執行。

<div id="app">
  <button @click.once="plus()">{{count}}</button>
</div>
Vue.createApp({
  setup() {
    const count = Vue.ref(0);
    const plus = () => {
      count.value++;
      console.log(count.value);
    };
    return { count, plus };
  },
}).mount("#app");

鍵盤類型修飾子

除了通用修飾子,針對鍵盤, Vue 也提供一些不錯用的修飾子

例如執行 @keydown 事件時,只想讓 enter 鍵才執行某個行為,則可以寫

<div @keydown.enter="console.log('enter')"></div>

其他常見的還有這些:

.enter
.tab
.delete
.esc
.space
.ctrl
.shift

上一篇
我的 Vue.js 筆記(14) - 指令:v-bind
下一篇
我的 Vue.js 筆記(16) - 指令:v-model
系列文
這是我的 Vue.js 筆記,不知道有沒有機會幫到你30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言