iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Modern Web

微光採集瓶:用 Vue 3 打造每日美好記錄網頁系列 第 26 篇

【Day 26】讓光芒擁有名字:自訂心情定義

  • 分享至 

  • xImage
  •  

昨天我們替微光採集瓶加上了首頁與採集主畫面的轉場動態,在畫面呈現和體驗更完整。

但在每天放入微光的過程中,我發現了一個體驗上的問題:這些預設的色彩,背後到底代表了什麼心情?
原本系統裡的顏色其實沒有綁定明確的情緒,大家可能只是憑直覺選個順眼的顏色放進去。但如果沒有定義,過了一兩週回頭看,很可能早就忘記當初選擇這個顏色時是帶著什麼心情;更重要的是,到了月底回顧「月度微光色卡」時,這些顏色如果有了自己的定義,就能讓原本單純的比例數據多一層情緒上的意義。
因此今天(Day 26),我們要來替每道微光賦予名字,並且讓使用者隨時能修改。

一、設計上的取捨:為什麼不強制彈窗?

在規劃這個功能時,我原本想過要不要在第一次進入時自動彈出視窗,引導大家先把四個顏色命名好。

但後來想想,這樣其實很不合理:大家一進來根本還沒看過採集瓶長怎樣、不知道這個系統在幹嘛,這時候突然要人幫顏色取名字只會覺得莫名其妙,大概也只會隨便填填急著關掉。

最自然的流程,應該是讓使用者先進到頁面看見瓶子、知道核心互動後,等他對這些顏色產生自己的想法,再主動點擊按鈕去修改。因此我直接給定一組預設名稱(平靜、喜悅、溫柔、安心),想改的人隨時能自訂,不想改的人也能立刻開始記錄,完全不打擾當下的探索流程。

因此最後決定的做法是:

  • 有預設的定義:系統先給定一組預設值(平靜、喜悅、溫柔、安心)。
  • 保留自訂彈性,但不強迫:在選色區下方放一個「修改心情名稱」入口,想改的人隨時點進去改就好。

二、資料結構設計:色碼到名字的對應

比起把原本的陣列全部打掉重練,我採用更簡單直覺的物件 Key-Value 方式,讓「色碼」直接對應「心情名稱」:

// ==========================================
// 心情名稱(色碼 → 名字)
// ==========================================
const paletteColors = ['#8db3d4', '#e6c683', '#d7a9b8', '#9bb89f']

const defaultLabels = {
  '#8db3d4': '平靜',
  '#e6c683': '喜悅',
  '#d7a9b8': '溫柔',
  '#9bb89f': '安心'
}

// 使用者改過的名字會覆蓋預設值
const labels = ref({
  ...defaultLabels,
  ...JSON.parse(localStorage.getItem('store_color_labels') || '{}')
})

// 透過 watch 深度監聽自動存檔
watch(
  labels,
  (val) => {
    localStorage.setItem('store_color_labels', JSON.stringify(val))
  },
  { deep: true }
)

// 查詢色碼對應的心情
function labelOf(color) {
  if (!color) return ''
  // 系統自動補上的白色光珠,就叫做留白
  if (color.toLowerCase() === '#ffffff') return '留白'
  return labels.value[color] || ''
}

const showLabelEditor = ref(false)

