跳至主要内容

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

檢視所有標籤

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

· 閱讀時間約 3 分鐘
KD Chang
Builder, Curator & Lifelong Learner

在現代網頁開發中,動畫是一種強而有力的表現手法,能提升使用者體驗,使介面更加生動、有趣。相比 JavaScript,CSS Animation 提供一種更簡潔、性能更佳的動畫解法,尤其適合製作 UI 中的小型動畫效果。

本篇教學筆記將介紹 CSS Animation 的基本語法、常見屬性與一個實際範例,幫助你快速上手。


為什麼使用 CSS Animation?​

CSS Animation 的優點:

  1. 簡單易用:使用純 CSS 撰寫動畫,不需額外 JavaScript。
  2. 效能佳:瀏覽器針對 CSS Animation 做過優化,效能較好。
  3. 語意清楚:樣式與行為分離,程式碼結構清晰。

基本語法​

CSS 動畫的基本概念分為兩大部分:

  1. @keyframes:定義動畫的每個階段(狀態)
  2. 動畫屬性(如 animation-name、animation-duration 等):設定動畫的名稱、時間、重複次數等

1. 定義動畫步驟:@keyframes​

@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

也可以使用百分比表示中間過程:

@keyframes moveBox {
0% {
transform: translateX(0);
}
50% {
transform: translateX(100px);
}
100% {
transform: translateX(0);
}
}

2. 套用動畫屬性​

.box {
animation-name: fadeIn;
animation-duration: 1s;
animation-timing-function: ease-in-out;
animation-delay: 0s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}

也可以使用簡寫語法:

animation: fadeIn 1s ease-in-out 0s 1 forwards;

常見屬性說明​

屬性說明
animation-name對應的 @keyframes 名稱
animation-duration動畫持續時間(如 2s、500ms)
animation-delay動畫延遲時間
animation-iteration-count播放次數(數字或 infinite)
animation-direction播放方向(如 normal、reverse、alternate)
animation-timing-function動畫速度曲線(如 linear、ease、ease-in-out、cubic-bezier)
animation-fill-mode動畫結束後元素狀態(如 none、forwards、backwards、both)

實際範例:淡入移動效果​

HTML​

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Animation 入門範例</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="animated-box">Hello CSS Animation</div>
</body>
</html>

CSS(style.css)​

body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}

.animated-box {
padding: 20px 40px;
background-color: #4a90e2;
color: white;
font-size: 24px;
border-radius: 8px;
opacity: 0;
transform: translateY(30px);
animation: fadeSlideIn 1s ease-out forwards;
}

@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

效果說明​

當頁面載入時,.animated-box 元素會從下方淡入移動到原位。這種效果常用於元件出現時的動畫,例如:卡片載入、提示訊息出現等。


進階補充​

多個動畫階段​

可以使用百分比定義多個狀態:

@keyframes bounce {
0% { transform: translateY(0); }
30% { transform: translateY(-50px); }
50% { transform: translateY(0); }
70% { transform: translateY(-25px); }
100% { transform: translateY(0); }
}

搭配 hover 做互動動畫​

.button {
transition: transform 0.3s ease;
}

.button:hover {
transform: scale(1.1);
}

雖然這是使用 transition,但若需要更多控制,就可以改用 animation。


總結​

CSS Animation 提供一套簡潔的方式,能有效為網頁增添動態效果。適合使用在進場動畫、提示動畫、狀態變化等場合。若需求單純、動畫步驟不複雜,建議優先使用 CSS Animation 來取代 JavaScript,提升效能與維護性。

如果你剛開始學前端,建議從觀察現有網站的動畫效果出發,試著模仿並自己實作,會對 CSS Animation 有更深的理解。下一步你可以學習 transition、transform 與 cubic-bezier,讓動畫更自然、細緻。

Monorepo 入門教學筆記:使用 npm Workspaces 管理多專案 | 學習筆記

· 閱讀時間約 4 分鐘
KD Chang
Builder, Curator & Lifelong Learner

一、什麼是 Monorepo?​

Monorepo(Monolithic Repository) 是一種將多個相互關聯的專案(如前端、後端、共用函式庫等)統一放在同一個 Git 倉庫中進行版本管理的架構策略。這種做法可提升跨專案開發效率、共用程式碼的一致性,並簡化 CI/CD 流程。

相較於 Multi-repo(每個專案獨立倉庫),Monorepo 具有以下幾項優勢:

優點​

  • 統一依賴管理:使用者可於 root 層集中管理所有套件與版本。
  • 共用程式碼方便:子專案間可以引用彼此模組,而不需額外發佈。
  • 版本一致性高:統一管理 Node.js 與 TypeScript 設定,避免各專案設定不一致。
  • 原子性變更:可一次提交多個模組的改動,有利於大型重構與追蹤問題。

缺點​

  • 權限與管理更複雜:團隊需要良好的規範以避免耦合過深。
  • 初期學習門檻略高:需要理解 workspace 機制與設定方式。
  • 大型 repo 操作效能問題:隨專案規模增長,Git 操作與工具效能需特別注意。

二、何謂 npm Workspaces?​

