iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Modern Web

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

【Day 13】點亮記憶:光珠懸浮回饋與點擊預覽卡片

  • 分享至 

  • xImage
  •  

「微光採集瓶」最重要的核心,不只是收集,而是重溫記憶。當初在輸入框裡寫下的那句「今天的美好小事」,如果存進瓶子後就再也看不到了,那過一陣子之後很有可能會忘記,當初發生了什麼令自己感到幸福的事情,我覺得有點可惜,美好的記憶應該要一直存在腦海裡。

所以今天我們要讓使用者可以跟瓶子裡的光珠互動:滑鼠移上去時有微光反應,點擊後彈出小卡片,重新顯示出那天寫下的那道微光。

一、互動設計的兩道關卡

在實作之前,先思考使用者操作的重點:

  1. 光珠太小很難點(操作提示不足):

    光珠的尺寸只有 14px,在畫面上非常小。如果滑鼠移上去沒有任何變化,使用者根本不會知道「原來這顆球可以點」。所以我們需要加上 :hover 效果,讓珠子在滑鼠靠近時稍微放大、加強光暈,並換上 cursor: pointer 的手勢。

  2. 怎麼展示內容(Modal 彈出視窗):

    我們不需要複雜的路由跳轉,只要一個簡單的浮層(Modal)。點擊光珠時展示它、點擊背景或關閉按鈕時收起它。

在 Vue 裡,處理彈窗最經典的方式就是 「單一狀態控制」。

二、在 <script setup> 增加選中狀態

打開 src/components/GemJar.vue。我們只需要宣告一個響應式變數 activeGem,用來記錄「當前被點擊的光珠物件」:

// 記錄目前被點選要查看的光珠(沒點選時為 null)
const activeGem = ref(null)

// 開啟預覽卡片
function openGem(gem) {
  activeGem.value = gem
}

// 關閉預覽卡片
function closeGem() {
  activeGem.value = null
}

這個邏輯非常簡單:

  • 平常沒有點擊任何光珠時,activeGem 的值是 null。
  • 點擊某顆光珠時,把那顆光珠的物件(包含 note、color、id)傳進來存著。
  • 想關閉時,再把它重設回 null。

三、綁定點擊事件與彈出卡片

接著到 <template> 區塊,我們做兩件事:

  1. 在 .gem-dot 上綁定點擊事件 @click="openGem(gem)"。
  2. 在畫面最底層新增一個用 v-if="activeGem" 控制的彈出視窗。
<!-- 裝著所有光珠的區域 -->
<div class="gem-pile">
  <div
    v-for="gem in gems"
    :key="gem.id"
    class="gem-dot"
    :style="{
      backgroundColor: gem.color,
      '--offset-x': `${gem.offsetX}px`,
      '--offset-y': `${gem.offsetY}px`
    }"
    @click="openGem(gem)"
  ></div>
</div>

<!-- 彈出預覽卡片 -->
<div v-if="activeGem" class="modal-backdrop" @click="closeGem">
  <div class="gem-card" :style="{ borderColor: activeGem.color }" @click.stop>
    <!-- 小光點裝飾,沿用該光珠的顏色 -->
    <div class="gem-badge" :style="{ backgroundColor: activeGem.color }"></div>
    <!-- 當時寫下的文字 -->
    <p class="gem-text">{{ activeGem.note }}</p>
    <button class="btn-close" @click="closeGem">收起微光</button>
  </div>
</div>

Vue 實用小技巧:什麼是 @click.stop?

在外層的黑底遮罩 .modal-backdrop 上,我們綁定了 @click="closeGem",意思是「點擊背景空白處就關閉彈窗」。

但如果不做任何處理,點擊中間的白色卡片時,點擊事件會冒泡(Bubbling)傳遞到外層背景,導致點擊卡片看文字時卡片反而意外關閉。

只要在卡片容器加上 @click.stop(等同於原生 JS 的 event.stopPropagation()),就能阻擋點擊事件往外冒泡。

四、加上懸浮回饋與卡片樣式

最後,在 <style scoped> 裡加上視覺效果:

/* 加上指標手勢 */
.gem-dot {
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

/* 滑鼠懸浮時:稍微放大、光暈增強 */
.gem-dot:hover {
  transform: translate(var(--offset-x, 0), var(--offset-y, 0)) scale(1.4) !important;
  box-shadow: 0 0 12px rgba(255, 255, 255, 0.8);
  z-index: 10;
}

/* 遮罩背景 */
.modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(4px);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 100;
}

/* 預覽卡片本體 */
.gem-card {
  background: #1e2228;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 12px;
  padding: 24px;
  width: 240px;
  text-align: center;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

/* 卡片上方的心情光點 */
.gem-badge {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin: 0 auto 16px auto;
  box-shadow: 0 0 8px currentColor;
}

/* 採集時記錄的心情文字 */
.gem-text {
  color: #f0f6fc;
  font-size: 0.95rem;
  line-height: 1.6;
  margin: 0 0 20px 0;
  word-break: break-all;
}

/* 關閉按鈕 */
.btn-close {
  background: rgba(255, 255, 255, 0.1);
  border: none;
  color: #8b949e;
  padding: 6px 18px;
  border-radius: 16px;
  cursor: pointer;
  font-size: 0.8rem;
  transition: background 0.2s, color 0.2s;
}

.btn-close:hover {
  background: rgba(255, 255, 255, 0.2);
  color: #ffffff;
}

五、成果驗證

https://ithelp.ithome.com.tw/upload/images/20260927/20178067Bs47qsFRtv.png

https://ithelp.ithome.com.tw/upload/images/20260927/20178067eIo3rVFvy5.png

https://ithelp.ithome.com.tw/upload/images/20260927/20178067ChbsMDvLV4.png

存檔後回到瀏覽器測試:

  1. 將滑鼠移到瓶子裡的光珠上,確認游標是否變成手勢,且光珠會發亮有光暈。
  2. 點擊其中一顆光珠,確認畫面是否暗下來並浮出預覽卡片,卡片上的顏色與文字是否與當初輸入的一致。
  3. 點擊卡片本體,確認卡片不會誤關閉;點擊周圍深色背景或「收起微光」按鈕時,卡片能正常收合。

今日小結

  • 使用單一響應式變數 activeGem,控制彈窗的開啟、關閉與內容綁定。
  • 透過 :hover 放大與游標提示,解決小元素不易點選的問題,大幅提升介面操作友善性。
  • 使用@click.stop阻擋事件冒泡,避免點擊彈窗內容時觸發背景的關閉邏輯。

明日預告

現在光珠不僅能採集、自然堆疊,還能隨時被點開回味了!
但如果重新整理瀏覽器,這些珍貴的記憶就會全部消失。明天(Day 14),我們要為採集瓶加上「本地持久化存儲」,讓你的每一道微光,即使關閉分頁也不會消散。


上一篇
【Day 12】自然散落效果:用隨機微位移打破過度整齊的堆疊
下一篇
【Day 14】別讓記憶消失:用 LocalStorage 實現資料持久化儲存
系列文
微光採集瓶:用 Vue 3 打造每日美好記錄網頁 共 19 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言