iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0
Modern Web

了不起的 Svelte系列 第 16

第 16 天:Svelte 中的邏輯運作:`each` 邏輯區塊(一)

  • 分享至 

  • xImage
  •  

第 16 天:Svelte 中的邏輯運作:each 邏輯區塊(一)

「我的 each 邏輯區塊看起來真棒,不是嗎?」他徵詢我的意見。「看看它是如何將繁瑣的工作處理得如此簡潔漂亮。」
我同意這個 each 邏輯區塊的確厲害。
「沒錯。」他掃視著那些 each 邏輯區塊,從每一個開頭到每一個結尾,「我花了整整三年時間掙得的錢才賣下了它。」

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

第 16 天要講的是

  1. 在 HTML 當中使用 each 邏輯區塊

  系列文進行到這邊已經過一半了,回頭想想我們似乎學會了不少東西,但看看這個專案的目標:隨機色票產生器,好像還有好大一段路要走!?其實並沒有。今天就讓我們把色票的部分實作出來,並且學習使用 each 邏輯區塊吧。
  為了要實作色票的部分,考量到分工的情形,我們也另外準備一個 Svelte 元件 Palettes.svelte 來專門處理色票吧。這個 Svelte 元件的位置一樣是在 /src/lib/ 資料夾裡頭,內容我們就先這樣寫寫看:

/src/lib/Palettes.svelte
<script>
  import unlock from "../assets/unlock.svg";
  let palettes = ['ff4000', '32e6e3', '009fe9'];
</script>

<div class="palettes">

  <!-- 第一張色票 -->
  <div class="card">
    <div class="palette" style='background: #{palettes[0]}' />
    <div class="hex-code">
      <p>
        {palettes[0]}
      </p>
    </div>
    <div class="lock-icon">
      <img src={unlock} alt="color-unlocked" />
    </div>
  </div>

  <!-- 第二張色票 -->
  <div class="card">
    <div class="palette" style='background: #{palettes[1]}' />
    <div class="hex-code">
      <p>
        {palettes[1]}
      </p>
    </div>
    <div class="lock-icon">
      <img src={unlock} alt="color-unlocked" />
    </div>
  </div>

  <!-- 第三張色票 -->
  <div class="card">
    <div class="palette" style='background: #{palettes[2]}' />
    <div class="hex-code">
      <p>
        {palettes[2]}
      </p>
    </div>
    <div class="lock-icon">
      <img src={unlock} alt="color-unlocked" />
    </div>
  </div>
</div>

  而關於 Palettes.svelte CSS 的設定部分,程式碼放在文末附錄,這邊就先專注 Javascript 跟 HTML 的元素。

  • 第二行:import unlock from "../assets/unlock.svg";
      引入一個我們想要用的 svg 檔案。這是參考自 Font Awesome 當中代表解鎖這個意象的 SVG 圖檔。該檔案的出處可以參考這裡,而詳細內容請見文末附錄。

  • 第三行:let palettes = ['ff4000', '32e6e3', '009fe9'];
      宣告變數 palettes,將我們需要的色票 hex 色碼集合成一個陣列。

  • 第六行:<div class="palettes">
      將所有的色票放在這個 <div> 當中,作為色票容器 (container) 的一個 <div>

  • 第九行:<div class="card">
      每一張 <div class="card"> 代表一個顏色的色票。這是第一張色票,也就是 'ff4000'

  • 第十行:<div class="palette" style='background: #{palettes[0]}' />
      直接用 CSS 行內 (inline) 設定,將背景顏色藉由 style='background: #{palettes[0]}' 設定為第一張色票的顏色。

  • 第十三行:{palettes[0]}
      同時將 hex 色碼以文字的方式呈現出來。

  • 第二十二行:<div class="card">
      第二張色票,也就是 '32e6e3'

  • 第二十三行:<div class="palette" style='background: #{palettes[1]}' />
      直接用 CSS 行內 (inline) 設定,將背景顏色藉由 style='background: #{palettes[1]}' 設定為第二張色票的顏色。

  • 第二十六行:{palettes[1]}
      同時將 hex 色碼以文字的方式呈現出來。

  • 第三十五行:<div class="card">
      第三張色票,也就是 '009fe9'

  • 第三十六行:<div class="palette" style='background: #{palettes[2]}' />
      直接用 CSS 行內 (inline) 設定,將背景顏色藉由 style='background: #{palettes[2]}' 設定為第三張色票的顏色。

  • 第三十九行:{palettes[2]}
      同時將 hex 色碼以文字的方式呈現出來。

  並且在 App.svelte 引入這個熱騰騰剛出爐的 Palettes.svelte