從 npm 7 開始,Node.js 官方就原生支援 Workspaces。它允許開發者在單一專案下,透過一個 package.json 管理多個子專案(workspace packages)。這讓 npm 也能像 Yarn 或 pnpm 一樣支援 monorepo。

特點:

  • 原生支援,不需額外工具
  • 使用方式簡單直觀
  • 適合小型與中型 monorepo 專案

三、建立 Monorepo 專案實例(使用 npm workspaces)​

1. 初始化根目錄​

mkdir my-monorepo
cd my-monorepo
npm init -y

修改根目錄下的 package.json 加入 workspaces 設定:

{
"name": "my-monorepo",
"version": "1.0.0",
"private": true,
"workspaces": ["packages/*"]
}

這表示所有子專案會放在 packages/ 目錄中,支援通配符 *。


2. 建立三個子專案​

  • packages/utils:共用函式庫
  • packages/backend:Node.js API
  • packages/frontend:前端應用(可用 React/Vite)
mkdir -p packages/utils
mkdir -p packages/backend
mkdir -p packages/frontend

初始化子專案:

cd packages/utils
npm init -y

cd ../backend
npm init -y

cd ../frontend
npm init -y

3. 撰寫共用模組(utils)​

packages/utils/index.js:

function greet(name) {
return `Hello, ${name}`;
}

module.exports = { greet };

packages/utils/package.json:

{
"name": "@my/utils",
"version": "1.0.0",
"main": "index.js"
}

4. 使用共用模組於 backend​

packages/backend/index.js:

const { greet } = require("@my/utils");

console.log(greet("Backend"));

packages/backend/package.json 加入依賴:

{
"name": "@my/backend",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@my/utils": "1.0.0"
}
}

當你在 monorepo 根目錄執行:

npm install

npm 會自動建立 workspace 之間的 symbolic link,將 @my/utils 套件安裝給 @my/backend,無需手動 npm publish。

執行 backend:

node packages/backend/index.js

輸出結果為:

Hello, Backend

5. 多專案腳本管理​

在 root 的 package.json 中可設定統一指令:

{
"scripts": {
"start:backend": "npm --workspace @my/backend start",
"start:frontend": "npm --workspace @my/frontend start"
}
}

若在 @my/backend 的 package.json 中定義了:

{
"scripts": {
"start": "node index.js"
}
}

則可於根目錄執行:

npm run start:backend

四、進階使用技巧​

1. 同時執行所有 workspace 指令​

npm run build --workspaces

這會同時執行所有子專案中名為 build 的 script。

2. 安裝依賴給特定子專案​

npm install lodash --workspace @my/backend

等同於進到 packages/backend 下執行 npm install lodash。

3. 使用 TypeScript 建構共用型別​

若你使用 TypeScript,可將 packages/utils 改為 index.ts 並加上 types 欄位:

{
"name": "@my/utils",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts"
}

建議搭配 tsc -b 支援 project references,以改善大型專案建置效能。


五、適合使用 Monorepo 的情境​

  • 前後端一體化開發(Fullstack)
  • 套件開發與組合應用(如微前端架構)
  • 共用型別與邏輯模組(utility / types / domain model)
  • 多人協作、模組劃分清晰的大型產品

六、總結​

Monorepo 是一種有效提升多專案整合效率的開發模式。透過 npm Workspaces,你可以不用額外安裝任何工具,即可快速建立一個結構清晰的 monorepo。這種架構不僅適合大型產品團隊,也非常適合個人或小型團隊開發多模組系統時採用。

建議開發者從簡單的 monorepo 起步,並根據團隊需求逐步導入版本控制策略、模組邊界規範與自動化部署流程,以發揮 Monorepo 架構的最大價值。


若你有意將這份架構應用到 React、Next.js、NestJS、TypeScript、Lerna 等進階框架或部署情境,歡迎告訴我,我可以提供進一步的範例與最佳實踐建議。

React 與 Next.js 入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
KD Chang
Builder, Curator & Lifelong Learner

1. React 簡介​

React 是由 Facebook(現 Meta)開發的 JavaScript 前端函式庫,主要用於構建 UI 元件。它採用組件化開發方式,並透過 Virtual DOM 提升效能。

2. Next.js 簡介​

Next.js 是一個基於 React 的框架,提供伺服器端渲染(SSR)、靜態網站生成(SSG)等功能,讓開發者能夠更輕鬆地開發 SEO 友好的應用程式。

3. 安裝 Next.js​

使用 create-next-app 初始化 Next.js 專案:

npx create-next-app@latest my-next-app
cd my-next-app
npm run dev

這將會啟動開發伺服器,預設運行於 http://localhost:3000。

4. Next.js 核心概念​

4.1 頁面(Pages)​

Next.js 使用 pages/ 目錄來定義路由,每個 .js 或 .tsx 文件會自動成為一個頁面。

範例:pages/index.js

export default function Home() {
return <h1>歡迎來到 Next.js!</h1>;
}

新增 pages/about.js:

export default function About() {
return <h1>關於我們</h1>;
}

瀏覽 / 會載入 index.js,瀏覽 /about 會載入 about.js。

使用 next/link 來建立導航連結:

import Link from "next/link";

