跳至主要内容

70 篇文章 含有標籤「frontend engineer」

檢視所有標籤

EventSource API in JavaScript 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在現代的網頁應用程式中,實時性資料更新是一個常見需求,例如即時通知、股價更新、聊天室訊息、伺服器狀態監控等。傳統上,開發者可能會透過輪詢(Polling)或 WebSocket 來實現。然而,若只是單向由伺服器推送訊息到瀏覽器端,其實有更簡單且高效的選擇:EventSource API

EventSource 基於 Server-Sent Events(SSE),由伺服器主動推送文字資料到客戶端,並且使用 HTTP 協議的持久連線,開發上比 WebSocket 更簡單,適合事件流的場景。本文將帶我們快速入門 EventSource API,理解它的特性與應用方式。


重點摘要

  1. EventSource 與 SSE 的核心概念

    • EventSource 是瀏覽器提供的 JavaScript API,用於接收伺服器推送的 SSE(Server-Sent Events)。
    • 採用 HTTP 長連線,不需要 WebSocket,也不需要額外協議。
    • 支援自動重連(瀏覽器會自動在連線中斷時重新連接伺服器)。
  2. EventSource 的適用場景

    • 即時通知(系統提醒、訊息推送)
    • 資料更新(股價、天氣、賽事比分)
    • 記錄串流(伺服器日誌、事件追蹤)
    • 聊天室訊息(單向推送)
  3. EventSource 的特性

    • 單向通訊:伺服器 → 客戶端
    • 自動重連機制(可透過伺服器端 retry: 指令調整重試時間)
    • 基於純文字的事件格式(MIME type 為 text/event-stream
    • 可透過自訂事件名稱分發不同事件
  4. 與其他技術比較

    • Polling:需要客戶端頻繁請求,耗費頻寬與伺服器資源。
    • WebSocket:雙向溝通更靈活,但需要額外處理協議與狀態管理。
    • EventSource(SSE):單向推送即可,實作簡單、輕量化,適合多數即時通知場景。

EventSource 使用範例

1. 瀏覽器端(JavaScript)

// 建立 EventSource 連線
const eventSource = new EventSource('/events');

// 接收預設訊息(message 事件)
eventSource.onmessage = function (event) {
console.log('收到訊息:', event.data);
};

// 接收自訂事件
eventSource.addEventListener('news', function (event) {
console.log('收到新聞事件:', event.data);
});

// 監控錯誤與連線狀態
eventSource.onerror = function (error) {
console.error('EventSource 發生錯誤:', error);
};

2. 伺服器端(Node.js Express 範例)

const express = require('express');
const app = express();

app.get('/events', (req, res) => {
// 設定 SSE 必要的 Header
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

// 每隔 3 秒推送一個訊息
const intervalId = setInterval(() => {
const data = new Date().toLocaleTimeString();
res.write(`data: 現在時間 ${data}\n\n`);
}, 3000);

// 當客戶端中斷連線時清理資源
req.on('close', () => {
clearInterval(intervalId);
});
});

app.listen(3000, () => {
console.log('SSE 伺服器運行於 http://localhost:3000/events');
});

3. SSE 資料格式範例

伺服器回傳的資料需符合 text/event-stream 格式,每筆訊息以兩個換行結尾。

data: 這是一個預設訊息

event: news
data: 這是一個新聞更新

event: alert
data: 系統警告訊息
retry: 5000

說明:

  • data::主要訊息內容,可以有多行。
  • event::指定自訂事件名稱,客戶端可用 addEventListener 監聽。
  • retry::定義自動重連的延遲時間(毫秒)。

注意事項

  1. 瀏覽器支援性:大部分現代瀏覽器支援 EventSource(IE 除外)。
  2. 跨域問題:若伺服器與前端不同網域,需設定 CORS。
  3. 資料格式:僅支援 UTF-8 文字資料,若要傳送二進位資料需轉成 Base64 或 JSON。
  4. 連線數限制:部分瀏覽器對同一網域的 SSE 連線數有限制(通常 6 條)。
  5. 斷線重連:內建自動重連機制,但若伺服器返回錯誤狀態碼,可能需手動處理。

總結

EventSource API 提供了一個簡單又高效的方式,讓前端應用程式能夠輕鬆接收伺服器的即時推送。相較於 WebSocket,EventSource 不需要額外的協議處理,也避免了頻繁輪詢帶來的效能浪費。在僅需單向資料更新的場景下,它是一個理想解決方案。

當我們下次需要在前端實現即時通知、動態更新數據或流式資料顯示時,不妨先考慮 EventSource,它或許就是最輕量的選擇。

JavaScript 模組系統:CommonJS 與 AMD 入門教學 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在 JavaScript 早期,所有程式碼通常寫在單一文件中,這樣的方式在小型專案中或許可行,但當應用程式變得更大、更複雜時,這種結構會導致管理困難。因此,模組化的概念被引入,允許開發者將程式碼拆分成可重複使用的獨立部分,提高可維護性與擴展性。

在 ES6 標準推出之前,JavaScript 主要依賴 CommonJS(CJS)Asynchronous Module Definition(AMD) 來實現模組化。這兩種模組系統有不同的設計理念與應用場景,以下將詳細介紹其特性與實作方式。


1. CommonJS(CJS)—— Node.js 的標準模組系統

概述

CommonJSNode.js 所採用,主要用於伺服器端開發。它的核心概念是 同步載入(Synchronous Loading),這意味著模組在執行時會逐步載入,而不是並行載入。

CommonJS 主要透過 require() 來載入模組,並使用 module.exportsexports 來匯出模組內容。

CommonJS 語法

(1) 定義模組(匯出)

// math.js
const pi = 3.14159;

function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

// 匯出模組
module.exports = {
pi,
add,
subtract
};

(2) 使用模組(載入)

// main.js
const math = require('./math');

console.log(math.pi); // 3.14159
console.log(math.add(10, 5)); // 15
console.log(math.subtract(20, 8)); // 12

CommonJS 特點

優點: 適用於伺服器端(Node.js),可輕鬆管理模組與依賴。
簡單直覺的 require()module.exports 語法
支援循環依賴(Circular Dependencies),當兩個模組互相依賴時,仍能正確解析。

缺點: 同步載入(Synchronous Loading),不適合瀏覽器端,因為會阻塞執行緒,影響頁面效能。
不支援瀏覽器環境,需使用 Webpack 或 Browserify 來轉換為瀏覽器可用的程式碼。


2. AMD(Asynchronous Module Definition)—— 適用於瀏覽器的模組系統

概述

AMD 是專為 瀏覽器環境 設計的模組系統,解決了 CommonJS 無法在前端環境直接運作的問題。AMD 的關鍵特點是 非同步載入(Asynchronous Loading),允許模組在需要時才載入,避免影響頁面效能。

AMD 主要使用 define() 來定義模組,require() 來載入模組。

AMD 語法

(1) 定義模組(匯出)

// math.js
define([], function () {
const pi = 3.14159;

function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

return {
pi,
add,
subtract
};
});

(2) 使用模組(載入)

// main.js
require(['math'], function (math) {
console.log(math.pi); // 3.14159
console.log(math.add(5, 6)); // 11
});

AMD 特點

優點: 適用於瀏覽器環境,支援非同步載入,提高效能。
使用 define()require() 來管理模組,能夠載入多個依賴。
非同步執行,適合大型應用程式,減少載入時間。

缺點: 語法較繁瑣,比 CommonJS 需要更多設定。
需要 RequireJS 來執行,瀏覽器無法直接支援 AMD。


3. CommonJS vs AMD vs ES Modules(ESM)

特性CommonJS(CJS)AMDES Modules(ESM)
適用環境Node.js瀏覽器瀏覽器 & Node.js
載入方式require()require()import/export
同步/非同步同步(Synchronous)非同步(Asynchronous)靜態解析(Static)
優勢簡單易用,適合伺服器端適用瀏覽器,非同步載入現代標準,支援 Tree Shaking
限制不適合瀏覽器需要 RequireJS需要 ES6 瀏覽器或 Node.js 12+

4. CommonJS 與 AMD 的使用時機

  • 當開發伺服器端應用程式時,建議使用 CommonJS,因為它與 Node.js 相容性最佳。
  • 當開發前端應用時,AMD 是一種選擇,但目前更推薦使用 ES Modules(ESM)
  • 現代 JavaScript 建議使用 ES Modules(import/export),因為它已經成為標準,並且同時支援瀏覽器與 Node.js 環境。

5. 結論

在 JavaScript 模組化的歷史發展中,CommonJS 被廣泛用於 伺服器端,而 AMD 則主要針對 瀏覽器環境 設計。隨著 ES6 的 ES Modules(ESM)標準化,許多開發者已經轉向 ESM,因為它在語法上更直覺,並且可以同時適用於前端與後端。

雖然 CommonJS 和 AMD 仍然在某些專案中使用,但未來趨勢將逐漸轉向 ES Modules。因此,對於新專案,建議 優先使用 ES Modules(import/export),而對於舊專案或特定環境(如 Node.js 早期版本),仍可能需要使用 CommonJS 或 AMD。

JavaScript 模組(Module)入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

1. 什麼是 JavaScript 模組?

JavaScript 模組(Module)是一種將程式碼拆分成多個獨立文件,並在不同文件間共享和管理程式碼的方式。透過模組化的設計,可以讓程式碼更具結構性、可讀性與可維護性。

在 ES6(ECMAScript 2015)之前,JavaScript 主要透過 IIFE(立即執行函式)、CommonJS 或 AMD 來模組化程式碼。而 ES6 之後,JavaScript 原生支援 ES Modules(ESM),提供 importexport 來管理模組。


2. 為什麼需要模組?

  1. 避免全域變數污染
    • 模組能夠封裝變數,避免不同程式碼區塊互相影響。
  2. 提高可維護性
    • 讓程式碼結構更清晰,拆分不同的功能至獨立文件中。
  3. 支援程式碼重用
    • 可在多個專案中共享相同的模組,避免重複開發。
  4. 支援延遲載入(Lazy Loading)
    • 透過動態 import(),按需載入模組,提高效能。

3. ES6 模組語法

在 ES6 中,我們主要使用 exportimport 來定義和載入模組。

(1) export 的使用

命名匯出(Named Export)

// math.js
export const pi = 3.14159;
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}

