2025-01-14 JavaScript 系列八:第4課 ── 行事曆應用程式-步驟05

2025-01-14 JavaScript 系列八:第4課 ── 行事曆應用程式-步驟05

我的按鈕想做成 RWD , 當變成手機的螢幕大小時,變成沒有文字的圖示按鈕

太棒了~你想讓按鈕在手機上變成圖示(icon button),這就是 RWD(響應式設計)的好實踐 👏
我來教你一步一步怎麼做,用最簡單的方法來實現這個效果!


✅ 效果目標:

  • 👉 電腦螢幕:按鈕顯示「新增活動」文字
  • 👉 手機螢幕:按鈕只顯示 ➕ 圖示(用 emoji 或 FontAwesome)

🧩 方法一:使用純 CSS + media query(簡單易懂)

🧾 修改樣式(Calendar.vue 的 <style scoped> 裡)

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
.add-event-button {
background-color: #007bff;
color: white;
border: none;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
display: inline-flex;
align-items: center;
gap: 4px;
}

.add-event-icon {
display: none;
}

/* 電腦版,顯示文字 + 圖示(可選) */
@media (min-width: 600px) {
.add-event-text {
display: inline;
}
}

/* 手機版,只顯示圖示,隱藏文字 */
@media (max-width: 599px) {
.add-event-text {
display: none;
}
.add-event-icon {
display: inline;
}
}

🧾 修改 JS 建立按鈕的部分(dateClick 裡)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const button = document.createElement('button')
button.className = 'add-event-button'

// 建立 icon span
const icon = document.createElement('span')
icon.className = 'add-event-icon'
icon.textContent = '➕' // 你也可以用 FontAwesome 的 `<i class="fas fa-plus"></i>`

// 建立文字 span
const text = document.createElement('span')
text.className = 'add-event-text'
text.textContent = '新增活動'

// 組合按鈕內容
button.appendChild(icon)
button.appendChild(text)

這樣一來:

  • 👀 在桌機畫面會看到:➕ 新增活動
  • 📱 在手機畫面只會看到:➕

想加 FontAwesome 圖示?

只要在 index.html 加上這一行就能用:

1
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />

然後把 icon.textContent = '➕' 改為:

1
icon.innerHTML = '<i class="fas fa-plus"></i>'

要不要我幫你加上完整的程式碼一起貼上測試?還是你想先自己試看看?😎

很好問題!針對你使用的 Vue <style scoped>,如果你希望在 scoped 樣式中,影響由 JS 動態插入的 DOM 元素(像你用 FullCalendar 建的 .add-event-button),這時候就要用 :deep()


✅ 所以你應該這樣寫:

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
:deep(.add-event-button) {
background-color: #007bff;
color: white;
border: none;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
display: inline-flex;
align-items: center;
gap: 4px;
}

:deep(.add-event-text) {
display: inline;
}

:deep(.add-event-icon) {
display: none;
}

@media (max-width: 599px) {
:deep(.add-event-text) {
display: none;
}

:deep(.add-event-icon) {
display: inline;
}
}

💡 為什麼要用 :deep()

因為 .add-event-button 是你用 JS 動態加入到 DOM 裡的,它不是 .vue 組件內部產生的元素,因此 scoped CSS 的 attribute selector 不會套用到它。
使用 :deep() 就能讓 CSS 穿透 scoped 限制,正確影響這些外部或第三方 DOM。


小提醒:

  • :deep() 只需要加在 .vue 檔的 scoped <style>
  • 如果你改成 <style> 沒有 scoped,就不需要 :deep(),但會全域影響整個網站樣式

你要不要我幫你整理成完整的 RWD calendar 按鈕小樣板?還是你想自己組合試試?😄

當然可以,這裡是整理後的版本,包含以下幾個重點:

✅ 使用 :deep() 讓按鈕樣式正確套用
✅ 按鈕插入 .fc-daygrid-day-frame 中,保持版面整潔
✅ 保留點擊事件,可以擴充成開啟表單功能
✅ 結構清楚,註解清晰,方便日後維護


✅ 整理後的程式碼如下:

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
<template>
<div>
<h2>我的行事曆</h2>
<div ref="calendarRef" id="calendar"></div>
</div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const calendarRef = ref(null)