export default function Navbar() {
return (
<nav>
<Link href="/">首頁</Link> | <Link href="/about">關於</Link>
</nav>
);
}

4.3 頁面中的 props​

Next.js 支援 getServerSideProps(伺服器端渲染)和 getStaticProps(靜態生成)。

伺服器端渲染(SSR)​

export async function getServerSideProps() {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
return { props: { data } };
}

export default function Page({ data }) {
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

靜態生成(SSG)​

export async function getStaticProps() {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
return { props: { data } };
}

export default function Page({ data }) {
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

5. API 路由(API Routes)​

在 pages/api/ 目錄下建立 API 端點。

範例:pages/api/hello.js

export default function handler(req, res) {
res.status(200).json({ message: "Hello, API!" });
}

請求 /api/hello 會返回 JSON 資料。

6. 使用全域狀態管理(React Context)​

import { createContext, useContext, useState } from "react";

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}

export function useTheme() {
return useContext(ThemeContext);
}

在 _app.js 中使用 Provider:

import { ThemeProvider } from "../context/ThemeContext";

export default function MyApp({ Component, pageProps }) {
return (
<ThemeProvider>
<Component {...pageProps} />
</ThemeProvider>
);
}

在元件中存取狀態:

import { useTheme } from "../context/ThemeContext";

export default function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
切換主題(目前:{theme})
</button>
);
}

7. 總結​

Next.js 提供了比 React 更豐富的功能,如內建路由、伺服器端渲染(SSR)和 API 路由,適合開發高效能與 SEO 友好的網站。熟悉這些核心概念後,你可以更輕鬆地構建現代化的前端應用程式。

補充:可選搭配技術(實務常見)​

技術目的
Tailwind CSS快速開發 UI 樣式
Zustand/Redux全域狀態管理
NextAuth.js登入驗證(支援 Google, GitHub 等)
PrismaORM 操作 MySQL/PostgreSQL
React Query前端資料抓取與快取
shadcn/ui組件庫(Tailwind 美型元件)

Vue Router 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
KD Chang
Builder, Curator & Lifelong Learner

前言​

Vue Router 是 Vue.js 官方提供的前端路由解決方案,專為構建單頁應用(SPA, Single Page Application)而設計。它讓我們可以根據網址變化動態切換畫面而不重新載入頁面,是開發 Vue 應用不可或缺的工具之一。

本文將介紹 Vue Router 的基本概念、安裝方式、核心語法,並透過簡單實作幫助我們快速入門。


一、什麼是前端路由​

在傳統網頁架構中,網址的改變會導致瀏覽器重新向伺服器請求一個新的 HTML 頁面。但在 SPA 中,整個網站的內容是透過 JavaScript 管理畫面切換,網址改變時並不會重新載入整個頁面,而是由「前端路由器」來處理畫面更新。

Vue Router 就是 Vue 的前端路由器。


二、安裝 Vue Router​

在 Vue 3 專案中,可以透過以下指令安裝 Vue Router:

npm install vue-router@4

安裝完成後,在 src/router/index.js(或 router.ts)中建立路由設定。


三、基本使用範例​

1. 建立路由元件​

建立幾個簡單的元件:

// src/views/Home.vue
<template>
<h1>首頁</h1>
</template>

// src/views/About.vue
<template>
<h1>關於我們</h1>
</template>

2. 設定路由​

// src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
import About from "../views/About.vue";

const routes = [
{ path: "/", component: Home },
{ path: "/about", component: About },
];

const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;

3. 在 main.js 掛載路由​

// src/main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";

createApp(App).use(router).mount("#app");

4. 使用 <router-view> 顯示頁面​

<!-- src/App.vue -->
<template>
<div>
<h1>我的網站</h1>
<nav>
<router-link to="/">首頁</router-link>
|
<router-link to="/about">關於</router-link>
</nav>
<router-view></router-view>
</div>
</template>

<router-link> 是 Vue Router 提供的元件,用來建立不重新載入的內部連結。<router-view> 則是畫面會顯示對應元件的插槽。


四、動態路由參數​

可使用 :id 的方式定義動態參數:

// router/index.js
import User from "../views/User.vue";

const routes = [{ path: "/user/:id", component: User }];

在元件中取得參數:

<!-- views/User.vue -->
<template>
<div>使用者 ID:{{ $route.params.id }}</div>
</template>

五、巢狀路由​

當需要在某個頁面內部再切換子頁面時,可使用巢狀路由。

// router/index.js
import Dashboard from "../views/Dashboard.vue";
import Profile from "../views/Profile.vue";
import Settings from "../views/Settings.vue";

const routes = [
{
path: "/dashboard",
component: Dashboard,
children: [
{ path: "profile", component: Profile },
{ path: "settings", component: Settings },
],
},
];

在 Dashboard.vue 中放置 <router-view> 來呈現子路由內容:

<template>
<div>
<h2>儀表板</h2>
<router-link to="/dashboard/profile">個人資料</router-link>
<router-link to="/dashboard/settings">設定</router-link>
<router-view></router-view>
</div>
</template>

六、導覽守衛(Navigation Guard)​

我們可以用來保護某些頁面,例如使用者未登入不得進入:

// router/index.js
const router = createRouter({...})