預設匯出(Default Export)

// greeting.js
export default function sayHello(name) {
return `Hello, ${name}!`;
}

(2) import 的使用

匯入命名匯出

// main.js
import { pi, add, subtract } from "./math.js";

console.log(pi); // 3.14159
console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6

匯入預設匯出

// main.js
import sayHello from "./greeting.js";

console.log(sayHello("Alice")); // "Hello, Alice!"

匯入所有模組內容

// main.js
import * as math from "./math.js";

console.log(math.pi); // 3.14159
console.log(math.add(2, 3)); // 5

使用 as 重新命名

import { add as sum, subtract as minus } from "./math.js";

console.log(sum(10, 5)); // 15
console.log(minus(10, 5)); // 5

4. ES 模組的特性

  1. 靜態解析(Static Analysis)

    • importexport 必須在頂層作用域,不能在條件語句或函式內部。
    • 在編譯時(compile time)解析模組,而不是執行時(runtime)。
  2. 模組作用域

    • 每個模組都有自己的作用域,變數不會污染全域作用域。
  3. 自動使用嚴格模式(Strict Mode)

    • ES6 模組內部自動啟用 "use strict",無需手動指定。

5. 動態載入模組

有時候我們希望在特定條件下載入模組,而不是在程式開始時就載入所有模組。這時可以使用 import() 來動態載入。

