本篇文章為 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 標籤:
- div – 基本區塊
- span – 額外文字
- h4 – 小標題
- ul – 清單
- 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 開始培養前端開發的興趣。