router.beforeEach((to, from, next) => {
const isLoggedIn = false // 假設未登入
if (to.path === '/dashboard' && !isLoggedIn) {
next('/') // 導回首頁
} else {
next()
}
})

七、路由模式(Hash vs History)​

Vue Router 支援兩種模式:

  1. Hash 模式(預設): 網址含 #,如 /#/about,適用於靜態伺服器
  2. History 模式(推薦): 網址乾淨,需伺服器配合設定

選擇 History 模式時,需設定:

createRouter({
history: createWebHistory(),
routes,
});

若使用 Vite / Vue CLI,也需額外設定伺服器的 404 fallback。


八、程式化導航​

我們也可以在程式中使用 $router 導覽:

this.$router.push("/about");

或者使用命名路由與參數:

this.$router.push({ name: "user", params: { id: 123 } });

九、總結​

概念說明
<router-view>顯示當前路由對應的元件
<router-link>建立內部連結
$route取得當前路由資訊(如參數)
$router控制路由導航的方法
動態路由使用 :id 定義參數
巢狀路由路由中可包含子路由
導覽守衛控制進入頁面的權限
模式hash 或 history 模式

結語​

Vue Router 是構建 Vue SPA 必備的工具之一,掌握它能幫助我們設計更有結構、可導航的前端應用。在進階應用中,Vue Router 還支援命名路由、懶加載、滾動行為、過渡動畫等功能。

如果我們有興趣了解 Vue Router 與後端整合、登入驗證、或 Nuxt.js 中的路由自動生成,歡迎再提出更進一步的需求。

Element Plus 介紹入門教學筆記 | 學習筆記

· 閱讀時間約 6 分鐘
KD Chang
Builder, Curator & Lifelong Learner

前言​

在現代前端開發中,UI 框架對於提升開發效率、提升用戶體驗具有至關重要的作用。Element Plus 是一個基於 Vue 3 的開源 UI 框架,它提供了豐富的組件,並且與 Vue 3 的 Composition API 完美兼容,能幫助開發者快速構建高質量的前端應用。

在筆記中,我們將使用 Vue 3 的 setup() 語法來講解如何在專案中使用 Element Plus,並展示如何搭配 Vue 3 的新特性來實現更加清晰和模組化的開發模式。

重點摘要​

  • Element Plus:基於 Vue 3 的 UI 組件庫,提供了豐富的 UI 元件,支持 Composition API 和 TypeScript。
  • Vue 3 Setup:使用 Vue 3 的 Composition API 和 setup() 來構建組件邏輯,並將 UI 與邏輯分開。
  • 組件設置:展示如何在 setup() 中引入並使用 Element Plus 組件。
  • 全域配置:設置 Element Plus 的全域屬性,例如默認主題或組件大小。
  • 實際範例:通過簡單的範例,演示如何在 Vue 3 中使用 Element Plus 進行開發。

安裝與設置​

安裝 Element Plus​

在 Vue 3 專案中使用 Element Plus,首先需要安裝它。假設你的專案已經配置了 Vue 3,則可以通過以下命令安裝 Element Plus。

npm install element-plus --save

或者使用 yarn:

yarn add element-plus

設置 Vue 3 與 Element Plus​

在 Vue 3 的專案中,通過 setup() 語法來設置 Element Plus,首先需要在 main.js 或 main.ts 中引入 Element Plus 並配置樣式:

import { createApp } from 'vue';
import App from './App.vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';

const app = createApp(App);
app.use(ElementPlus);
app.mount('#app');

這樣,Element Plus 就成功集成到你的 Vue 3 專案中,接下來可以開始使用其組件。

使用 Vue 3 Setup 語法進行開發​

按鈕 (Button) 組件​

在 Vue 3 中,setup() 是一個組件的初始化函數,所有的組件邏輯應該放在這個函數中。以下是如何在 setup() 中使用 Element Plus 的按鈕組件。

<template>
<el-button type="primary">主要按鈕</el-button>
<el-button type="success">成功按鈕</el-button>
<el-button type="danger">危險按鈕</el-button>
</template>

<script setup>
import { ElButton } from 'element-plus';
</script>

在此範例中,使用 import 引入 ElButton 組件,並在模板中直接使用。這樣,我們就能夠根據需要渲染出不同樣式的按鈕。Element Plus 的組件會自動按照設置渲染出對應的 UI。

對話框 (Dialog) 組件​

Element Plus 提供了功能強大的對話框組件,能夠輕鬆實現彈窗效果。下面是如何在 setup() 中實現一個顯示對話框的功能:

<template>
<el-button @click="openDialog">顯示對話框</el-button>
<el-dialog :visible.sync="dialogVisible" title="對話框標題">
<p>這是一個對話框示例。</p>
</el-dialog>
</template>

<script setup>
import { ref } from 'vue';
import { ElButton, ElDialog } from 'element-plus';

const dialogVisible = ref(false);

const openDialog = () => {
dialogVisible.value = true;
};
</script>

在這個範例中,使用 ref() 創建了 dialogVisible 這個響應式變數,並且通過按鈕的點擊事件來控制對話框的顯示和隱藏。sync 修飾符用來將對話框的顯示狀態與 dialogVisible 變數同步。