if (true) {
import("./math.js").then((math) => {
console.log(math.add(5, 10)); // 15
});
}
  • import() 回傳一個 Promise,當模組載入完成後執行回調函式。
  • 這種方式適合懶加載(Lazy Loading)與條件性載入。

6. varlet 在模組中的行為

在模組內,變數 var 仍然會被提升(Hoisting),但 letconst 具有區塊作用域。

// module.js
var globalVar = "I am global";
let localVar = "I am local";
// main.js
import "./module.js";

console.log(globalVar); // "I am global" (因為 var 會提升到全域)
console.log(localVar); // ReferenceError: localVar is not defined

7. 在瀏覽器與 Node.js 環境使用 ES 模組

(1) 瀏覽器

在 HTML 文件中,使用 <script type="module"> 來載入 ES6 模組。

<script type="module">
import { add } from "./math.js";
console.log(add(10, 5));
</script>

(2) Node.js

Node.js 14+ 版本支援 ES 模組,但需要:

  • 檔案副檔名改為 .mjs
  • package.json 設定 "type": "module"
{
"type": "module"
}
// math.mjs
export function multiply(a, b) {
return a * b;
}
// main.mjs
import { multiply } from "./math.mjs";
console.log(multiply(4, 5)); // 20

8. 模組引入方式整理

環境引入方式
瀏覽器(ESM)<script type="module">
Node.js(ESM)import { foo } from './module.mjs'
Node.js(CommonJS)const foo = require('./module.js')
動態載入(Lazy Load)import('./module.js').then(...)
重新命名import { foo as newFoo } from './module.js'
匯入所有內容import * as mod from './module.js'

9. 結論

  1. ES 模組是 JavaScript 原生模組系統,使用 importexport 來管理程式碼。
  2. 模組有助於提升可讀性與可維護性,避免全域變數污染。
  3. 動態載入(import())可以優化效能,適合延遲載入模組。
  4. 瀏覽器與 Node.js 都支援 ES6 模組,但 Node.js 需要 .mjspackage.json 設定 "type": "module"
  5. 模組可以透過不同方式引入,根據環境選擇適合的方法。

掌握 JavaScript 模組的概念,能夠讓你更有效地開發與維護大型專案。

MongoDB 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在現代應用程式開發中,資料儲存已不再侷限於傳統的關聯式資料庫(如 MySQL、PostgreSQL)。特別是在處理非結構化資料、需要高延展性或頻繁 schema 變動的應用場景中,NoSQL 資料庫逐漸成為主流選擇。

其中,MongoDB 是最受歡迎的 NoSQL 資料庫之一。它採用文件型(Document-Oriented)結構,使用 JSON 類型格式(實際為 BSON)儲存資料,讓開發者能更靈活地設計資料模型與操作資料。MongoDB 強調可擴展性、彈性資料結構與高效查詢能力,廣泛應用於 Web 開發、物聯網、大數據處理等領域。


重點摘要

  • MongoDB 是什麼?

    • 開源的 NoSQL 文件資料庫,使用 BSON 格式儲存資料。
    • 資料以「資料庫 → 集合(Collection)→ 文件(Document)」的層級組織。
    • 每個文件(Document)類似於 JSON 結構,支援巢狀資料與陣列。
  • 主要特性

    • 文件型資料儲存(更彈性且接近開發者熟悉的物件結構)
    • 無需預先定義 Schema,可動態變更欄位
    • 垂直與水平延展能力佳
    • 提供複寫與分片支援(Replica Set、Sharding)
    • 強大的查詢語言,支援索引、聚合、全文搜尋
  • 應用場景

    • RESTful API 後端儲存(如 Node.js + Express 專案)
    • 快速原型設計與資料模型測試
    • 高並發讀寫需求(例如留言板、商品評論系統)
    • 資料格式變動頻繁的場景(如 IoT 裝置紀錄)

安裝與啟動

1. 安裝 MongoDB(本機)

Mac 使用者(使用 Homebrew):

brew tap mongodb/brew
brew install mongodb-community@7.0
brew services start mongodb/brew/mongodb-community

Windows / Linux: 可前往 https://www.mongodb.com/try/download/community 下載對應版本。

2. 啟動 MongoDB

mongod

啟動成功後,預設會在 mongodb://localhost:27017 提供本地服務。

3. 開啟 Mongo Shell(或使用 MongoDB Compass GUI)

mongosh

進入後會看到互動式 shell 環境,開始操作你的資料庫。


MongoDB 基本操作(Shell 範例)

1. 建立 / 切換資料庫

use blog

2. 建立集合(Collection)與新增文件(Document)

db.posts.insertOne({
title: 'MongoDB 入門教學',
author: 'KD',
tags: ['database', 'nosql', 'mongodb'],
published: true,
created_at: new Date(),
});

插入文件時自動建立集合與資料庫。

3. 查詢文件

db.posts.find();
db.posts.find({ author: 'KD' });
db.posts.findOne({ published: true });

支援條件、邏輯查詢、排序、分頁等功能:

db.posts.find({ published: true }).sort({ created_at: -1 }).limit(5);

4. 更新文件

db.posts.updateOne({ title: 'MongoDB 入門教學' }, { $set: { published: false } });

支援 $set, $inc, $push, $unset 等更新操作符。

5. 刪除文件

db.posts.deleteOne({ title: 'MongoDB 入門教學' });

使用 Mongoose 操作(Node.js 範例)

在 Node.js 專案中,常使用 mongoose 封裝操作 MongoDB。

1. 安裝套件

npm install mongoose

2. 建立連線與定義模型

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/blog');

const postSchema = new mongoose.Schema({
title: String,
author: String,
tags: [String],
published: Boolean,
created_at: { type: Date, default: Date.now },
});

const Post = mongoose.model('Post', postSchema);

3. 實際使用範例

