Svelte 教學,行事曆開發範例,如何與 WordPress 頁面整合

本篇文章為 Svelte 教學,以行事曆為開發範例,示範 Svelte 開發步驟,並說明如何在 WordPress 頁面中顯示。

最終成果請參考 2022 行事曆

什麼是 Svelte

根據 Stack Overflow 調查報告,Svelte 是 2021 最受歡迎的前端開發框架,State of JS 的 JavaScript 調查中,也被評為是最受喜愛和最滿意的 Web 框架,光這樣的調查結果就足夠讓人好奇。

Stack Overflow 的調查有提到,開發者體驗在近來是愈來愈重要,注意哦,是開發者體驗,不是使用者體驗,技術架構的開發體驗,對工程師來說,也是決定技術架構的因數之一,現在各大公司為了搶人才,也開始專注在開發者體驗,減少人才流失。

配給 MacBook 也能大大提升開發者體驗,真羨慕 MacBook 標配的公司。

如果大部分開發者都認為 Svelte 令他們滿意,那開發者體驗一定不差。

如果曾經使用過 vuejs,恭喜你,Svelte 對你來說非常容易,Svelte 的開發模式、程式寫法非常相似,但不知為何,使用 Svelte 真的比較開心,同樣的功能,Svelte 寫的程式碼比較少,對於頭腦的負擔也輕鬆很多。

你沒有注意到的重要指標~

程式碼要寫少一點!

– Rich Harris (Svelte 的作者)

不過程式碼的品質和數量,應該還是取決於開發者的能力。

Svelte 的基礎就是 HTML、CSS、JavaScript,是前端開發的根本,只要這三個基礎穩固,進入任何前端開發框架都不是問題。

要學習一門新的程式語言,或學習新的開發框架,親自動手寫個東西最有效果;過去的經驗也許可以加速瀏覽文件的速度,但還是比不上真的實際執行一次。

以下藉由開發一個簡單的行事曆元件,來了解 Svelte 的運作,從分析程式需要什麼功能開始,再來查詢文件探索 API,避免一開始就從頭到尾瀏覽文件,讀了很多,寫的太少。

Svelte 開發環境準備

直接開始啦,不要再介紹 Svelte 多好多好的。

以下使用 Macbook Air M1 操作,MacBook 的開發環境比 Windows 方便很多。

#1 安裝 node.js 開發環境

開啟終端機,執行下列指令(你用 Mac 應該有先裝 Homebrew 吧!)。

brew install node

Homebrew 是 macOS 的軟體管理工具,類似 Linux apt-get,Windows 可用 chocolatey 代替。

不管是不是開發者,都應該試試看 Homebrew,你是開發者那還等什麼。

#2 初始專案範本

npx degit sveltejs/template calendar

如上輸入執行指令,會新增一個名為 calendar 的目錄,目錄中已建立好需要的檔案。

如果你有 Visual Studio Code,直接開啟專案目錄。

cd calendar
code .

當然可以選擇其它文字編輯器,只是 Visual Studio Code,免費好用。

如果尚未安裝 Visual Studio Code,輸入以下指令執行即自動安裝。

brew install --cask visual-studio-code

#3 安裝依賴程式庫

在 calendar 目錄中執行:

npm install

如上輸入執行指令,安裝相關程式庫。

如果需要其它程式庫,就和 node 一樣,直接 npm install,例如以下的行事曆範例,需要用到 Ramda library

npm install ramda 

#4 啟動本機開發 Server

如下輸入指令執行,

npm run dev

開啟瀏覽器,輸入網址 http://localhost:8080。

看到大大的 HELLO WORLD!

那就是成功了。

行事曆程式設計範例

這個行事曆應該要能顯示 2022 一整年的日期,並能簡單標註週休二日和假日,最好還能標註一些特別日子。

就這樣先從簡單的功能開始,之後也許可以加上待辦清單、時間提醒等功能。

使用 HTML 描繪一整年的月曆結構,總共 12 個月,每個月份列出星期一到星期日,然後列出每個月份的日期。

使用 CSS 將 12 個月份分開,並依據畫面寬度,自動適應縮排顯示。月份的標題還有每個日期的顯示,都由 CSS 控制樣式。

使用政府 Open Data,取得行政機關辦公日曆表,在日曆中顯示放假日資訊,這個部分將利用 JavaScript 讀取 Open Data,讓資料整合在日期中,然後控制滑鼠游標,移到日期上面就顯示假期資訊。

開始囉,首先開啟 src/App.svelte 檔案,刪掉預設的程式碼,整理一下。

<script>
    // 這裡是寫 javascrpt 的地方   
</script>


// 從這裡開始寫 html,沒有 single root 的限制。
<div>