表單 (Form) 組件​

Element Plus 的表單組件支持高效的表單驗證,以下範例展示如何在 setup() 中使用表單組件進行資料提交。

<template>
<el-form :model="form" ref="formRef" label-width="120px">
<el-form-item
label="名稱"
prop="name"
:rules="[{ required: true, message: '請輸入名稱', trigger: 'blur' }]"
>
<el-input v-model="form.name" placeholder="請輸入名稱"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</template>

<script setup>
import { ref } from 'vue';
import { ElButton, ElForm, ElFormItem, ElInput } from 'element-plus';

const form = ref({
name: '',
});

const submitForm = () => {
// 表單提交處理
console.log(form.value.name);
};
</script>

在這個範例中,使用 ref() 創建表單的資料模型,並且為名稱欄位設置了必填的驗證規則。當點擊提交按鈕時,將會輸出表單中的名稱欄位值。

表格 (Table) 組件​

Element Plus 的表格組件支持展示大量數據,並且提供排序、過濾等功能。以下是如何使用 setup() 語法來渲染表格:

<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column label="年齡" prop="age"></el-table-column>
<el-table-column label="地址" prop="address"></el-table-column>
</el-table>
</template>

<script setup>
import { ref } from 'vue';
import { ElTable, ElTableColumn } from 'element-plus';

const tableData = ref([
{ name: '王小明', age: 25, address: '台北市' },
{ name: '李大華', age: 30, address: '高雄市' },
{ name: '張三', age: 28, address: '台中市' },
]);
</script>

這個範例展示了如何使用 ref() 創建表格的數據源,並使用 ElTable 和 ElTableColumn 來渲染表格。

全域配置​

Element Plus 提供了全域配置的能力,允許你在項目中設置統一的組件配置。例如,設置所有按鈕的默認大小或主題色彩等。

import { createApp } from 'vue';
import App from './App.vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';

const app = createApp(App);

app.use(ElementPlus, {
size: 'small', // 設定所有組件的大小為 small
zIndex: 3000, // 設定 z-index
});

app.mount('#app');

這樣設置之後,你的所有組件將會默認使用小號尺寸,並且對話框等組件的 z-index 也會被統一設置。

總結​

Element Plus 是一個強大且易於使用的 UI 框架,與 Vue 3 的 Composition API 完美集成。通過 setup() 語法,開發者能夠更加簡潔且模組化地編寫組件邏輯,從而提升開發效率。無論是常見的按鈕、對話框,還是複雜的表格、表單,Element Plus 都能提供強大的支持。希望本文能幫助你快速上手 Element Plus,並利用它來構建高效、現代化的前端應用。

Vuex 入門教學筆記:集中式狀態管理實作入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
KD Chang
Builder, Curator & Lifelong Learner

前言​

在 Vue.js 開發中,當應用程式變得複雜,元件之間需要共享的狀態越來越多時,僅靠 props 與 events 傳遞資料會變得混亂與難以維護。這時,我們就需要一個集中式的狀態管理方案,而 Vuex 正是官方為 Vue 提供的解決方案。

Vuex 是一個專為 Vue 應用開發的狀態管理模式。它將應用中所有的狀態集中管理,並以可預測的方式更新,便於追蹤與維護。


一、Vuex 是什麼?​

Vuex 基於 Flux 架構 設計,核心概念如下:

  • State:集中管理的資料來源(全域狀態)
  • Getter:從 state 派生出來的資料(類似 computed)
  • Mutation:唯一可以同步改變 state 的方法
  • Action:處理非同步操作並提交 mutation
  • Module:將 store 拆分為模組化結構

二、安裝與設定 Vuex​

以 Vue 3 專案為例,先安裝 Vuex:

npm install vuex@4

建立 store​

// src/store/index.js
import { createStore } from "vuex";

const store = createStore({
state() {
return {
count: 0,
};
},
getters: {
doubleCount(state) {
return state.count * 2;
},
},
mutations: {
increment(state) {
state.count++;
},
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit("increment");
}, 1000);
},
},
});

export default store;

三、在 Vue 中註冊 Vuex​

// main.js
import { createApp } from "vue";
import App from "./App.vue";
import store from "./store";

createApp(App).use(store).mount("#app");

四、在元件中使用 Vuex​

1. 讀取 State 和 Getter​

<template>
<div>
<p>Count:{{ count }}</p>
<p>Double:{{ doubleCount }}</p>
</div>
</template>

<script>
import { computed } from "vue";
import { useStore } from "vuex";

export default {
setup() {
const store = useStore();
const count = computed(() => store.state.count);
const doubleCount = computed(() => store.getters.doubleCount);
return { count, doubleCount };
},
};
</script>

2. 呼叫 Mutation 和 Action​

<template>
<button @click="increment">+1</button>
<button @click="incrementAsync">+1(非同步)</button>
</template>

<script>
import { useStore } from "vuex";

export default {
setup() {
const store = useStore();
const increment = () => store.commit("increment");
const incrementAsync = () => store.dispatch("incrementAsync");
return { increment, incrementAsync };
},
};
</script>

五、模組化 Vuex Store​