新增資料:

const newPost = new Post({
title: '用 Node.js 操作 MongoDB',
author: 'KD',
tags: ['nodejs', 'mongodb'],
published: true,
});

await newPost.save();

查詢資料:

const posts = await Post.find({ published: true }).limit(5);

更新資料:

await Post.updateOne({ title: '用 Node.js 操作 MongoDB' }, { published: false });

刪除資料:

await Post.deleteOne({ title: '用 Node.js 操作 MongoDB' });

聚合(Aggregation)入門

MongoDB 提供強大的 Aggregation Pipeline 功能,可進行統計、分組、轉換。

範例:統計作者貼文數量

db.posts.aggregate([{ $group: { _id: '$author', count: { $sum: 1 } } }, { $sort: { count: -1 } }]);

總結

MongoDB 以其彈性、易用與高延展性,成為許多現代應用的首選資料庫,特別是在快速開發、微服務架構或大數據處理場景中表現優異。透過簡單的 JSON 結構與強大的查詢能力,即使不熟 SQL 的開發者也能快速上手,打造穩定且具擴展性的資料儲存系統。

初學者可先從基本的增刪查改練習起,逐步熟悉資料結構與聚合操作,再延伸到使用 Mongoose 開發 REST API,或搭配 GraphQL、Next.js 等前後端整合工具,深入打造現代 Web 應用。

Node.js Express.js 入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

1. 簡介

Express.js 是一個基於 Node.js 的 Web 應用框架,提供簡潔且靈活的 API,適用於建立伺服器端應用程式。它可以用來開發 RESTful API、Web 應用或後端服務。

為什麼選擇 Express.js?

  • 輕量且易於學習
  • 擴展性高
  • 內建強大的中介軟體(Middleware)系統
  • 支援各種範本引擎(例如:EJS, Pug)

2. 安裝與專案初始化

安裝 Node.js

在開始使用 Express.js 之前,請先安裝 Node.js

初始化專案

建立一個新的專案資料夾,然後執行以下指令來初始化 Node.js 專案:

mkdir express-app
cd express-app
npm init -y

安裝 Express.js

npm install express

3. 建立第一個 Express 伺服器

建立 server.js 檔案,並加入以下程式碼:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send('Hello, Express!');
});

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});

啟動伺服器

node server.js

然後在瀏覽器打開 http://localhost:3000/,應該可以看到 Hello, Express!

4. 中介軟體(Middleware)

Express 提供 Middleware,可用來處理請求與回應,例如:解析請求體、驗證請求等。

使用 express.json() 解析 JSON

app.use(express.json());

建立自訂中介軟體

app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});

5. 路由(Routing)

Express 允許定義不同的 HTTP 方法對應不同的路由。

GET 路由

app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);
});

POST 路由

app.post('/api/users', (req, res) => {
const newUser = req.body;
res.status(201).json(newUser);
});

參數化路由

app.get('/api/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ id: userId, name: `User ${userId}` });
});

6. 靜態檔案服務

Express 可用來提供靜態檔案,例如 HTML、CSS、JavaScript。

app.use(express.static('public'));

然後在 public/index.html 中放入 HTML,即可直接透過 http://localhost:3000/index.html 存取。

7. 錯誤處理

Express 提供錯誤處理中介軟體,可用來處理應用中的錯誤。

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ message: 'Something went wrong!' });
});

8. 整合 MongoDB

可以使用 mongoose 來與 MongoDB 互動。

安裝 mongoose

npm install mongoose

連接 MongoDB

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Connected to MongoDB');
}).catch(err => {
console.error('MongoDB connection error:', err);
});

9. 部署 Express 應用

可以使用 PM2 來管理 Express 伺服器。

安裝 PM2

npm install -g pm2

啟動應用

pm2 start server.js --name express-app

10. 總結

透過這篇筆記,你已經學會:

  1. 安裝與初始化 Express.js
  2. 建立基本 Web 伺服器
  3. 使用中介軟體與路由
  4. 提供靜態檔案
  5. 錯誤處理
  6. 整合 MongoDB
  7. 部署 Express 應用

這些概念是 Express.js 開發的基礎,熟練後可以進一步學習 JWT 認證、WebSocket、GraphQL 等進階技術!

滾動視差(Parallax Scrolling)網頁設計入門教學筆記 | 學習筆記

· 閱讀時間約 5 分鐘
kdchang

滾動視差(Parallax Scrolling)是一種前端網頁設計技術,透過不同層的背景與內容以不同的速度滾動,營造出立體感與動態視覺效果。這種技術常見於品牌網站、產品介紹頁面或作品展示頁面,能有效提升使用者的沉浸感與互動體驗。

滾動視差的視覺效果

  1. 背景與內容滾動速率不同:背景滾動速度較慢,前景滾動速度較快,模擬景深效果。
  2. 多層次視覺變化:不同層的元素可以有獨立的滾動行為,增加動態感。
  3. 創造故事性:透過滾動觸發不同場景,讓使用者體驗連貫的視覺敘事。

二、滾動視差的基本實作

1. 使用純 CSS 來製作滾動視差

CSS 提供了 background-attachment: fixed; 屬性,可以讓背景圖像保持固定位置,而前景內容繼續滾動,營造簡單的滾動視差效果。

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>滾動視差示例</title>
<style>
body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}

.parallax {
background-image: url('parallax-background.jpg');
height: 100vh;
background-attachment: fixed;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}

.content {
height: 500px;
background-color: white;
text-align: center;
padding: 50px;
}
</style>
</head>
<body>

<div class="parallax"></div>

<div class="content">
<h2>滾動視差示例</h2>
<p>這是一個簡單的滾動視差網頁,背景固定不動,前景內容滾動。</p>
</div>

<div class="parallax"></div>

</body>
</html>

