iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
Modern Web

了不起的 Svelte系列 第 14

第 14 天: Svelte 的事件:事件修飾(一)

  • 分享至 

  • xImage
  •  

第 14 天: Svelte 的事件:事件修飾(一)

「我將在今天向你提出一個莫大的請求,」他一邊說一邊心滿意足的用 modifier 修飾手邊的事件。「所以我希望你能夠真正認識我。我不希望你會認為我只是一個路人。你看,我總是將自己投向陌生人群,東飄西盪,為的只是讓我能夠忘記那些傷心事。」

~節錄自《The Great Svelte:第四章》

第 14 天要講的是

  1. Svelte 當中的事件修飾
  2. 簡介 HTML 的 <dialog> 元素

  昨天我們又掌握了更多在 Svelte 這個架構中傳遞事件的方法,今天繼續來討論事件。除了事件的傳遞之外,在某些特殊的狀況,我們反而可能希望事件不要傳遞,或是想要避免預設事件被觸發,或是希望事件只會觸發一次,等等不同的無理取鬧的要求。Svelte 想當然爾必須要配合這些任性的要求。但,究竟該怎麼做到呢?

Svelte 當中的事件修飾

  答案是透過事件修飾。在 Svelte 的架構中,我們用 on:eventName 來表示我們要接收選定的事件。用 ={eventHandler} 來設定事件處理器。用 |modifier 來對事件進行控制,或是對事件處理器的使用時機加上條件。完整的寫法是像這樣:

<element on:eventName|modifier={eventHandler} />

  修飾事件,就是指透過這個 modifier,來達成我們各種不尋常的要求:

  • preventDefault
      利用這個修飾詞,表示事件發生時,會先呼叫 event.preventDefault(),接著才由事件處理器進行處理。當我們在實作使用者介面的表格時,很實用的一個功能。

  • stopPropagation
      利用這個修飾詞來呼叫 event.stopPropagation,避免事件繼續往上傳遞到其他 HTML 元素。

  • once
      利用這個修飾詞,限制事件處理器只能運作一次。當事件被接收並透過事件處理器處理完成後,該事件處理器就會被移除。

  • self
      利用這個修飾詞,限制事件處理器只會處理發生自本身 HTML 元素的事件,也就是 event.target 必須是本身那個 HTML 元素,事件處理器才會進行處理。

  • trusted
      利用這個修飾詞,限制事件處理器只會處理透過使用者介面觸發的事件,而忽略那些用 Javascript 呼叫 dispatchEvent() 做出來的「虛擬」事件。也就是說只會處理 event.isTrustedtrue 的事件。

  當然如果想要的話,我們也可以在事件處理器上加入多個不同的修飾詞:

<element on:eventName|modifierA|modifier|…={eventHandler} />

  了解了事件修飾的用法跟語法之後,就讓我們在專案當中一邊實作一個互動視窗 (Modal),一邊練習使用事件修飾看看吧。

簡介 HTML 的 <dialog> 元素

  我們可以快速的利用 HTML 的 <dialog> 元素以及它所提供的功能快速做出一個互動視窗 (Modal)。一個互動視窗 (Modal) 最重要的就是兩個功能,【開啟】跟【關閉】。當互動視窗 (Modal)【開啟】時,使用者介面當中其他元素的功能都會被無效化,有點像是強迫使用者將注意力集中在眼前的互動視窗 (Modal) 的意思。建議的互動視窗 (Modal) 【開啟】方式,是透過 Javascript:

dialog.showModal();

  而要【關閉】互動視窗 (Modal),則可以透過按下 【Esc】鍵,或同樣透過 Javascript:

dialog.close();

  那麼讓我們在專案中加入一個互動視窗 (Modal) 看看吧。就像先前在第 06 天提過的,為了讓檔案分工清楚,我們也另外做出一個專屬於互動視窗的 Svelte 元件 Modal.svelte吧:

/src/lib/Modal.svelte
<script>
  let dialog;
  
  setTimeout(() => {
    dialog = document.querySelector('dialog');
    dialog.showModal();
  }, 1);

</script>