當我們的應用變大,state 增加時,可將 store 拆分成多個模組。

// src/store/modules/counter.js
export default {
namespaced: true,
state: () => ({
count: 0,
}),
mutations: {
increment(state) {
state.count++;
},
},
};
// src/store/index.js
import { createStore } from "vuex";
import counter from "./modules/counter";

export default createStore({
modules: {
counter,
},
});

在元件中使用時要記得模組的命名空間:

store.commit("counter/increment");

六、Vuex 與 Composition API 的搭配​

Vuex 4 支援 Vue 3 的 Composition API,我們可以透過 useStore() 搭配 computed() 來存取或操作資料。這樣的使用方式更模組化,也能更輕鬆撰寫邏輯可重用的自定義 hooks。

// composables/useCounter.js
import { computed } from "vue";
import { useStore } from "vuex";

export default function useCounter() {
const store = useStore();
const count = computed(() => store.state.counter.count);
const increment = () => store.commit("counter/increment");
return { count, increment };
}

七、Vuex 與非同步操作的實務應用​

Vuex 的 Action 適合處理 API 呼叫,例如取得後端資料:

// store/modules/todos.js
export default {
namespaced: true,
state: () => ({
list: [],
loading: false,
}),
mutations: {
setLoading(state, flag) {
state.loading = flag;
},
setTodos(state, todos) {
state.list = todos;
},
},
actions: {
async fetchTodos({ commit }) {
commit("setLoading", true);
const res = await fetch("https://jsonplaceholder.typicode.com/todos");
const data = await res.json();
commit("setTodos", data.slice(0, 5));
commit("setLoading", false);
},
},
};

八、Vuex 的限制與未來​

Vuex 提供完整的狀態追蹤與結構化設計,適合大型應用。不過,它的學習曲線略高,對於小型專案可能顯得冗長。Vue 團隊也在 Vue 3 推出後推薦使用 Pinia 作為新的官方狀態管理方案,擁有更輕量的語法與更佳的 TypeScript 支援。

但 Vuex 在大型專案、多人協作、需要嚴格管理資料流程的場景下仍然非常實用與穩定。


九、總結與建議​

功能說明
state全域共享狀態資料
getters從 state 衍生計算的資料
mutations同步更新狀態的唯一方法
actions處理非同步並提交 mutation
modules將 store 拆分管理
Composition API搭配 useStore() 模組化使用

建議我們在小型應用中可以先用 props 和 emit 傳遞資料,等到資料流變複雜或頁面之間需頻繁共享狀態時,再引入 Vuex 管理。當然,若我們正開發大型後台系統、電子商務網站,Vuex 的集中式結構能大大提升可維護性與擴展性。

如欲進一步探索,建議查看 Vuex 官方文件、或試著實作一個待辦清單管理應用,實踐 Vuex 中的完整生命週期與流程。

Webpack 入門教學筆記:現代前端建構工具的基礎與實戰 | 學習筆記

· 閱讀時間約 4 分鐘
KD Chang
Builder, Curator & Lifelong Learner

前言​

在前端專案日益龐大與模組化的今天,建構工具(build tools)扮演了極其關鍵的角色。而 Webpack 作為目前最主流的模組打包器(module bundler),廣泛應用於各類前端應用與框架中(如 React、Vue 等)。本篇筆記將介紹 Webpack 的基本概念、核心組件與實際範例,協助你快速理解與實作。


一、什麼是 Webpack?​

Webpack 是一個靜態模組打包器,它會從你的應用程式進入點(entry point)開始,分析相依的模組(JavaScript、CSS、圖片、JSON 等),然後打包成一或多個 bundle,供瀏覽器載入使用。

主要特性包含:

  • 支援模組系統(如 CommonJS、ESM)
  • 可搭配各種 Loader 處理不同類型資源
  • 使用 Plugin 擴充打包功能
  • 開發與生產模式可分離配置
  • 支援 Hot Module Replacement(HMR)與 Dev Server

二、基本安裝與專案初始化​

建立一個新的專案資料夾:

mkdir my-webpack-app
cd my-webpack-app
npm init -y

安裝 Webpack 及其 CLI 工具:

npm install --save-dev webpack webpack-cli

建立基本的專案目錄結構:

my-webpack-app/
├── dist/
│ └── index.html
├── src/
│ └── index.js
├── package.json
└── webpack.config.js

三、撰寫基本範例​

1. src/index.js​

import "./style.css";

const element = document.createElement("h1");
element.textContent = "Hello Webpack!";
document.body.appendChild(element);

2. src/style.css​

body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
text-align: center;
padding-top: 100px;
}

3. dist/index.html​

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Webpack App</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>

四、Webpack 基礎設定檔​

建立 webpack.config.js:

const path = require("path");

module.exports = {
entry: "./src/index.js", // 入口檔案
output: {
filename: "main.js", // 輸出檔案名稱
path: path.resolve(__dirname, "dist"), // 輸出目錄
clean: true, // 每次打包清空 dist
},
module: {
rules: [
{
test: /\.css$/i, // 處理 CSS 檔案
use: ["style-loader", "css-loader"],
},
],
},
mode: "development", // 模式(也可設為 'production')
};