這種方式雖然簡單,但無法實現更複雜的視差動畫效果。如果想要更進階的效果,通常需要搭配 JavaScript 或 CSS 變形(Transform)。


2. 使用 CSS transform 來實現滾動視差

透過 transform: translateZ() 搭配 perspective(),可以製造出更立體的視差效果。

.parallax-container {
perspective: 1px;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
}

.parallax-layer {
position: absolute;
width: 100%;
transform: translateZ(-1px) scale(2);
}

這種方式可以讓不同層的元素有不同的滾動速率,達到更細緻的視覺效果。


三、使用 JavaScript 製作更靈活的滾動視差

雖然純 CSS 可以實現基本視差效果,但若要控制不同層級的滾動速度,或者添加額外動畫效果,就需要 JavaScript。

1. 簡單的 JavaScript 滾動視差

使用 window.scrollY 來控制元素的 transform 屬性,使其隨滾動變化。

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript 滾動視差</title>
<style>
body {
margin: 0;
font-family: Arial, sans-serif;
}
.parallax {
position: relative;
height: 100vh;
overflow: hidden;
background: url('parallax-background.jpg') center/cover no-repeat;
}
.text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 2rem;
color: white;
}
</style>
</head>
<body>

<div class="parallax">
<div class="text">滾動視差效果</div>
</div>

<script>
window.addEventListener('scroll', function() {
let scrollPosition = window.scrollY;
document.querySelector('.parallax').style.backgroundPositionY = scrollPosition * 0.5 + 'px';
});
</script>

</body>
</html>

在這個範例中,我們透過 JavaScript 讓背景圖片根據滾動位置改變 backgroundPositionY,從而達成視差效果。


2. 使用第三方函式庫(如 ScrollMagic)

如果想要更進階的視差效果,可以使用 ScrollMagic 這類 JavaScript 函式庫,來更精確地控制滾動動畫。

首先安裝 ScrollMagic:

npm install scrollmagic

然後在 JavaScript 中設定滾動觸發點:

let controller = new ScrollMagic.Controller();
let scene = new ScrollMagic.Scene({
triggerElement: '.parallax',
duration: '100%',
triggerHook: 0
})
.setTween('.parallax', { y: '50%', ease: Linear.easeNone })
.addTo(controller);

這樣可以讓 .parallax 元素在滾動時逐漸移動,達成視差效果。


四、滾動視差的應用場景

滾動視差可以應用於許多不同類型的網站,例如:

  1. 品牌網站:用來展示產品特性與公司理念,提高視覺吸引力。
  2. 作品集網站:適合攝影師、設計師,讓內容更具層次感。
  3. 故事敘述頁面:用來製作互動式故事,讓用戶在滾動中探索內容。
  4. 促銷與行銷頁面:讓特定區塊在滾動時突出,吸引目光。

五、滾動視差的優勢與缺點

優勢

  • 增強視覺吸引力,使網站更具互動性。
  • 可提升品牌形象,讓內容更具故事性。
  • 創造更流暢的使用者體驗,增加網站的停留時間。

缺點

  • 過多視差效果可能會影響效能,導致頁面滾動不流暢。
  • 可能對行動裝置不友善,需要額外的優化。
  • 過度使用可能會影響可讀性,降低使用者體驗。

六、結論

滾動視差是一種有效提升網站視覺吸引力的技術,適用於品牌展示、作品集與故事敘述類型的網站。透過 CSS 的 background-attachment,JavaScript 的 scrollY,或是使用函式庫如 ScrollMagic,都能實現不同程度的視差效果。

然而,使用時需注意效能與可讀性,確保不會影響使用者體驗。在實作時,建議先從簡單的 CSS 視差效果開始,逐步引入 JavaScript 或函式庫,根據需求選擇最佳實作方式。

TypeScript 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

TypeScript 是由 Microsoft 開發的 JavaScript 超集(Superset),提供靜態型別檢查(Static Type Checking),讓開發者在編譯時發現錯誤,提升程式碼的可靠性與可維護性。TypeScript 會被編譯為標準 JavaScript,並可以運行於任何支援 JavaScript 的環境,例如瀏覽器或 Node.js。

TypeScript 的主要特點

  1. 靜態型別檢查:在開發階段偵測類型錯誤,減少潛在錯誤。
  2. 強大的 IDE 支援:提供自動補全、型別推斷等功能,提高開發效率。
  3. 物件導向特性:支援類別(Class)、介面(Interface)、泛型(Generics)等功能。
  4. 相容 JavaScript:可以與現有的 JavaScript 程式碼共存,逐步導入 TypeScript。
  5. 模組化開發:支援 ES6+ 模組系統,便於管理大型應用程式。

二、安裝與設定 TypeScript

1. 安裝 TypeScript

可以使用 npm 來安裝 TypeScript:

npm install -g typescript

安裝完成後,可以使用以下指令來檢查 TypeScript 版本:

tsc -v

2. 初始化 TypeScript 專案

在專案目錄中執行以下指令,產生 tsconfig.json 設定檔:

tsc --init

這個設定檔可以調整 TypeScript 的編譯選項,例如輸出目錄、是否允許隱式 any 類型等。


三、基本語法

1. 變數與型別

TypeScript 透過 : 來指定變數的型別:

let name: string = 'Alice';
let age: number = 25;
let isStudent: boolean = true;

也可以使用 any 來允許變數接受任何型別:

let value: any = 'Hello';
value = 123; // 不會報錯

2. 陣列與元組

可以使用 type[] 來定義陣列型別:

let numbers: number[] = [1, 2, 3, 4];
let names: string[] = ['Alice', 'Bob'];

元組(Tuple)允許指定固定數量與型別的元素:

let person: [string, number] = ['Alice', 25];

3. 物件與介面

可以使用 interface 來定義物件的結構:

interface Person {
name: string;
age: number;
isStudent?: boolean; // 可選屬性
}

let user: Person = {
name: 'Alice',
age: 25,
};