</div>


<style>
    // 這裡是寫 css 的地方
</style>

存檔看一下瀏覽器剛開啟的 Hello World 畫面,已經自動重新整理,一片空白,等待發揮想像力。

編寫 JavaScript 邏輯

政府資料開放平台取得今年的行事曆,請下載 JSON 格式,XML 也可以,但 JavaScript 處理 JSON 比較方便。

在同一個目錄儲存檔案 holiday.js,檔案內容稍微修改成:

module.exports = [
    { "date": "20220101", "week": "六", "isHoliday": "2", "note": "開國紀念日" },
    { "date": "20220102", "week": "日", "isHoliday": "2", "note": "" },
    { "date": "20220103", "week": "一", "isHoliday": "0", "note": "" },
    // 以下省略
]

因為是 JSON 文件的關係,我們之後可以自由依據需求,增加欄位定義,增加功能,非常方便。

將 JSON 文件改成 JavaScript Object 格式,再變成模組匯出,這樣就可方便在其它程式中讀取,再來準備幾個計算函式,方便 html 呼叫:

<script>
import * as R from 'ramda'
import t from './holiday.js'

// 今天
let currentDate = new Date();

// 今年
let year = currentDate.getFullYear();

// 格式化日期為 yyyyMMdd
const formatDate = (i, month) => `${year}${("0" + month).slice(-2)}${("0" + i).slice(-2)}`

// 格式化後的今天日期
const today = formatDate(currentDate.getDate(), currentDate.getMonth()+1)

/**
* 檢查傳入的日期是否為今天,是則回傳 “today”,給 css 設計樣式
* @param i 日期
* @param month 月份
*/
const isToday = (i , month) => {
    const date = formatDate(i, month)
    return date === today ? 'today' : ''
}

// 計算並回傳本月的最後一天
const calLastDay = (m) => {
    return new Date(year, m, 0).getDate();
}

// 計算本月的第一天是在星期幾
const calFirstDay = (m) => {    
    const day = [6,2,2,5,0,3,5,1,4,6,2,4]
	return (day[m-1] % 7 - 1) * 35;
}

// 取得日期的 css 樣式
const checkHoliday = (i, month) => {
    const date = formatDate(i, month)

    // 尋找 holiday 日期為 date 的那一筆物件。
    const info = R.find(R.propEq('date', date), t)

    if(info.note == '') // 沒有 note 的日期,顯示紅色假日或一般日
        return info.isHoliday == '2' ? 'holiday' : ''
    else {
        if(info.isHoliday == '1')
            return 'sad'
        else
            return 'special'
    }
}


// 從 holiday 取得指定日期的 note
const findTip = (i, month) => {
    const date = formatDate(i, month)
    const note = R.compose(
        R.prop('note'),
        R.find(R.propEq('date', date)),
    )(t)

    return note
}

</script>

規劃 HTML 結構