安裝所需的 CSS loader:

npm install --save-dev style-loader css-loader

五、打包與啟動​

執行打包指令:

npx webpack

執行後會自動將所有相依檔案打包為 dist/main.js,可以直接打開 dist/index.html 查看效果。


六、啟用 Webpack Dev Server(開發伺服器)​

為了開發方便,我們可以啟用內建的開發伺服器,支援 HMR(Hot Module Replacement)功能。

安裝 dev server:

npm install --save-dev webpack-dev-server

在 webpack.config.js 增加設定:

devServer: {
static: './dist',
port: 3000,
open: true, // 自動開啟瀏覽器
hot: true, // 啟用 HMR
}

更新 package.json 的 scripts:

"scripts": {
"build": "webpack",
"start": "webpack serve"
}

執行:

npm run start

開發伺服器啟動後會自動開啟 localhost:3000,修改檔案後可即時預覽變更。


七、區分開發與生產模式​

在實際開發中,我們會針對開發與正式環境建立不同的設定檔,使用 webpack-merge 套件來合併共用設定:

npm install --save-dev webpack-merge

建立以下三個檔案:

webpack.common.js
webpack.dev.js
webpack.prod.js

webpack.common.js 放共用設定,其他兩個則各自設定環境特有的項目,例如:

  • webpack.dev.js: 開啟 Source Map、HMR
  • webpack.prod.js: 最佳化壓縮、移除 console.log 等

八、擴充功能:使用 Babel 處理 ES6+​

Webpack 本身不會轉譯 JavaScript,需要搭配 Babel:

npm install --save-dev babel-loader @babel/core @babel/preset-env

新增 .babelrc:

{
"presets": ["@babel/preset-env"]
}

在 webpack.config.js 加入規則:

{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}

這樣就能讓 Webpack 在打包過程中使用 Babel 將 ES6+ 語法轉譯為相容的版本。


九、使用 Plugin 擴充功能:HtmlWebpackPlugin​

HtmlWebpackPlugin 可自動產生並插入 script 標籤:

npm install --save-dev html-webpack-plugin

修改設定:

const HtmlWebpackPlugin = require("html-webpack-plugin");

plugins: [
new HtmlWebpackPlugin({
template: "./dist/index.html",
inject: "body",
}),
];

不再需要手動在 index.html 中引入 main.js,Webpack 會自動插入對應 bundle。


十、結語與建議​

Webpack 雖然設定上比 Vite 複雜,但擁有極高的自訂彈性與完整生態系,是大型專案不可或缺的建構工具。透過 Loader 處理不同格式的資源、Plugin 擴充功能,再加上分環境設定與開發伺服器支援,Webpack 能有效協助你管理現代前端應用的整個建構流程。

適合情境包括:

  • React、Vue 中大型應用
  • 多入口或模組系統複雜的專案
  • 需要高度自訂打包流程的企業內部系統

雖然 Vite、Parcel 等工具正迅速崛起,但 Webpack 仍是學習前端建構工具不可忽略的重要基礎。

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

· 閱讀時間約 2 分鐘
KD Chang
Builder, Curator & Lifelong Learner

Cookie 是一種儲存在使用者瀏覽器上的小型文字檔案,用於保存使用者的狀態或資訊。常見用途包含:

紀錄登入狀態:讓使用者在網站上保持登入,不需每次重新輸入帳號。 使用者偏好設定:保存使用者選擇的語言、主題等個人化設定。 追蹤使用者行為:例如分析網站流量、廣告投放追蹤等。

重點摘要

Cookie 依據不同的分類方式,可以分為以下幾種常見種類:

一、依用途分類:​

  1. 功能性 Cookie(Functional Cookies)

    • 主要用於提升網站使用體驗,例如記住使用者的登入狀態、語言設定、購物車內容等。
  2. 必要性 Cookie(Strictly Necessary Cookies)

    • 維持網站基本運作所需,例如登入認證、網頁導航等,通常無法被關閉。
  3. 分析型 Cookie(Analytical/Performance Cookies)

    • 用於收集網站流量數據,分析使用者行為,幫助網站優化,例如 Google Analytics。
  4. 廣告追蹤 Cookie(Advertising/Targeting Cookies)

    • 用於追蹤使用者瀏覽行為,以提供個人化廣告或推薦內容。

二、依存放時間分類:​

  1. 暫時性 Cookie(Session Cookies)

    • 只在使用者開啟網頁期間有效,關閉瀏覽器後即刪除。
  2. 永久性 Cookie(Persistent Cookies)

    • 設定到期日期,存放於使用者裝置上,保存時間較長,即使關閉瀏覽器也不會刪除,直到設定的到期日或手動刪除。

三、依來源分類:​

  1. 第一方 Cookie(First-party Cookies)

    • 由使用者瀏覽的網站所設定,通常用於記錄該網站上的互動紀錄。
  2. 第三方 Cookie(Third-party Cookies)

    • 由非該網站的第三方(如廣告商)設定,用於跨網站追蹤使用者行為,以推送廣告等。