4. 函式與型別

函式的參數與回傳值可以明確指定型別:

function add(a: number, b: number): number {
return a + b;
}

若函式沒有回傳值,可以使用 void

function logMessage(message: string): void {
console.log(message);
}

也可以使用箭頭函式語法:

const multiply = (a: number, b: number): number => a * b;

5. 型別別名(Type Alias)

type 關鍵字可以為型別取別名:

type ID = string | number;
let userId: ID = 123;

四、進階語法

1. Enum(列舉型別)

enum 允許定義一組具有特定名稱的數值:

enum Direction {
Up = 1,
Down,
Left,
Right,
}

let move: Direction = Direction.Up;

2. 泛型(Generics)

泛型允許函式或類別支援不同的型別,提高可重用性:

function identity<T>(value: T): T {
return value;
}

console.log(identity<string>('Hello'));
console.log(identity<number>(123));

泛型也可用於類別:

class Box<T> {
content: T;
constructor(value: T) {
this.content = value;
}
}

let stringBox = new Box<string>('TypeScript');
let numberBox = new Box<number>(100);

3. 類別與繼承

TypeScript 提供完整的類別支援,與 JavaScript ES6 類似:

class Person {
name: string;
constructor(name: string) {
this.name = name;
}
greet(): void {
console.log(`Hello, my name is ${this.name}`);
}
}

let alice = new Person('Alice');
alice.greet();

繼承類別:

class Student extends Person {
studentId: number;
constructor(name: string, studentId: number) {
super(name);
this.studentId = studentId;
}
}

let bob = new Student('Bob', 123);
bob.greet();

4. 非空斷言(Non-null Assertion)

可以使用 ! 來告訴 TypeScript 變數一定不會是 nullundefined

let value: string | null = 'Hello';
console.log(value!.length);

五、TypeScript 與 JavaScript 的比較

特性JavaScriptTypeScript
型別檢查靜態型別檢查
介面有介面與型別定義
類別與繼承ES6+ 支援支援完整 OOP
泛型支援泛型開發
Enum 列舉有內建 Enum
編譯時錯誤可提前檢查錯誤

六、TypeScript 專案開發

TypeScript 可與現代開發工具整合,如 Webpack、Babel 等。例如,在 React 或 Vue 開發中,可以使用 TypeScript 提供的型別檢查來提升程式碼質量。

在專案中安裝 TypeScript 相依套件:

npm install typescript @types/node --save-dev

若要搭配 React,則需安裝 @types/react@types/react-dom

npm install @types/react @types/react-dom --save-dev

七、總結

TypeScript 提供靜態型別檢查、模組化開發、泛型與完整的物件導向特性,使 JavaScript 程式碼更安全、可維護且容易擴展。透過與現有 JavaScript 相容的特性,可以逐步導入 TypeScript,提升專案的開發體驗與效能。在現代前端與後端開發中,TypeScript 已成為主流選擇之一。

Nuxt.js 入門教學筆記 | 學習筆記

· 閱讀時間約 5 分鐘
kdchang

Nuxt.js 是一個基於 Vue.js 的漸進式框架,專為構建伺服器端渲染(SSR)和靜態站點生成(SSG)應用程式而設計。它提供開發者一個強大的開發體驗,並簡化 Vue.js 應用的架構與設定,適合 SEO 優化、效能最佳化以及提升開發效率。

Nuxt.js 的核心特性包括:

  1. 伺服器端渲染(SSR):增強 SEO 並提升初始載入速度。
  2. 靜態站點生成(SSG):透過預先生成 HTML 提供更快的載入時間。
  3. 自動路由:基於 pages 目錄的檔案自動建立對應的路由,無需額外配置 Vue Router。
  4. 模組系統:支援大量 Nuxt 模組(如 TailwindCSS、PWA、Auth 等)來快速擴展功能。
  5. 組態簡單:預設優化 Vue.js 應用的結構與設定,減少繁瑣的配置工作。
  6. 組件自動載入:Nuxt 可自動載入 components 目錄內的 Vue 組件,減少 import 的需求。

二、安裝與初始化 Nuxt.js

1. 使用 Nuxt CLI 安裝(推薦方式)

Nuxt 提供官方 CLI 工具 nuxi 來建立新專案。

npx nuxi init my-nuxt-app
cd my-nuxt-app
npm install

上述指令會自動建立一個 my-nuxt-app 專案,並下載 Nuxt 相關相依套件。

2. 使用 create-nuxt-app 安裝(舊版方式)

如果要使用較舊的安裝方式,也可以透過 create-nuxt-app 指令來建立專案:

npx create-nuxt-app my-nuxt-app

此方法會提供互動式選單,讓開發者選擇 UI 框架(TailwindCSS、Bootstrap)、插件(Axios、PWA)以及 Nuxt 模式(SSR 或 SSG)。

3. 啟動開發伺服器

安裝完成後,可以執行以下指令來啟動開發環境:

npm run dev

預設會啟動本機伺服器 http://localhost:3000,可在瀏覽器中打開檢視。


三、專案結構

Nuxt.js 採用約定式(Convention over Configuration)架構,專案目錄結構如下:

my-nuxt-app/
│── assets/ # 未編譯的靜態資源,如 CSS、圖片
│── components/ # Vue 組件(自動載入)
│── layouts/ # 頁面佈局
│── pages/ # 自動建立的路由頁面
│── plugins/ # Nuxt 插件,如 Vue 插件或第三方庫
│── public/ # 靜態資源,可直接透過 URL 存取
│── server/ # 伺服器端 API(Nuxt 3)
│── store/ # Vuex 狀態管理(Nuxt 2,Nuxt 3 改用 `pinia`)
│── nuxt.config.ts # Nuxt 設定檔
│── package.json # npm 套件設定

四、路由與頁面

1. 自動建立路由