onMounted(() => {
if (window.FullCalendar && window.FullCalendar.Calendar) {
const calendar = new window.FullCalendar.Calendar(calendarRef.value, {
initialView: 'dayGridMonth',
locale: 'zh-tw',
events: [
{
title: '測試活動',
start: new Date().toISOString().split('T')[0], // 今天
}
],
dateClick(info) {
// 🧪 印出 DOM 結構可供除錯觀察
console.log(info.dayEl.outerHTML)

// 移除已存在的新增按鈕
document.querySelectorAll('.add-event-button').forEach(btn => btn.remove())

// ✅ 找到可插入的區塊(不是 dayEl 自己,避免 layout 混亂)
const cellEl = info.dayEl.querySelector('.fc-daygrid-day-frame')
if (!cellEl) return

// 建立按鈕元素
const button = document.createElement('button')
button.textContent = '新增活動'
button.className = 'add-event-button'

// 設定點擊行為
button.onclick = () => {
alert(`你點了 ${info.dateStr},這裡可以打開活動編輯表單!`)
}

// 插入到 cell 中
cellEl.appendChild(button)
}
})
calendar.render()
} else {
console.error('FullCalendar 尚未載入,請檢查 index.html CDN script。')
}
})
</script>

<style scoped>
#calendar {
max-width: 800px;
margin: 20px auto;
}

/* ✅ 使用 :deep() 讓樣式能穿透 scoped 套用到 JS 動態加的按鈕 */
:deep(.add-event-button) {
background-color: #1e2b37;
color: white;
border: none;
padding: 2px 6px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
</style>

如果你要進一步做 RWD 的圖示按鈕切換(例如手機只顯示 icon),我可以再幫你加入 @media 和 icon 的樣式結構 👌
要不要我幫你做那一段也一起整進來?

太好了,我幫你把 RWD 版本整合進來了 ✅
目標是:

  • 電腦寬度下顯示「新增活動」文字按鈕
  • 手機寬度下變成只顯示 icon(使用 emoji 作為示意,可換成 Font Awesome 等)

✅ 完整整合版:含 :deep() + RWD 響應式樣式

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
<template>
<div>
<h2>我的行事曆</h2>
<div ref="calendarRef" id="calendar"></div>
</div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const calendarRef = ref(null)

onMounted(() => {
if (window.FullCalendar && window.FullCalendar.Calendar) {
const calendar = new window.FullCalendar.Calendar(calendarRef.value, {
initialView: 'dayGridMonth',
locale: 'zh-tw',
events: [
{
title: '測試活動',
start: new Date().toISOString().split('T')[0],
}
],
dateClick(info) {
console.log(info.dayEl.outerHTML)

// 移除舊按鈕
document.querySelectorAll('.add-event-button').forEach(btn => btn.remove())

const cellEl = info.dayEl.querySelector('.fc-daygrid-day-frame')
if (!cellEl) return

// 建立按鈕
const button = document.createElement('button')
button.className = 'add-event-button'
button.innerHTML = `<span class="text">新增活動</span><span class="icon">➕</span>` // icon 可改用 Font Awesome

button.onclick = () => {
alert(`你點了 ${info.dateStr},這裡可以打開活動編輯表單!`)
}

cellEl.appendChild(button)
}
})
calendar.render()
} else {
console.error('FullCalendar 尚未載入,請檢查 index.html CDN script。')
}
})
</script>

<style scoped>
#calendar {
max-width: 800px;
margin: 20px auto;
}

/* ✅ 基本樣式:使用 :deep() 讓 scoped CSS 有效 */
:deep(.add-event-button) {
background-color: #1e2b37;
color: white;
border: none;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
gap: 4px;
}

/* ✅ 預設顯示文字與 icon */
:deep(.add-event-button .icon) {
display: none;
}

:deep(.add-event-button .text) {
display: inline;
}

/* ✅ 手機寬度下改為只顯示 icon */
@media (max-width: 600px) {
:deep(.add-event-button .text) {
display: none;
}
:deep(.add-event-button .icon) {
display: inline;
font-size: 16px;
}
}
</style>

🔍 測試方式建議:

  1. 開啟開發者工具 → 切換手機預覽模式看看是否成功切換
  2. 若有安裝 icon 套件(如 Font Awesome),可將 改為 <i class="fas fa-plus"></i>

想進一步加 popup 表單編輯活動,或改用 modal?我也可以幫你整合進來喔!要嗎?😎