<div id="year">
    <!-- 使用 each 語法,總共 12 個 calendar div -->
    {#each {length: 12} as _, month}
    <div class="calendar">
        <div class="caption">  <!-- caption div,顯示各個月份的標題 -->
            <span class="previous"><</span>
            <h4>{month+1}月 {year} </h4>
            <span class="next">></span>
        </div>

        <ul class="week"> <!-- week 列出星期一到星期日 -->
            <li>日</li>
            <li>一</li>
            <li>二</li>
            <li>三</li>
            <li>四</li>
            <li>五</li>
            <li>六</li>
        </ul>

        <ul class="dates"> <!-- dates 顯示這個月的所有日期-->
            <li style="margin-left: {calFistDay(month+1)}px;"></li>

            {#each {length: calLastDay(month+1)} as _, i}
                <li class="{checkHoliday(i+1, month+1)} {findToday(i+1, month+1)}">
                    {i+1}
                    <span class="tooltiptext">{findTip(i+1, month+1)}</span>
                </li>
            {/each}
        </ul>
    </div>
    {/each}
</div>

完成這一段 html,只需幾個基本 html 標籤:

  1. div – 基本區塊
  2. span – 額外文字
  3. h4 – 小標題
  4. ul – 清單
  5. li – 清單內容

Svelte 的部分呢,只有兩個需要學:迴圈的語法,和如何顯示變數。

{#each {length: 5} as _, i} 
    {i}  <!-- 用迴圈顯示變數 i -->
{/each}

上面的程式的結果會顯示 0 1 2 3 4

each 語法官方說明在此
顯示變數就是把變數用大括號刮起來。

到這邊即已完成行事曆的功能部分,接下來是利用 CSS 讓行事曆變得好看一點。

CSS 樣式

<style>

/* reset css */
#year * {
    margin: 0;
    padding: 0;
    box-sizing: content-box;
    line-height: 2em;
}

/* 使用 flex 安排每個月份,最多一排三個月,自動適應寬度 */
#year {
    display: flex;
    justify-content: space-evenly;
    flex-wrap: wrap;
    gap: 1em;
    max-width: 960px;
    margin: 0 auto;
    padding: 1em;
}

/* 月份樣式,背景漸層顏色 */
.calendar {
    width: 245px;
    border: 1px solid gray;
    cursor: pointer;
    background-image: linear-gradient(180deg, #ffeb92 0%, #ffbbcf 100%);
}

/* 月份標題,利用 flex 自動分配間隔 */
.caption {
    padding: 0.5em;
    display: flex;
    justify-content: space-around;
}

/* 星期樣式,利用 flex 自動分配間隔 */
.week {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    border-bottom: 1px solid black;
}

/* 星期間隔設定為 35px */
ul.week > li {
    list-style: none;
    flex-basis: 35px;
    text-align: center;
}

/* 日期樣式,利用 flex 自動分配間隔和換行 */
.dates {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
}

/* 每個日期間隔一樣設定在 35px */
ul.dates > li {
    list-style: none;
    flex-basis: 35px;
    text-align: center;
    padding: 4px 0;
}

/* 假日的樣式,棕色底白色字 */
.holiday {
    position: relative;
    color: white;
    background-color: brown;
}

/* 特別日樣式,紅底白字 */
.special {
    position: relative;
    color: white;
    background-color: red;
}

/* 節日卻還是要上班的日子 */
.sad {
    position: relative;
    color: white;
    background-color: DarkGoldenrod;
}

/* 說明文字的位置,放在日期的上方 */
.tooltip {
    position: relative;
    display: inline-block;
    border-bottom: 1px dotted black;
}

/* 說明文字樣式 */
.tooltiptext {
    transition: opacity 0.2s;  
    opacity: 0;
    left: 0;
    color: #fff;
    text-align: center;
    border-radius: 6px;
    position: absolute;
    z-index: 1;
    top: -1.5em;
    white-space: nowrap;
    background-image: linear-gradient(45deg, #FF3CAC 0%, #784BA0 50%, #2B86C5 100%);
    pointer-events: none;
}

/* 滑鼠移到有說明文字的日期時,顯示說明 */
.special:hover .tooltiptext, .sad:hover .tooltiptext {
    opacity: 1;
}

/* 今天的樣式 */
.today {
    color:black;
    font-weight: bolder;
    background-color: #85FFBD;
    background-image: linear-gradient(45deg, #85FFBD 0%, #FFFB7D 100%);
}
</style>

加上 CSS 後,行事曆的樣子就顯現出來了,這個樣式只是個基礎,還可以加上各式各樣的設計。

唯一的限制,是你的想像力!(啊就是想不到會當工程師啊)

如何在 WordPress 頁面整合 Svelte

以上步驟即完成本機開發,那如果想要發佈在 WordPress 頁面,該如何做呢?

#1 執行打包

修改 src/main.js 程式如下

import App from './App.svelte';

const app = new App({
    target: document.getElementById('svelte'),  //指定行事曆的位置
});

export default app;

開啟終端機,到專案目錄中執行如下指令:

npm run build

執行 build script 會產生優化過的最終版本,檔案放在 /public/build 目錄 ~

我們只需要 build 目錄下面的檔案。

#2 上傳打包檔案

這邊使用 Hostinger 虛擬主機當操作範例,如果你使用的虛擬主機像是 NameHero 提供 cPanel,一樣有 File Manager 可以上傳檔案。

開啟虛擬主機的檔案管理功能,使用 FTP 上傳也行。

進入 wodpress 的 wp-content 目錄中,建立一個資料夾名為 calendar。

上傳前一步驟產生的完整 build 目錄。

#3 建立 WordPress 頁面

並非一定是頁面,Svelte 也可以放在文章 (Post) 中,或是網頁的任何地方。

在 WordPress 編輯器中選擇加入 Custom HTML。

在客製的 HTML 中輸入如下程式碼。

<div id="svelte"></div>
<link rel="stylesheet" href="/wp-content/calendar/build/bundle.css">
<script src="/wp-content/calendar/build/bundle.js"></script>

儲存測試,完成啦~點此看看實際上的效果

延伸學習

上述教學只需要基礎的網頁開發技能,只要會網頁開發,Svelte 就沒什麼問題。

你會發現上面的網頁開發,都是基礎的技術,Svelte 讓你的技術有更大的發揮。

Svelte 學習資源:官方教學
網頁開發學習資源:學習如何開發 WEB

如果從未接觸前端開發,可以藉由學習 Svelte 開始培養前端開發的興趣。