iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Modern Web

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

【Day 5 】認識 <style scoped> 與刻出採集瓶輪廓

  • 分享至 

  • xImage
  •  

可以往前點到 Day 3 那篇,在拆解 .vue的三個區塊時,<style>後面有一個 “scoped”。

為什麼要在 <style> 後面加上一個 scoped 呢?這就是今天的第一個重點,我們要來介紹 scoped 這個屬性,說明它在 Vue 裡有什麼功能。

簡單來說,scoped 可以在我們建立新的元件時,避免一樣名稱的Class相互影響,造成全域樣式汙染。

小實驗:如果大家都有 <button> ……

  1. 在src/components/ 底下新增一個子元件:MemoryCard.vue 。
    (未來要拿來展示每一顆光珠故事的小卡片)

  2. 輸入以下程式碼:

<template>
  <div class="card">
    <p>這是一顆裝著美好回憶的光珠</p>
    <button class="action-btn">查看當天回憶</button>
  </div>
</template>

<style>
/* 故意不加 scoped! */
button {
  background-color: #ff9800;
  color: white;
  border: none;
  border-radius: 20px;
  padding: 8px 16px;
  font-weight: bold;
}

p {
  color: #ffb74d;
}
</style>
  1. 沿用昨天的 App.vue ,引入、掛載剛剛新增的子元件,其餘程式碼皆與昨日一樣。
<script setup>
import { ref } from 'vue'
// 1. 引入子元件
import MemoryCard from './components/MemoryCard.vue'

const count = ref(0)

function addGem() {
  count.value++
  console.log(count.value)
}
</script>

<template>
  <p>已採集 {{ count }} 顆光珠</p>
  <button @click="addGem">採集</button>

  <!-- 2. 掛載子元件 -->
  <MemoryCard />
</template>
  1. 到瀏覽器可以看到新增的一行字和按鈕,對比昨日未更改的瀏覽器畫面。

https://ithelp.ithome.com.tw/upload/images/20260919/20178067iyOS8cxgUD.png

https://ithelp.ithome.com.tw/upload/images/20260919/20178067BrG6scTPUG.png

  • 更改前(上圖):白字、白色方形按鈕
  • 更改後(下圖):橘色字、橘色橢圓形按鈕

上半部被汙染了?

明明我們是將橘色字和橘色橢圓形按鈕寫在MemoryCard.vue 裡面,為什麼連採集的區塊都變成這種樣式?

原因就是我們沒有在子元件的<style>後面加上scoped!這會使子元件裡寫的樣式外洩成「全域樣式(Global CSS)」,無差別地將樣式套到整個專案上!

瀏覽器在讀取 CSS 時,預設並沒有「元件」的概念。當我們在 MemoryCard.vue 寫下 button 和 p 卻沒有加上 scoped 時,瀏覽器會把這些樣式當成全站通用的規則。

結果就是:瀏覽器只要在畫面上看到任何 <button> 或 <p>(包含 App.vue 原本白色方形的採集按鈕與文字),都會強制替它們套上橘色與橢圓形外觀。

  • 要解決這個問題,只需要在 <style> 後面加上 scoped,不讓元件樣式互相影響:
<style scoped>
/* 加上 scoped 後,這裡的樣式就只會對 MemoryCard.vue 生效 */
button {
  background-color: #ff9800;
  /* ... */
}
</style>

到瀏覽器看更改後的畫面就是正常的樣式了,如下圖:

https://ithelp.ithome.com.tw/upload/images/20260919/201780679FOA1nQOVg.png

💡底層運作的小秘密

加上 scoped 後,Vue 在編譯時會偷偷替這個元件的所有 HTML 標籤加上一串唯一的識別碼(例如 data-v-7ba5bd90),並把 CSS 選擇器改寫成 button[data-v-7ba5bd90],這就是樣式不會外洩的真正原因!

看完了樣式污染的實驗,我們就知道 <style scoped> 有多重要了!接下來請先將剛剛在 App.vue 引入的 MemoryCard 拿掉(我們在後面的篇章會再用到它),現在要回過頭來專心設計專案主角——採集瓶的外觀。
今天只會稍微寫出瓶子外觀,細節的設計(例如陰影、玻璃質感)就等之後再慢慢調整。

採集瓶設計

我想要採集瓶開口有一個軟木塞,在我加入光珠時,軟木塞會先被打開,在讓光珠緩緩落進瓶中,所以今天要做的部分有兩個:

  1. 軟木塞
  2. 瓶身
  • 程式碼如下:
/* 軟木塞 */
.cork {
  width: 40px;
  height: 12px;
  background-color: #a07855;
  border-radius: 3px;
}

/* 瓶身 */
.bottle {
  width: 160px;
  height: 220px;
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-radius: 12px 12px 40px 40px; /* 上小下大的圓角就是瓶子 */
  display: flex;
  align-items: center;
  justify-content: center;
  color: #6e7681;
}

如果想要完整App.vue程式碼可以看下面這段,內容包含一些置中、結構細項。

  • App.vue 完整程式碼

    <script setup>
    import { ref } from 'vue'
    
    const count = ref(0)
    
    function addGem() {
      count.value++
      console.log(count.value)
    }
    </script>
    
    <template>
      <main class="bottle-app">
        <h1>微光採集瓶</h1>
        <p class="subtitle">在每一天的最後,採集一道微小的美好</p>
    
        <!-- 瓶子結構 -->
        <div class="bottle-wrapper">
          <div class="cork"></div>
          <div class="bottle">
            <span>瓶子目前是空的</span>
          </div>
        </div>
    
        <!-- 原本的計數與採集按鈕 -->
        <p>已採集 {{ count }} 顆光珠</p>
        <button @click="addGem">採集</button>
      </main>
    </template>
    
    <style scoped>
    /* 頁面置中對齊 */
    .bottle-app {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
      text-align: center;
      gap: 12px;
    }
    
    /* 瓶子的樣式 */
    .bottle-wrapper {
      display: flex;
      flex-direction: column;
      align-items: center;
      margin: 16px 0;
    }
    
    /* 軟木塞:棕色小方塊 */
    .cork {
      width: 40px;
      height: 12px;
      background-color: #a07855;
      border-radius: 3px;
    }
    
    /* 瓶身:透明帶白邊的長方圓角框 */
    .bottle {
      width: 160px;
      height: 220px;
      border: 2px solid rgba(255, 255, 255, 0.3);
      border-radius: 12px 12px 40px 40px; /* 上小下大的圓角勾出瓶子輪廓 */
      display: flex;
      align-items: center;
      justify-content: center;
      color: #6e7681;
      font-size: 0.85rem;
    }
    </style>
    

畫面呈現

https://ithelp.ithome.com.tw/upload/images/20260919/20178067AVyK07a9Un.png
今天的文章就到這邊結束啦~希望讀者在看完後可以對 scoped 有詳細了解,也可以自己變更一些程式碼做出你更喜歡的瓶身造型喔!

明日預告

Day 6 要學習動態綁定(v-bind),讓今天看起來只是由線條組成的玻璃瓶可以擁有動態樣式,變得更吸睛!


上一篇
【Day 4】讓畫面動起來!認識雙大括號 {{ }} 與響應式 ref( )
下一篇
【Day 6】v-bind 動態綁定:讓瓶身回應你的動作
系列文
微光採集瓶:用 Vue 3 打造每日美好記錄網頁 共 20 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言