Nuxt.js 會根據 pages/ 目錄內的 Vue 檔案自動產生對應的路由。例如,在 pages/index.vue 建立首頁:

<template>
<div>
<h1>歡迎來到 Nuxt.js</h1>
</div>
</template>

若在 pages/about.vue 建立新的 Vue 檔案,則 http://localhost:3000/about 會自動對應到該頁面。

2. 動態路由

可以使用 _ 命名的方式建立動態路由。例如,在 pages/blog/_id.vue

<template>
<div>
<h1>文章 ID: {{ route.params.id }}</h1>
</div>
</template>

<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
</script>

訪問 http://localhost:3000/blog/123,頁面將顯示 文章 ID: 123


五、Nuxt 組件與佈局

1. 自動載入組件

components/ 內的 Vue 檔案會自動載入,例如建立 components/Navbar.vue

<template>
<nav class="bg-blue-500 p-4 text-white">
<h1>網站導覽列</h1>
</nav>
</template>

然後在 pages/index.vue 內直接使用 <Navbar />,無需 import

<template>
<div>
<Navbar />
<h1>首頁內容</h1>
</div>
</template>

2. 佈局(Layouts)

佈局是共享的頁面結構,可在 layouts/default.vue 內定義:

<template>
<div>
<Navbar />
<slot />
</div>
</template>

所有 pages/ 內的頁面會自動套用 default.vue 佈局。


六、Nuxt 伺服器端 API(Nuxt 3)

Nuxt 3 內建簡單的 API 伺服器,可在 server/api/hello.ts 新增 API:

export default defineEventHandler((event) => {
return { message: "Hello from Nuxt API" };
});

這樣就可以透過 http://localhost:3000/api/hello 訪問該 API。


七、Nuxt 資料獲取

1. useFetch() 獲取 API 資料

Nuxt 3 提供 useFetch 來處理 API 讀取,例如:

<template>
<div>
<h1>{{ data.message }}</h1>
</div>
</template>

<script setup>
const { data } = useFetch('/api/hello');
</script>

這會自動調用 server/api/hello.ts 並顯示回應內容。


八、部署 Nuxt 應用

1. 生成靜態站點

若要將 Nuxt 部署為靜態網站,可執行:

npm run build
npm run generate

這會在 dist/ 目錄內產生靜態 HTML 檔案,可直接部署到 Netlify 或 Vercel。

2. 部署至 Vercel

使用 Vercel CLI 部署:

npm install -g vercel
vercel

即可快速部署 Nuxt 應用。


九、結語

Nuxt.js 提供強大的功能來簡化 Vue.js 開發,透過自動路由、組件自動載入、伺服器 API 以及資料獲取等功能,大幅提升開發效率。對於需要 SEO 優化或靜態站點的專案而言,Nuxt 是一個非常適合的選擇。

Emotion CSS 入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

1. Emotion CSS 簡介

Emotion 是一款強大的 CSS-in-JS 解決方案,提供高效能且靈活的樣式管理方式,適用於 React 應用。Emotion 支援兩種主要的使用方式:

  1. CSS Prop(使用 JSX 內嵌樣式)
  2. styled API(使用 styled 函式創建元件)

2. 安裝 Emotion

使用 npm 或 yarn 安裝 Emotion 核心套件:

npm install @emotion/react @emotion/styled

如果專案使用 Babel,建議安裝 Emotion 的 Babel 插件來提高效能:

npm install --save-dev @emotion/babel-plugin

並在 .babelrc 中添加:

{
"plugins": ["@emotion"]
}

3. CSS Prop 用法

CSS Prop 允許你直接在 JSX 中定義 CSS 樣式。

基本範例

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';

const style = css`
background-color: lightblue;
padding: 20px;
border-radius: 8px;
`;

function App() {
return <div css={style}>Hello, Emotion!</div>;
}

export default App;

傳遞 props 變更樣式

const dynamicStyle = (color) => css`
background-color: ${color};
padding: 20px;
border-radius: 8px;
`;

function App({ color = 'lightblue' }) {
return <div css={dynamicStyle(color)}>Dynamic Emotion</div>;
}

4. styled API 用法

styled API 讓我們能夠創建具備 CSS 樣式的 React 元件。

基本範例

import styled from '@emotion/styled';

const Button = styled.button`
background-color: #3498db;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: #2980b9;
}
`;

function App() {
return <Button>Click Me</Button>;
}

export default App;

傳遞 props 變更樣式

const Button = styled.button`
background-color: ${(props) => props.bg || '#3498db'};
color: ${(props) => props.color || 'white'};
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: ${(props) => (props.bg ? darken(0.1, props.bg) : '#2980b9')};
}
`;

function App() {
return <Button bg="tomato">Custom Button</Button>;
}

5. 全域樣式與 Theme

使用 Global 樣式

import { Global, css } from '@emotion/react';

const globalStyles = css`
body {
margin: 0;
font-family: Arial, sans-serif;
}
`;

function App() {
return (
<>
<Global styles={globalStyles} />
<div>Hello, Global Emotion!</div>
</>
);
}

使用 Theme

import { ThemeProvider } from '@emotion/react';
import styled from '@emotion/styled';

const theme = {
colors: {
primary: '#3498db',
secondary: '#2ecc71'
}
};

const ThemedButton = styled.button`
background-color: ${(props) => props.theme.colors.primary};
color: white;
padding: 10px 20px;
border-radius: 5px;
`;

function App() {
return (
<ThemeProvider theme={theme}>
<ThemedButton>Themed Button</ThemedButton>
</ThemeProvider>
);
}

6. 總結

Emotion 是一款靈活且高效的 CSS-in-JS 解決方案,適用於 React 應用。它提供 css prop 以及 styled API 來幫助開發者管理樣式,並支援全域樣式與主題設定。這篇教學筆記涵蓋了基礎概念與常見用法,希望對你的開發過程有所幫助。