這樣寫有什麼好處?

  • 修改後自動儲存:使用 watch(..., { deep: true }) 監聽 labels 的變化,當使用者修改心情名稱時,系統就會自動將最新資料寫入 localStorage,不需要另外設置儲存按鈕。
  • 留白光珠也有名字:之前實作的「補簽留白珠(#ffffff)」在查名字時會自動回傳「留白」,讓沒寫小事的日子也擁有一種名稱。

三、畫面調整:調色盤 v-for 與單行提示

原本調色盤是手動寫死四顆按鈕,今天將他們改成 v-for 搭配 :style 動態上色:

<div class="palette">
  <button
    v-for="color in paletteColors"
    :key="color"
    class="color-dot"
    :class="{ 'is-active': selectedColor === color }"
    :style="{ backgroundColor: color }"
    @click="selectColor(color)"
  ></button>
</div>

<!-- 目前選中的顏色名稱與修改入口 -->
<p class="selected-label">{{ labelOf(selectedColor) }}</p>
<button class="btn-edit-labels" @click="showLabelEditor = true">
  修改心情名稱
</button>

這樣寫的好處是:

  1. 清理 CSS:原本 CSS 裡的 .color-dot.blue、.gold、.pink、.green 全部都可以直接刪掉。
  2. 視覺乾淨不擁擠:色塊本身不塞文字,只在下方顯示目前選中色彩的名字,畫面維持簡潔乾淨。

四、自訂心情彈窗

彈窗放在 .main-content 的彈窗區塊,結構簡單,點擊旁邊空白處或完成按鈕即可關閉:

<div v-if="showLabelEditor" class="modal-backdrop" @click="showLabelEditor = false">
  <div class="label-editor" @click.stop>
    <h3 class="editor-title">這些顏色,對你來說是什麼心情?</h3>

    <div v-for="color in paletteColors" :key="color" class="label-row">
      <span class="setting-dot" :style="{ backgroundColor: color }"></span>
      <input
        v-model="labels[color]"
        class="label-input"
        type="text"
        maxlength="6"
        placeholder="替這個顏色取名字"
      />
    </div>

    <button class="btn-close" @click="showLabelEditor = false">完成</button>
  </div>
</div>

五、讓名字出現在月度色卡與時光相簿

自訂的心情名稱不能只停留在主畫面,最關鍵的是要帶進月度色卡與時光相簿。

在計算比例的 colorStats 裡,多補上一個 label 欄位:

return Object.entries(counts)
  .map(([color, count]) => ({
    color,
    count,
    label: labelOf(color), // 新增心情名稱
    ratio: Math.round((count / total) * 100)
  }))
  .sort((a, b) => b.count - a.count)

在月度色卡與相簿大圖的色票列表裡,加入文字顯示:

<div v-for="(item, index) in colorStats" :key="index" class="swatch-item">
  <span class="swatch-bubble" :style="{ backgroundColor: item.color }"></span>
  <!-- 加上 v-if="item.label" 相容舊資料 -->
  <span v-if="item.label" class="swatch-label">{{ item.label }}</span>
  <span class="swatch-ratio">{{ item.ratio }}%</span>
</div>

小提醒
sealMonthlyCard 存的是當下 colorStats.value 的快照,所以封存時的心情名字會跟著一起被存進時光相簿。就算使用者以後改了名字,已經珍藏的歷史色卡依然會保留當初的心情。
加上 v-if="item.label" 是為了相容舊資料:今天之前存的色卡雖然顏色沒有定義名字,但畫面依然能正常顯示,排版完全不會跑掉。

六、成果展示

  1. 主畫面選色器即時提示

    切換不同顏色時,下方會呈現該色彩對應的心情名稱,點擊「修改心情名稱」即可隨時叫出彈窗。

  2. 自訂心情編輯彈窗

    四個微光色塊一字排開,輸入框上限 6 個字,修改完點擊「完成」即可關閉彈窗,名稱也會自動儲存。

    點擊影片:選中顏色顯示心情文字並進行修改

  3. 月度色卡上的心情標記

    色票除了顯示顏色與佔比,現在每一行都清楚列出了屬於自己的心情定義。

    https://ithelp.ithome.com.tw/upload/images/20261010/20178067OfIBCWbc8o.png

明日預告

明天(Day 27)我們要來做一件重要的事情——移除手動點擊的「查看本月色卡」按鈕。

原本主畫面上保留了「查看本月色卡」按鈕,方便開發與測試期間隨時檢視成果。明天我們會將它移除,讓月度色卡回歸月底專屬的回顧儀式,同時重新整理頁面佈局,讓整個採集流程更加完整。我們明天見!


上一篇
【Day 25】轉場與返回首頁:用 Vue Transition 打造「雙向切換」功能
下一篇
【Day 27】減法設計:移除冗餘入口與優化採集版面
系列文
微光採集瓶:用 Vue 3 打造每日美好記錄網頁 共 27 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言