四、特殊類型:​

  1. 安全性 Cookie(Secure Cookies)

    • 只能透過 HTTPS 傳輸,避免被攔截,主要保障敏感資料安全。
  2. HttpOnly Cookie

    • 僅限伺服器端存取,JavaScript 無法讀取,用於防範 XSS 攻擊。
  3. SameSite Cookie

    • 限制跨站請求攜帶 Cookie,減少 CSRF 攻擊風險,值可設為:
    • Strict:禁止跨站請求攜帶 Cookie。
    • Lax:部分允許,如從第三方網站點擊連結進來時可帶 Cookie。
    • None:允許跨站攜帶,但須配合 Secure。

總結

這些分類會依需求搭配使用,例如一個「必要性第一方暫時性 Cookie」可能用於維護登入和操作狀態;一個「第三方廣告追蹤永久性 Cookie」則可能用於跨網站顯示個人化廣告。

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

· 閱讀時間約 4 分鐘
KD Chang
Builder, Curator & Lifelong Learner

1. 什麼是 Alpine.js?​

Alpine.js 是一個輕量級的 JavaScript 框架,專為增強 HTML 標記而設計。它的語法靈感來自 Vue.js,但更加簡潔,適用於需要簡單互動的網頁。

它的主要特點包括:

  • 使用 HTML 屬性直接定義行為
  • 不需要額外的構建工具
  • 易於學習和使用
  • 與其他框架(如 Vue、React)兼容

2. 安裝與引入​

使用 Alpine.js 最簡單的方法是透過 CDN 引入。

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Alpine.js 入門</title>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
</head>
<body>
<h1>Alpine.js 教學</h1>
</body>
</html>

3. 基本語法與應用​

3.1 x-data​

x-data 屬性用於定義 Alpine.js 的組件狀態。

<div x-data="{ message: 'Hello, Alpine!' }">
<p x-text="message"></p>
</div>

這段程式碼會顯示 Hello, Alpine!,並且 x-text 會自動更新內容。

3.2 x-bind​

x-bind 允許綁定 HTML 屬性。

<div x-data="{ color: 'red' }">
<p x-bind:style="'color: ' + color">這是一段紅色文字</p>
</div>

3.3 x-on​

x-on 用於事件監聽,例如點擊事件。

<div x-data="{ count: 0 }">
<button x-on:click="count++">增加</button>
<p>計數:<span x-text="count"></span></p>
</div>

3.4 x-model​

x-model 允許雙向綁定表單元素。

<div x-data="{ name: '' }">
<input type="text" x-model="name" placeholder="輸入你的名字">
<p>你好,<span x-text="name"></span>!</p>
</div>

3.5 x-show​

x-show 控制元素顯示或隱藏。

<div x-data="{ isVisible: true }">
<button x-on:click="isVisible = !isVisible">切換顯示</button>
<p x-show="isVisible">這段文字可以顯示或隱藏</p>
</div>

3.6 x-if​

x-if 會動態新增或移除元素(比 x-show 更影響 DOM)。

<div x-data="{ isVisible: true }">
<button x-on:click="isVisible = !isVisible">切換</button>
<template x-if="isVisible">
<p>這是一段可動態新增或刪除的文字</p>
</template>
</div>

3.7 x-for​

x-for 用於迭代陣列。

<div x-data="{ items: ['蘋果', '香蕉', '橘子'] }">
<ul>
<template x-for="item in items" :key="item">
<li x-text="item"></li>
</template>
</ul>
</div>

3.8 計時器與非同步操作​

Alpine.js 支援 setTimeout 和 fetch 等 JavaScript 方法。

<div x-data="{
message: '載入中...',
async fetchData() {
let response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
let data = await response.json();
this.message = data.title;
}
}" x-init="fetchData">
<p x-text="message"></p>
</div>

4. Alpine.js 與 Tailwind CSS​

Alpine.js 常與 Tailwind CSS 搭配使用,打造簡潔的 UI。

<div x-data="{ open: false }" class="p-5">
<button x-on:click="open = !open" class="bg-blue-500 text-white px-4 py-2 rounded">
切換選單
</button>
<ul x-show="open" class="mt-2 border p-2">
<li>選單 1</li>
<li>選單 2</li>
<li>選單 3</li>
</ul>
</div>

5. Alpine.js 進階應用​

5.1 Alpine.store​

Alpine.store 可用於全域狀態管理。

<script>
document.addEventListener('alpine:init', () => {
Alpine.store('app', { count: 0 });
});
</script>

<div x-data>
<button x-on:click="$store.app.count++">增加</button>
<p>計數:<span x-text="$store.app.count"></span></p>
</div>

5.2 Alpine.plugin​

Alpine.js 提供外掛支援,例如 persist(本地儲存)。

<script src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.plugin(Alpine.persist);
});
</script>

<div x-data="{ count: $persist(0) }">
<button x-on:click="count++">增加</button>
<p>計數:<span x-text="count"></span></p>
</div>

6. 總結​

Alpine.js 是一個靈活且輕量的框架,適合用於簡單互動需求,如表單驗證、選單切換、即時更新內容等。它不需要複雜的配置,能夠快速增強靜態 HTML 頁面。

如果你的專案需要更強大的功能,可以考慮與 Vue.js 或 React 搭配,或在更大規模的應用中使用其他框架。