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️⃣ 功能需求整理
對外 v-model:
- 允許傳入初始 HEX 色碼,也可以取得目前選的 HEX 色碼。
內部狀態:
- 三個數字值分別代表 R / G / B(0~255)。
- 這三個數值會互相影響最終的 HEX 值。
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
| 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('') ); }
|
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>
|
✅ 功能檢查:
- 三個捲軸可拉動 R/G/B,HEX 值同步更新。
- 對外
v-model
可取得目前 HEX 色碼。
- 外部修改
v-model
的值,元件內部也會自動更新。
加上 動態動畫效果:當滑桿改變時,顏色預覽會平滑過渡,而不是瞬間跳變,使用 CSS transition 配合 Vue 的 reactivity 就能做到。
<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>
✅ 新增功能
顏色過渡動畫:
- CSS
transition: background-color 0.3s ease;
讓顏色改變時平滑漸變。
滑桿同步 HEX:
- 調整滑桿時,預覽區顏色和 HEX 都會立即更新,但有動畫過渡。
// app.vue
測試 MyColor.vue(含動畫效果)
<div style="margin-bottom: 30px;">
<h3>範例 1</h3>
<MyColor v-model="color1" />
<p>選擇的顏色: <span :style="{ color: color1 }">{{ color1 }}</span></p>
</div>
<div style="margin-bottom: 30px;">
<h3>範例 2</h3>
<MyColor v-model="color2" />
<p>選擇的顏色: <span :style="{ color: color2 }">{{ color2 }}</span></p>
</div>
<div style="margin-bottom: 30px;">
<h3>範例 3(初始經典藍)</h3>
<MyColor v-model="color3" />
<p>選擇的顏色: <span :style="{ color: color3 }">{{ color3 }}</span></p>
</div>