<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
<dialog>
  <!-- svelte-ignore a11y-no-static-element-interactions -->
  <div>
    <div class="title">
      <h2>Forbidden</h2>
      <small><em>adjective</em> for·bid·den \fər-ˈbi-dᵊn \</small>
    </div>

    <hr />
    <div class="content">
      <p>
        You have no privilidge to enter domain beyond 87. Please register
        as member so we can sent you some spam email.
      </p>
    </div>
    <hr />
    <!-- svelte-ignore a11y-autofocus -->
    <div class="footer">
      <button autofocus>close modal</button>
    </div>
  </div>
</dialog>
  • 第二行:let dialog;
      先宣告一個 dialog 變數,之後用來表示 HTML 的 <dialog> 元素。

  • 第五行:dialog = document.querySelector('dialog');
      用 document.querySelector('dialog') 將 HTML 的 <dialog> 元素用 Javascript 變數 dialog 來表示。注意到我們將這個動作利用 setTimeout() 設定在 Javascript 開始執行的 1 毫秒之後,原因是在 Svelte 當中,Javascript 開始執行時,我們的 HTML 元素還沒掛載好 。在之後的文章中,會介紹方法將這個看起來很彆扭的程式碼改寫得更乾淨。

  • 第六行:dialog.showModal();
      一拿到 <dialog> 這個元素,我們就用 showModal() 這個函式來開啟互動視窗 (Modal)。

  • 第十二行:<dialog>
      就是我們用來實作出的互動視窗的 <dialog> 本人。

https://ithelp.ithome.com.tw/upload/images/20230929/20120178tS6g3YDzEr.png
圖一、從互動視窗大聲呼喊「Forbidden」!

  今天關於事件修飾的初步介紹就到這邊了,我們明白事件修飾的語法,也知道怎麼在 Svelte 當中簡單做出一個互動視窗 (Modal)。但我們還沒真正讓互動視窗 (Modal) 動起來呢?沒關係,今天是中秋節,先祝大家月圓人團圓。剩下的內容就明天分曉囉。謝謝大家。

附錄

  完整的 Modal.svelte,包含 CSS 設定:

/src/lib/Modal.svelte
<script>
  let dialog;
  
  setTimeout(() => {
    dialog = document.querySelector('dialog');
    dialog.showModal();
  }, 1);

</script>

<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
<dialog>
  <!-- svelte-ignore a11y-no-static-element-interactions -->
  <div>
    <div class="title">
      <h2>Forbidden</h2>
      <small><em>adjective</em> for·bid·den \fər-ˈbi-dᵊn \</small>
    </div>

    <hr />
    <div class="content">
      <p>
        You have no privilidge to enter domain beyond 87. Please register
        as member so we can sent you some spam email.
      </p>
    </div>
    <hr />
    <!-- svelte-ignore a11y-autofocus -->
    <div class="footer">
      <button autofocus>close modal</button>
    </div>
  </div>
</dialog>

<style>
  dialog {
    color: var(--color-text);
    max-width: 20em;
    border-radius: 0.2em;
    border: none;
    padding: 2em;
    margin: auto;
    box-shadow: 0.5em 0.5em 1.5em rgba(0, 0, 0, 0.1),
      -0.5em -0.5em 1.5em rgba(0, 0, 0, 0.1);
  }
  dialog::backdrop {
    background: rgba(0, 0, 0, 0.4);
  }

  dialog > div > div {
    margin: 1em 0;
  }

  button {
    font-size: 1.1em;
    padding: 0.5em;
    border-radius: 0.2em;
    border: none;
    outline: none;
    cursor: pointer;
  }

  button:hover {
  filter: brightness(1.02);
  }
</style>

  此時的檔案架構:

C:.
│   .gitignore
│   index.html
│   jsconfig.json
│   package-lock.json
│   package.json
│   README.md
│   svelte.config.js
│   vite.config.js
│
├───.vscode
├───node_modules
├───public
│       vite.svg
│
└───src
    │   app.css
    │   App.svelte
    │   main.js
    │   vite-env.d.ts
    │
    ├───assets
    │       svelte.svg
    │
    └───lib
            Counter.svelte
            Modal.svelte

上一篇
第 13 天:Svelte 的事件:客製化事件
下一篇
第 15 天: Svelte 的事件:事件修飾(二)
系列文
了不起的 Svelte30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言