Tailwind CSS 入門教學筆記 | 學習筆記

· 閱讀時間約 5 分鐘
kdchang

Tailwind CSS 是一款以「工具類別優先」(Utility-First)為核心設計理念的 CSS 框架,與傳統的 CSS 框架(如 Bootstrap、Bulma)不同,它不提供預設的 UI 元件,而是提供大量的樣式工具類別,讓開發者可以快速組合來建構 UI,而不需要額外撰寫自訂 CSS。

相較於傳統 CSS 框架,Tailwind CSS 具有以下幾個主要優勢:

  1. 開發效率高:只需使用類別組合即可完成設計,無需撰寫額外 CSS。
  2. 高度可客製化:可以透過設定檔調整顏色、字型、間距等設計。
  3. 內建響應式支援:透過 sm: md: lg: xl: 等前綴輕鬆定義不同裝置的樣式。
  4. 一致性強:開發團隊可以統一使用 Tailwind CSS 定義的設計樣式,減少 UI 風格不一致的問題。
  5. 效能優化:可透過 PurgeCSS 移除未使用的樣式,確保最小化 CSS 檔案大小,提高網站載入速度。

二、安裝 Tailwind CSS

Tailwind CSS 可以透過多種方式安裝,以下介紹幾種常見的方法:

1. 使用 CDN(適合快速測試)

如果只是想快速體驗 Tailwind CSS,可以直接在 HTML 檔案中加入以下 <link>

<link href="https://cdn.jsdelivr.net/npm/tailwindcss@3.0.0/dist/tailwind.min.css" rel="stylesheet">

這種方式適合小型專案或測試 Tailwind CSS 的功能,但不適合正式開發,因為無法使用客製化設定。

2. 透過 npm 安裝(推薦方式)

在正式開發環境中,建議使用 npm 或 yarn 來安裝 Tailwind CSS,以便進行客製化設定。

安裝 Tailwind CSS

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

執行上述指令後,會在專案根目錄中產生 tailwind.config.js 設定檔,可用來調整 Tailwind 的預設樣式。

設定 Tailwind CSS

開啟 tailwind.config.js,找到 content 設定,確保 Tailwind 只處理專案內的相關檔案,例如:

module.exports = {
content: ["./src/**/*.{html,js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};

這樣 Tailwind CSS 就只會掃描 src 資料夾內的 HTML、JavaScript 和 TypeScript 檔案,避免產生不必要的 CSS。

引入 Tailwind 樣式

src/index.cssstyles.css 檔案中加入以下內容,讓 Tailwind CSS 套用基礎樣式:

@tailwind base;
@tailwind components;
@tailwind utilities;

最後,在開發環境中執行 Tailwind 編譯指令:

npx tailwindcss -i ./src/index.css -o ./dist/output.css --watch

這會自動監聽檔案變化,並輸出 Tailwind CSS 的樣式到 output.css


三、Tailwind CSS 常用類別

Tailwind CSS 提供大量的工具類別,以下介紹幾個常用的類別和應用範例。

1. 文字樣式

Tailwind 允許透過類別來快速調整字體大小、顏色、行距等樣式,例如:

<p class="text-lg font-bold text-gray-700 leading-relaxed">
這是一段示範文字
</p>

其中:

  • text-lg:字體大小
  • font-bold:加粗
  • text-gray-700:深灰色文字
  • leading-relaxed:行距較寬

2. 背景與邊框

可以使用背景色與邊框樣式來設計 UI,示例如下:

<div class="bg-blue-500 text-white p-4 rounded-lg shadow-lg">
Tailwind CSS 範例
</div>
  • bg-blue-500:藍色背景
  • text-white:白色文字
  • p-4:內距 16px
  • rounded-lg:圓角
  • shadow-lg:大型陰影

3. Flexbox 佈局

Tailwind CSS 提供完整的 Flexbox 工具類別,讓開發者能夠快速進行佈局:

<div class="flex items-center justify-between p-4 bg-gray-200">
<div>左側內容</div>
<div>右側內容</div>
</div>
  • flex:啟用 Flexbox
  • items-center:垂直置中
  • justify-between:左右對齊

4. Grid 佈局

使用 Grid 來建立多欄式佈局:

<div class="grid grid-cols-3 gap-4">
<div class="bg-red-200 p-4">1</div>
<div class="bg-green-200 p-4">2</div>
<div class="bg-blue-200 p-4">3</div>
</div>
  • grid:啟用 Grid
  • grid-cols-3:建立三欄
  • gap-4:欄間距

5. 響應式設計

Tailwind 內建響應式前綴,適用於不同裝置:

<div class="text-base md:text-lg lg:text-xl xl:text-2xl">
響應式字體大小
</div>
  • text-base:手機(預設)
  • md:text-lg:平板(min-width: 768px
  • lg:text-xl:筆電(min-width: 1024px
  • xl:text-2xl:桌機(min-width: 1280px

四、Tailwind CSS 進階功能

1. 自訂樣式

可以透過 tailwind.config.js 來擴充自訂樣式,例如新增顏色:

module.exports = {
theme: {
extend: {
colors: {
primary: "#1E40AF",
secondary: "#9333EA",
},
},
},
};

這樣就可以在 HTML 中使用 text-primarybg-secondary 來套用顏色。

2. 使用 @apply 簡化樣式

在 CSS 檔案中使用 @apply 來重複使用 Tailwind 類別:

.btn {
@apply bg-blue-500 text-white px-4 py-2 rounded;
}

然後在 HTML 中只需寫:

<button class="btn">按鈕</button>

五、總結

Tailwind CSS 透過工具類別的方式大幅提升開發效率,並提供響應式設計、靈活佈局與高度客製化的功能。對於前端開發者而言,熟悉 Tailwind CSS 可以讓 UI 設計更加直觀、高效,並減少對自訂 CSS 的依賴,進而提升開發維護性。