2025-04-08-JavaScript 系列九:第7課 ── 學習開發狀態複雜的 vue 元件

2025-04-08-JavaScript 系列九:第7課 ── 學習開發狀態複雜的 vue 元件

JavaScript 系列九:第7課 ── 學習開發狀態複雜的 vue 元件
課程目標
學習開發狀態複雜的 vue 元件
課程內容
前面的課程中,元件的狀態很單純,數量也很少

但是有些元件,雖然對外溝通的狀態很少

但是在元件內部,其實需要維持額外的多個狀態,才能使用

比方說「顏色選擇器」類型的元件:雖然對外就一個代表色碼的字串而已,但在內部需要不少狀態來維持

課後作業
這一課作業,請先看一下 Color Picker 元件的用法

https://quasar.dev/vue-components/color-picker

請使用官方的元件試玩工具:Vue SFC Playground

https://sfc.vuejs.org/

請建立 MyColor.vue 元件,並支援下列功能
v-model 能夠設定色碼、取得色碼,格式支援 HEX 即可,例如:經典藍 #34568b
不用支援各種花俏的顏色選擇面板,就做 RGB 三捲軸就好了:使用 製作三個可以拉動的捲軸,分別代表紅色、綠色、藍色的比例
請自行搜尋 hex to rgb javascript rgb to hex javascript 研究 hex 色碼與 rgb 色碼如何轉換
完成之後,請在 App.vue 之中匯入此元件,並用多個範例證明,有完成上述規格

做出以上功能,你就完成這次的課程目標了!
明白了!我們這一課是要做一個 狀態較複雜的 Vue 元件——一個 RGB 三捲軸的色彩選擇器(MyColor.vue),並用 v-model 對外提供 HEX 色碼。下面我幫你整理 完整的實作思路和範例程式碼,一步步說明:


1️⃣ 功能需求整理

  1. 對外 v-model

    • 允許傳入初始 HEX 色碼,也可以取得目前選的 HEX 色碼。
  2. 內部狀態

    • 三個數字值分別代表 R / G / B(0~255)。
    • 這三個數值會互相影響最終的 HEX 值。
  3. UI

    • 三個 <input type="range">,分別控制 R / G / B。
    • 顯示目前選的色塊與 HEX 值。

2️⃣ HEX ↔ RGB 轉換工具函式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// HEX -> RGB
function hexToRgb(hex) {
hex = hex.replace('#', '');
const bigint = parseInt(hex, 16);
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return { r, g, b };
}

// RGB -> HEX
function rgbToHex(r, g, b) {
return (
'#' +
[r, g, b]
.map(x => x.toString(16).padStart(2, '0'))
.join('')
);
}

3️⃣ MyColor.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<template>
<div class="my-color-picker">
<div
class="color-preview"
:style="{ backgroundColor: currentHex }"
></div>
<div class="sliders">
<label>R: {{ r }}
<input type="range" min="0" max="255" v-model.number="r" />
</label>
<label>G: {{ g }}
<input type="range" min="0" max="255" v-model.number="g" />
</label>
<label>B: {{ b }}
<input type="range" min="0" max="255" v-model.number="b" />
</label>
</div>
<p>HEX: {{ currentHex }}</p>
</div>
</template>

<script setup>
import { ref, watch, computed } from 'vue';

// props for v-model
defineProps({
modelValue: { type: String, default: '#000000' }
});
const emit = defineEmits(['update:modelValue']);

// 工具函式
function hexToRgb(hex) {
hex = hex.replace('#', '');
const bigint = parseInt(hex, 16);
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return { r, g, b };
}
function rgbToHex(r, g, b) {
return (
'#' +
[r, g, b]
.map(x => x.toString(16).padStart(2, '0'))
.join('')
);
}

// 內部狀態
const r = ref(0);
const g = ref(0);
const b = ref(0);

// 初始化 r/g/b
const init = hexToRgb(defineProps().modelValue);
r.value = init.r;
g.value = init.g;
b.value = init.b;

// 計算 HEX
const currentHex = computed(() => rgbToHex(r.value, g.value, b.value));

// 當 r/g/b 改變時,發送 update:modelValue
watch([r, g, b], () => {
emit('update:modelValue', currentHex.value);
});

// 當外部 modelValue 改變時,也更新內部狀態
watch(
() => defineProps().modelValue,
(newVal) => {
const rgb = hexToRgb(newVal);
r.value = rgb.r;
g.value = rgb.g;
b.value = rgb.b;
}
);
</script>

<style scoped>
.my-color-picker {
width: 250px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 8px;
}
.color-preview {
width: 100%;
height: 50px;
margin-bottom: 10px;
border: 1px solid #aaa;
border-radius: 4px;
}
.sliders label {
display: block;
margin-bottom: 5px;
}
</style>

4️⃣ App.vue 測試範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>
<h2>測試 MyColor.vue</h2>
<MyColor v-model="color1" />
<p>選擇的顏色: {{ color1 }}</p>

<MyColor v-model="color2" />
<p>選擇的顏色: {{ color2 }}</p>
</div>
</template>

<script setup>
import { ref } from 'vue';
import MyColor from './components/MyColor.vue';

const color1 = ref('#34568b'); // 初始經典藍
const color2 = ref('#ff0000'); // 初始紅色
</script>

✅ 功能檢查:

  1. 三個捲軸可拉動 R/G/B,HEX 值同步更新。
  2. 對外 v-model 可取得目前 HEX 色碼。
  3. 外部修改 v-model 的值,元件內部也會自動更新。

加上 動態動畫效果:當滑桿改變時,顏色預覽會平滑過渡,而不是瞬間跳變,使用 CSS transition 配合 Vue 的 reactivity 就能做到。


✅ 新增功能

  1. 顏色過渡動畫

    • CSS transition: background-color 0.3s ease; 讓顏色改變時平滑漸變。
  2. 滑桿同步 HEX

    • 調整滑桿時,預覽區顏色和 HEX 都會立即更新,但有動畫過渡。

// app.vue