/src/App.svelte
<!-- 在 Javascript 當中 import Counter -->
<script>
  import Counter from './lib/Counter.svelte';
  import Modal from './lib/Modal.svelte';
  import Palettes from './lib/Palettes.svelte';

  let count = 87;
  let showModal = false;

  let someState = 'TheGreatSvelte';
  const sparkle = (text) => {
    const sparkles = ['★', '☆', '✧', '✪'];
    const randomSparkles = () => sparkles[Math.floor(Math.random() * sparkles.length)];
    const sparkledText = text.split('').reduce((a, c) => a + randomSparkles() + c, '');
    return sparkledText;
  }

  const href = 'https://ithelp.ithome.com.tw/users/20120178/ironman/7031';

  const handleClick = (e) => {
    console.log(e);
    const tobeCount = count + e.detail;
    if (!(tobeCount > 87)) count = tobeCount;
    else showModal = true;
  }
</script>

<main>
  <!-- 在 HTML 當中直接嵌入 Counter -->
  <Counter {count} on:changeCount={handleClick}/>

  <Palettes />

  <p class='comment'>Check out <a {href}>Svelte Tutorial</a>, the awesome article powered by {sparkle(someState)}!</p>
</main>

<Modal {showModal} on:closeModal={() => showModal = false}/>
  • 第五行:import Palettes from './lib/Palettes.svelte';
      引入 Palettes.svelte

  • 第三十二行:<Palettes />
      使用 <Palettes />

https://ithelp.ithome.com.tw/upload/images/20231001/20120178GigOU1xZN2.png
圖一、色票出現啦!

  色票出現是出現了,但是回頭看看我們的 Palettes.svelte 這個檔案。在 HTML 的段落,我們寫下一大堆程式碼做出三張色票,實在是挺沒效率的。想想看,用這個方法也許可以做出三張色票,但色票的數目如果繼續增加,來到四張、五張、六張,甚至如果色票的數量是由使用者端的操作而動態改變的話呢?

在 HTML 當中使用 each 邏輯區塊

  看看 Palettes.svelte 的第三行程式碼:let palettes = ['ff4000', '32e6e3', '009fe9'];。我們已經把色票最重要的資料用 Javascript 的陣列 (Array) 表示出來了,想要根據這個陣列輕鬆做出多個色票,其實需要的只是一個跟 Javascript 陣列方法 mapforEach 類似的操作罷了。
  既然 Svelte 的編譯器能認我們在 HTML 段落中開啟 Javascript 的領域,那我們有沒有辦法將類似 Javascript 的邏輯施加在 HTML 元素上呢?
  都敢這麼問了,那麼答案肯定是有的。Svelte 提供我們 each 這樣的邏輯運作,讓我們能從 Javascript 的陣列變出一連串相關的 HTML 元素。就來看看要怎麼做吧:

{#each array as item}
  <!-- 請放入想要重複的模板 -->
{/each}
  • 第一行:{#each array as item}
      用 {#each} 開啟 each 運作邏輯,array 是代表 Javascript 陣列的變數,item 則是代表陣列當中各別項目的變數。

  • 第二行:<!-- 請放入想要重複的模板 -->
      開始撰寫我們需要的 HTML 模板。還記的我們可以用大括號 {} 在 HTML 當中展開 Javascript 的領域吧。這邊我們就可以用大括號 {} 將先前宣告的變數 item 拿來使用。

  • 第三行:{/each}
      用 {/each} 結束 each 的運作邏輯。

  沒錯就是這麼簡單。在 HTML 的段落中,用 {#each} 代表 each 運作邏輯的開頭,中間放入我們需要重複出現的 HTML 模板,最後用 {/each} 結束 each 運作邏輯。

  這樣講還是太抽象了嗎?那就讓我們實際在 Palettes.svelte 嘗試看看:

/src/lib/Palettes.svelte
<div class="palettes">

  <!-- 用 each 根據 palettes 這個陣列做出所有色票 -->
  {#each palettes as palette}
    <div class="card">
      <div class="palette" style='background: #{palette}' />
      <div class="hex-code">
        <p>
          {palette}
        </p>
      </div>
      <div class="lock-icon">
        <img src={unlock} alt="color-unlocked" />
      </div>
    </div>
  {/each}

</div>

  因為 Javascript 跟 CSS 的部分都沒有做修改,這邊就先略過,著重在 HTML 的部分。

  • 第一行:<div class="palettes">
      同樣放在這個 <div> 當中。

  • 第四行:{#each palettes as palette}
      用 {#each} 開啟 each 邏輯段落。其中 palettes 是我們在 Javascript 已經宣告過,代表不同顏色的陣列變數。而 palette 則是新宣告的變數,用來表示陣列當中的各別項目。這個新宣告的變數名稱怎麼取就看我們決定,就像使用 Javascript 的陣列方法 forEach 的習慣,我們也可以簡簡單單的取名為 x。這邊我們取個有意義、增加程式碼可讀性的,既然是代表 palettes 陣列當中的各別項目,那就取為 palette 吧。

  • 第六行:<div class="palette" style='background: #{palette}' />
      直接在 HTML 元素當中用大括號 {} 開啟 Javascript 的領域,並且放入新變數 palette

  • 第九行:{palette}
      同樣的,直接在 HTML 元素當中用大括號 {} 開啟 Javascript 的領域,並且放入新變數 palette

  • 第十六行:{/each}
      結束 each 的邏輯段落。

  這麼一來就完成了。重新看看我們的專案,是不是跟圖一慢慢刻出來的頁面長得一模一樣呢?

  當然,就像在 Javascript 的陣列方法 mapforEach 一樣,除了有最基本代表陣列各別項目的變數可以使用之外,我們也能夠在 {#each} 這個運作邏輯當中使用代表各個項目索引 (index) 的變數:

{#each array as item, index}
  <!-- 請放入想要重複的模板 -->
{/each}

  這就是今天關於 each 運作邏輯的介紹,相關的程式碼可以在 Github 資源庫找到。明天就讓我們繼續圍繞著 Svelte 提供的 each 邏輯段落,將我們需要的色票產生器一步一步打造出來吧。

附錄:Palettes.svelte

  這是今天 Palettes.svelte 最終的成果,包含 CSS 設定的部分:

/src/lib/Palettes.svelte
<script>
  import unlock from "../assets/unlock.svg";
  let palettes = ['ff4000', '32e6e3', '009fe9'];
</script>

<div class="palettes">

  <!-- 用 each 根據 palettes 這個陣列做出所有色票 -->
  {#each palettes as palette}
    <div class="card">
      <div class="palette" style='background: #{palette}' />
      <div class="hex-code">
        <p>
          {palette}
        </p>
      </div>
      <div class="lock-icon">
        <img src={unlock} alt="color-unlocked" />
      </div>
    </div>
  {/each}

</div>

<style>
  .palettes {
    margin: 1em;
    flex: 1;
    display: grid;
    gap: 0.5em;
  }

  .card {
    padding: 0.5em;
    background: var(--color-bg-3);
    border-radius: var(--border-radius);
    display: grid;
    grid-template-columns: 1fr 2fr 0.5fr;
    align-items: center;
  }

  .card .palette {
    height: 100%;
    border-radius: 0.2em;
  }

  .card .lock-icon {
    display: flex;
    width: 3em;
    height: 3em;
    padding: 0.7em;
    opacity: 0.3;
    cursor: pointer;
  }

  .card .lock-icon:hover {
    opacity: 0.5;
  }
</style>

附錄:unlock.svg

/src/assets/unlock.svg
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M144 144c0-44.2 35.8-80 80-80c31.9 0 59.4 18.6 72.3 45.7c7.6 16 26.7 22.8 42.6 15.2s22.8-26.7 15.2-42.6C331 33.7 281.5 0 224 0C144.5 0 80 64.5 80 144v48H64c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V256c0-35.3-28.7-64-64-64H144V144z"/></svg>

上一篇
第 15 天: Svelte 的事件:事件修飾(二)
下一篇
第 17 天:Svelte 中的邏輯運作:`each` 邏輯區塊(二)
系列文
了不起的 Svelte30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言