iT邦幫忙

2021 iThome 鐵人賽

DAY 30
3
Modern Web

排版神器 Tailwind CSS~和兔兔一起快速上手漂亮的元件開發!系列 第 31

Day 30:「很刺眼,這樣太亮了啦!」- 深色模式切換開關

Day30-Banner-not-yet

「最近眼睛都一直盯著電腦,超痠的」
「而且這台螢幕還壞掉,不能調整亮度」

這樣啊 ... 辛苦了,
不過可以不用調亮度啊,把主題換成深色主題就好了!

深色主題?

齁,你不知道這個喔? 現在越來越多軟體和網站支援了欸,你可以把主題配色換成深色版,這樣眼睛就輕鬆多了啦~

「哦哦,原來還有這回事喔,那我 ...」

你是要說你想學,是嗎!?
那我就教教你怎麼在 Tailwind 弄出深色模式的頁面吧!

「Tailw ... 呃 ... 好 ...」

carrotPoint 一言不合就建立元件

首先,在專案裡的 ./src/components 資料夾中新增一個 DarkModeSwitcher.vue 的元件:

緊接著:

<template>
  
</template>

<script>
export default {
  name: "DarkModeSwitcher",
}
</script>

因為我們最後會需要直向美美的排列,所以改一下 App.vue 的樣式,接著把元件新增到畫面中:

<template>
  <div :class="[
      'w-screen h-screen',
      'p-10',
      'flex flex-col items-center',
      'gap-10',
      'transition-all duration-300'
    ]"
  >
    <DarkModeSwitcher />
  </div>
</template>

<script>
import DarkModeSwitcher from './components/DarkModeSwitcher.vue'

export default {
  data() {
    return {
    
    }
  },
  components: {
    DarkModeSwitcher,
  }
}
</script>

一如往常的流程,閉著眼睛都能操作了吧~
下一步!
 

carrotPoint 深色模式切換開關


還記得我們在 Day 16 的 JIT 模式練習中做過這個 Toggle Switch 嗎?

這次算是它的延伸哦!

首先,來看一下我們這次要做的切換開關大概的樣子:


可以發現底部的圓角矩形只有邊框顏色底色的變化,然後上面的撥鈕則是會左右橫移,而撥鈕中間的圖案會呈現太陽與月亮的切換

感覺不難對吧?

沒關係,我們一步一步慢慢來。

Switch 基本款

我們的 Switch 可以從 Day 16 做過的來修改,基本上變化不大,先做一半就好,然後大概會像是這個樣子:

<label class="block">
  <div class="border-4 box-content w-20 h-10 rounded-full bg-yellow-400">
    <div class="rounded-full w-1/2 h-full scale-75 bg-white/75">
    </div>
  </div>
</label>

漂亮! 隨便做隨便美~
接著我們來做按鈕切換的功能吧!

好,那我們 ...

「等等啊兔兔! 怎麼就直接開始了? 不是應該要到動起來的段落嗎? 這個段落不是通常都只有做 CSS 切版的部分嘛! 怎麼突然就 ...」

欸欸欸,別緊張啦~

其實啊,CSS 能做到的部分非常的多,所以若是可以的話,能用 CSS 處理的東西就用 CSS 處理掉,別用到 JS 了!

還記得我們在 Day 16 搭配 label + input 使用 Tailwind 的 peer 變化模式就可以做到切換的效果嗎?

可是 peer 有一個缺點,就是它只能吃到在自己後面且跟自己同一層的元素。 這其實沒什麼不好,只是會讓能夠做出來的效果被侷限住了。

所以兔兔這邊要介紹個新東西叫做 ... Flagger

Tailwind Flagger

Flagger 是兔兔覺得「 peer 不夠用,還想要在更方便啊!」時所開發出來的產物,用法與 peer 差不多,但 Flagger 具有頻道。 以往 peer 只能有一個,你想要有第二個觸發點是做不到的,但 Flagger 可以分開,用名稱來對應,比如 flag-1flag-2 可以各自觸發 flag-1-checked:flag-2-checked: 之類的。

只是這是一個 Tailwind 的插件,必須要先在專案中安裝:

npm install -D tailwind-flagger

安裝好後,開啟專案根目錄中的 tailwind.config.js,然後把插件加到 tailwind 的配置中:

// const colors = require('tailwindcss/colors')
+  const flagger = require('tailwind-flagger')

module.exports = {
  mode: 'jit',
  purge: ['index.html','./src/**/*.{js,jsx,ts,tsx,vue,html}'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  plugins: [
+   flagger
  ],
}

增加完畢之後,我們開始來撰寫切換的功能。先在元件裡面加上一個 <input> 元素,且類型是 checkbox

<label class="block">
  <input type="checkbox" />
  <div class="border-4 box-content w-20 h-10 rounded-full bg-yellow-400">
    <div class="rounded-full w-1/2 h-full scale-75 bg-white/75">
    </div>
  </div>
</label>

加完後,我們幫 <input> 加上樣式 "sr-only flag-1",我們這邊就是用 flag 來取代 peer 了:

<label class="block">
  <input
    type="checkbox"
    class="sr-only flag-1"
  />
  <div class="border-4 box-content w-20 h-10 rounded-full bg-yellow-400">
    <div class="rounded-full w-1/2 h-full scale-75 bg-white/75">
    </div>
  </div>
</label>

OK 了嗎? 那我們就開始來做樣式變化了!

這邊來列出一下要做的事情:

  • 切換開關底部矩形: 平時邊框色是預設,背景色是黃色,切換後邊框顏色變成深灰色,背景色變為藍色
  • 撥鈕: 平時在左邊,切換後位置跑到右邊
  • 別忘了要加上過渡效果,讓它看起來絲滑柔順

基於上面這些點,我們就可以這樣寫:

<label class="block">
  <input
    type="checkbox"
    class="sr-only flag-1"
  />
  <div
    :class="[
      'border-4 box-content w-20 h-10 rounded-full',
      'bg-yellow-400 flag-1-checked:bg-blue-900',
      'flag-1-checked:border-gray-600',
      'transition-all duration-300'
    ]"
  >
    <div
      :class="[
        'rounded-full w-1/2 h-full scale-75',
        'translate-x-0 flag-1-checked:translate-x-full',
        'bg-white/75 flag-1-checked:bg-white/50',
        'transition-all duration-300'
      ]"
    >
    </div>
  </div>
</label>


有,效果出來了! 但千萬別只滿足於此呀!

我們還可以加上 icon 上它看起來更有模有樣。icon 一樣上 heroicons,會有一組實心的太陽與月亮的 icon,不過兔兔會直接貼在這裡:

<!-- SUN -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd" />
</svg>

<!-- MOON -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
</svg>

然後,其實因為這個 svg 是經過處理的,所以最外層都長一樣,大小也相同,所以我們可以把它稍微合併起來:

<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
  <!-- SUN -->
  <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd" />

  <!-- MOON -->
  <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
</svg>

接著放到撥鈕中,稍做調整一下應該會變成這個樣子:

  ...
<div
  :class="[
    'rounded-full w-1/2 h-full scale-75',
    'translate-x-0 flag-1-checked:translate-x-full',
    'bg-white/75 flag-1-checked:bg-white/50',
    'transition-all duration-300',
    'flex justify-center items-center'
  ]"
>
  <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
    <!-- SUN -->
    <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd" />
    <!-- MOON -->
    <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
  </svg>
</div>
  ...

會變成這樣!太陽和月亮重疊在一起了。

不過這當然不是我們要的效果,我們必須一樣分成切換前和切換後來顯示。調整一下顏色和顯示時機,然後我們可以直接把 class 寫在 svg 中的 path 上:

<div
  :class="[
    'rounded-full w-1/2 h-full scale-75',
    'translate-x-0 flag-1-checked:translate-x-full',
    'bg-white/75 flag-1-checked:bg-white/50',
    'transition-all duration-300',
    'flex justify-center items-center'
  ]"
>
  <svg xmlns="http://www.w3.org/2000/svg"
    :class="[
      'h-7 w-7',
      'text-yellow-500 flag-1-checked:text-white'
    ]"
    viewBox="0 0 20 20" fill="currentColor"
  >
    <path class="flag-1-checked:opacity-0 transition-all duration-300" fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd" />
    <path class="opacity-0 flag-1-checked:opacity-100 transition-all duration-300" d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
  </svg>
</div>


效果很華麗呢~

樣式的部分都完成了,
那麼接下來我們就可以開始完善它身為深色模式切換開關的功能吧!
 

carrotPoint 動起來

嘿,你期待的動起來階段到囉!

在我們做和深色模式相關的功能之前,我們必須先來了解一下 Tailwind 中的深色模式。

Tailwind 中的深色模式

Day 2 淺談核心概念時,兔兔就曾經講過了深色模式的特別點。深色模式分為兩種,一種是依照系統偏好設定的,一種是可以手動切換深 / 淺色的,而今天的內容我們兩種都會做到。

在 Tailwind 中,若是想要開啟深色模式,我們必須到配置檔 tailwind.config.js 中調整功能的參數。也就是 tailwind.config.js 中的 darkMode 選項:

// const colors = require('tailwindcss/colors')
const flagger = require('tailwind-flagger')

module.exports = {
  mode: 'jit',
  purge: ['index.html','./src/**/*.{js,jsx,ts,tsx,vue,html}'],
+ darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  plugins: [
    flagger
  ],
}

這邊來講解一下 darkMode 選項中各參數所代表的意義:

  • false:關閉深色模式,在語法智慧提示中也不會跳出深色模式的相關語法
  • "media":根據系統預設值,語法提示中會出現深色模式相關語法
  • "class":根據是否有 class 名稱 dark,語法提示中會出現深色模式相關語法

你可能不太好理解參數 "media""class" 實際上的差別,我們這裡稍做舉例:

<div>
  <div class="text-black dark:text-white">
    嗨,我是兔兔
  </div>
</div>

一般來說,我們要在 tailwind 開啟深色模式功能後,若要使用深色模式,我們只需要在前面加上 dark: 前綴詞,那麼這個樣式就會只在是深色時觸發

當我們的參數是 "media" 時,上面的樣式變化只會根據系統預設值觸發,也就是你的電腦主題設定為深色時,文字就會變成白色而不是黑色。 (頁面需重整)

但參數改成 "class" 之後,會發現即使電腦主題色為深色,樣式仍然不會切換過去,為什麼呢?

那是因為前面所說的,要看是否有 dark 這個 class 名稱,舉個例:

<div class="dark">
  <div class="text-black dark:text-white">
    A
  </div>
</div>

<div>
  <div class="text-black dark:text-white">
    B
  </div>
</div>

實作一次會發現,A 的文字變成白色了,可是 B 還是黑色。 這就是完全的手動切換,靠著是否是 .dark子元素來判斷是否在編譯時要使深色模式生效,這時則與系統設定值無關了。

所以通常為了使整個頁面都能是 .dark 的子元素,我們會選擇用 js 在 body 標籤上動態新增 / 移除 .dark 來達到深淺色模式的手動切換。

實作深色模式

我們前面說過,要同時做到可以依照系統設定值,又要能夠手動切換。如果想要兩種都有,我們這邊應該要選擇 "class" 參數才可以:

// const colors = require('tailwindcss/colors')
const flagger = require('tailwind-flagger')

module.exports = {
  mode: 'jit',
  purge: ['index.html','./src/**/*.{js,jsx,ts,tsx,vue,html}'],
- darkMode: false, // or 'media' or 'class'
+ darkMode: "class", // or 'media' or 'class'
  theme: {
    extend: {},
  },
  plugins: [
    flagger
  ],
}

這樣設定值就完成了,儲存之後我們來看看其他部分。

為了監控切換開關的狀態來新增移除 .dark,我們定義個變數來儲存狀態,且使 input 跟這個變數用 v-model 同步。

但說了,是要監控,所以我們還要寫 watch。

那麼 Vue 的部分大概就會是這樣:

export default {
  name: "DarkModeSwitcher",
  data() {
    return {
      checked: false,
    }
  },
  watch: {
    checked(){
      document.body.classList.toggle('dark')
    }
  }
}

這時候去切換一下應該能看到效果。

從畫面上看不出差異哦,因為我們現在只是在 body 新增 class 而已,所以要看一下元素:

有,很成功的加上去了!

那麼我們就趕緊弄出個深色模式的頁面來測試吧!
 

carrotPoint 可能會眼睛痛的測試

首先,為了快速通關,我幫你們直接準備好頁面素材啦!

因為會用到之前做過的按鈕,所以記得加回專案中哦~

那我們就開始吧!
這邊就是準備好的素材,已經融合進 App.vue 了:

<div :class="[
    'w-screen h-screen',
    'p-10',
    'flex flex-col items-center',
    'gap-10',
    'transition-all duration-300'
  ]"
>
  <DarkModeSwitcher />

  <h1 class="text-5xl font-bold transition-all duration-700">日夜切換功能</h1>
  <span class="text-xl text-gray-500 transition-all duration-700 text-center"> 日夜切換功能,是讓小兔子的眼睛可以獲得充分的休息、減輕眼睛壓力,讓兔子們可以一直看的好遠! </span>
  <div class="flex flex-col gap-4">
    <RabbitButton text="我超喜歡 Tailwind" color="gray">
      <template v-slot:iconLeft>
        <svg class="w-6 h-6 fill-current text-red-500 transition-all" viewBox="0 0 391.837 391.837" style="enable-background:new 0 0 391.837 391.837;" xml:space="preserve">
          <g><path d="M285.257,35.528c58.743,0.286,106.294,47.836,106.58,106.58               c0,107.624-195.918,214.204-195.918,214.204S0,248.165,0,142.108c0-58.862,47.717-106.58,106.58-106.58l0,0c36.032-0.281,69.718,17.842,89.339,48.065C215.674,53.517,249.273,35.441,285.257,35.528z"/></g>
        </svg>
      </template>        
    </RabbitButton>

    <RabbitButton text="贊助兔子們" color="blue">
      <template v-slot:iconLeft>
        <svg class="w-6 h-6" viewBox="0 0 771.62 771.62">
          <g><path d="M274.41,0l1.64.53c.55.18,1.12.36,1.59.54l2.94,1.07,2.94,1.07.74.27.66.26,1.34.54,2.66,1.07,2.48,1.07c1.63.71,3.33,1.43,4.78,2.14l4.49,2.14,4.12,2.14c.67.36,1.39.71,2,1.07L308.73,15c1.3.71,2.42,1.43,3.65,2.14a95.12,95.12,0,0,1,21.48,17.12A45,45,0,0,1,344,51.36c.45,1.42.74,2.85,1.06,4.28s.6,2.85.86,4.28q.82,4.28,1.4,8.56a132.6,132.6,0,0,1,.37,34.24A176.52,176.52,0,0,1,339.51,137c-3.85,11.42-8.21,22.83-12.37,34.24l-1.58,4.28-1.51,4.28c-1,2.86-2,5.71-3,8.56-1.92,5.71-3.65,11.42-5.77,17.12a227.59,227.59,0,0,1-16,34.24c-1.65,2.85-3.35,5.71-5.18,8.56s-3.72,5.71-5.78,8.56a148.13,148.13,0,0,1-14,17.12h-1a147.09,147.09,0,0,1-14-17.12c-2.07-2.85-3.91-5.71-5.79-8.56s-3.52-5.71-5.17-8.56a227.59,227.59,0,0,1-16-34.24c-2.12-5.7-3.85-11.41-5.77-17.12-.95-2.85-2-5.7-3-8.56l-1.5-4.28-1.58-4.28c-4.16-11.41-8.53-22.82-12.38-34.24a175.76,175.76,0,0,1-8.16-34.23,132.6,132.6,0,0,1,.37-34.24c.38-2.86.85-5.71,1.39-8.56.27-1.43.57-2.86.87-4.28s.61-2.86,1-4.28A45.18,45.18,0,0,1,214,34.24a95,95,0,0,1,21.49-17.12c1.22-.71,2.35-1.43,3.65-2.14L241,13.91c.64-.36,1.36-.71,2-1.07l4.12-2.14,4.49-2.14c1.45-.71,3.15-1.43,4.78-2.14l2.48-1.07,2.66-1.07,1.33-.54.67-.26.74-.27,2.94-1.07,2.94-1.07c.47-.18,1-.36,1.58-.54L273.41,0Z" style="fill:#39b54a" /><path d="M0,273.41l.53-1.65c.18-.54.36-1.11.54-1.58l1.07-2.94,1.07-2.94.27-.74.26-.67.54-1.33,1.07-2.66,1.07-2.48c.71-1.63,1.43-3.33,2.14-4.78l2.14-4.49L12.84,243c.36-.67.71-1.39,1.07-2L15,239.09c.71-1.3,1.43-2.43,2.14-3.65A95,95,0,0,1,34.24,214a45.18,45.18,0,0,1,17.12-10.13c1.42-.44,2.85-.74,4.28-1s2.85-.6,4.28-.87c2.85-.54,5.7-1,8.56-1.39a132.6,132.6,0,0,1,34.24-.37A175.76,175.76,0,0,1,137,208.3c11.42,3.85,22.83,8.22,34.24,12.38l4.28,1.58,4.28,1.5c2.86,1,5.71,2,8.56,3,5.71,1.92,11.42,3.65,17.12,5.77a227.59,227.59,0,0,1,34.24,16c2.85,1.65,5.71,3.35,8.56,5.17s5.71,3.72,8.56,5.79a147.09,147.09,0,0,1,17.12,14v1a148.13,148.13,0,0,1-17.12,14c-2.85,2.06-5.71,3.91-8.56,5.78s-5.71,3.53-8.56,5.18a227.59,227.59,0,0,1-34.24,16c-5.7,2.12-11.41,3.85-17.12,5.77-2.85.94-5.7,2-8.56,3l-4.28,1.51-4.28,1.58c-11.41,4.16-22.82,8.52-34.24,12.37a176.52,176.52,0,0,1-34.23,8.17,132.6,132.6,0,0,1-34.24-.37q-4.29-.57-8.56-1.4c-1.43-.26-2.86-.56-4.28-.86s-2.86-.61-4.28-1.06a45,45,0,0,1-17.12-10.13,95.12,95.12,0,0,1-17.12-21.48c-.71-1.23-1.43-2.35-2.14-3.65l-1.07-1.91c-.36-.64-.71-1.36-1.07-2l-2.14-4.12-2.14-4.49c-.71-1.45-1.43-3.15-2.14-4.78l-1.07-2.48-1.07-2.66-.54-1.34-.26-.66-.27-.74-1.07-2.94-1.07-2.94c-.18-.47-.36-1-.54-1.59L0,274.41Z" style="fill:#39b54a" /><path d="M23.43,22.72c4.48-1.86,8.48-3.25,12.3-4.46l2.86-.9,2.73-.77c1.81-.5,3.66-1.05,5.34-1.42l5.14-1.23c1.65-.33,3.32-.7,4.9-1,3.22-.61,6.26-1,9.25-1.42A104.3,104.3,0,0,1,96.82,12a64.07,64.07,0,0,1,22.85,8.51c6.27,4.17,12.24,8.66,18,13.33A220.74,220.74,0,0,1,169.29,65a281.92,281.92,0,0,1,25.59,37.11c7.73,13.18,15.1,26.71,22.6,40.11l2.81,5,2.85,5c1.91,3.32,3.8,6.66,5.76,9.92,3.87,6.58,7.85,13,11.58,19.77a341.68,341.68,0,0,1,20.07,42.64c1.44,3.79,2.85,7.6,4.17,11.5s2.6,7.86,3.75,11.93a189.78,189.78,0,0,1,5.79,25.57l-.7.7A189.78,189.78,0,0,1,248,268.47c-4.07-1.15-8-2.46-11.93-3.75s-7.71-2.73-11.5-4.17a341.68,341.68,0,0,1-42.64-20.07c-6.72-3.73-13.19-7.71-19.77-11.58-3.26-2-6.6-3.85-9.92-5.76l-5-2.85-5-2.81c-13.4-7.5-26.93-14.87-40.11-22.6A281.92,281.92,0,0,1,65,169.29a220.74,220.74,0,0,1-31.11-31.6c-4.67-5.78-9.16-11.75-13.33-18A64.07,64.07,0,0,1,12,96.82,104.3,104.3,0,0,1,11.55,66c.38-3,.81-6,1.42-9.25.27-1.58.64-3.25,1-4.9l1.23-5.14c.37-1.68.92-3.53,1.42-5.34l.77-2.73.9-2.86c1.21-3.82,2.6-7.82,4.46-12.3Z" style="fill:#00f444" /><path d="M755.88,768.61c-1.81.42-3.44.67-5.13,1s-3.28.51-4.9.75l-4.68.53-4.53.39c-5.92.39-11.49.43-16.87.28a144.61,144.61,0,0,1-29.2-4,119.35,119.35,0,0,1-12.75-3.84c-4.05-1.48-8-3-12-4.55-8-3-15.91-6.2-23.84-9.33-15.71-6.42-31.21-13-46.37-20s-30-14.21-44.7-21.65L528.94,697,507.1,685.61l-21.87-11.3c-7.32-3.74-14.58-7.54-22-11.22l-11-5.55-11.1-5.49L418.9,641.11c-14.83-7.29-29.43-14.81-43.5-22.86l-10.49-6.1-10.35-6.23q-10.31-6.28-20.49-12.7-20.34-12.83-39.21-27.13-9.47-7.14-18.67-14.51a149.44,149.44,0,0,1-16.9-16.28c-5.26-5.8-10.46-11.66-16.08-17.1a95.13,95.13,0,0,0-9-7.63,73.63,73.63,0,0,1-8.93-7.65,48.31,48.31,0,0,1-3.8-4.5c-1.16-1.6-2.31-3.22-3.42-4.88q-3.34-4.95-6.34-10.24c-4-7.06-7.47-14.65-11.12-22.06-.9-1.86-1.84-3.68-2.76-5.53S196,452,195,450.29c-2-3.52-4.37-6.69-6.51-10.08a37.85,37.85,0,0,1-5-11.54c-1.16-4.38-1.53-9.53-2.17-14.42-.32-2.45-.55-5-.79-7.5s-.52-5-.68-7.62c-.38-5.15-.64-10.42-.7-15.89s0-11.08.3-16.89l.18-4.32.28-4.43c.21-3,.37-5.9.61-8.91.53-6.05,1-12,1.62-18.21.21-1.58.33-3.09.61-4.75l.4-2.48.21-1.24.26-1.3c.17-.86.38-1.76.61-2.68s.47-1.86.73-2.8.58-2,.86-2.94.71-2.09,1.06-3.14l1.09-3.16,1.33-3.4,1.33-3.41,1.54-3.6c2-4.76,4.24-9.78,7.16-15.47l4.73-8.87,2.81-4.88,1.4-2.44.7-1.22.82-1.34L213,256l.81-1.33,1-1.49,1.94-3,3.89-6,1-1.49c.15-.24.33-.51.53-.8l.59-.84,2.33-3.37,12.72-12.72,3.37-2.33.84-.59.8-.53,1.49-1,6-3.89,3-1.94,1.49-1L256,213l5.33-3.26,1.34-.82,1.22-.7,2.44-1.4,4.88-2.81,8.87-4.73c5.69-2.92,10.71-5.18,15.47-7.16l3.6-1.54,3.41-1.33,3.4-1.33,3.16-1.09c1.05-.35,2.14-.75,3.14-1.06s2-.63,2.94-.86,1.91-.53,2.8-.73,1.82-.44,2.68-.61l1.3-.26,1.24-.21,2.48-.4c1.66-.28,3.17-.4,4.75-.61,6.2-.67,12.16-1.09,18.21-1.62,3-.24,5.94-.4,8.91-.61l4.43-.28,4.32-.18c5.81-.28,11.43-.37,16.89-.3s10.74.32,15.89.7c2.61.16,5.08.45,7.62.68s5.05.47,7.5.79c4.89.64,10,1,14.42,2.17a37.85,37.85,0,0,1,11.54,5c3.39,2.14,6.56,4.5,10.08,6.51,1.74,1,3.58,2,5.42,2.88s3.67,1.86,5.53,2.76c7.41,3.65,15,7.12,22.06,11.12q5.29,3,10.24,6.34c1.66,1.11,3.28,2.26,4.88,3.42a48.31,48.31,0,0,1,4.5,3.8,73.63,73.63,0,0,1,7.65,8.93,95.13,95.13,0,0,0,7.63,9c5.44,5.62,11.3,10.82,17.1,16.08a149.44,149.44,0,0,1,16.28,16.9q7.36,9.22,14.51,18.67,14.34,18.83,27.13,39.21,6.43,10.17,12.7,20.49l6.23,10.35,6.1,10.49c8,14.07,15.57,28.67,22.86,43.5l10.94,22.23,5.49,11.1,5.55,11c3.68,7.38,7.48,14.64,11.22,22l11.3,21.87L697,528.94l11.24,21.93q11.16,22,21.65,44.7c7,15.16,13.57,30.66,20,46.37,3.13,7.93,6.33,15.79,9.33,23.84,1.51,4,3.07,8,4.55,12a119.35,119.35,0,0,1,3.84,12.75,144.61,144.61,0,0,1,4,29.2c.15,5.38.11,11-.28,16.87l-.39,4.53-.53,4.68c-.24,1.62-.43,3.19-.75,4.9s-.56,3.32-1,5.13Z" style="fill:#f15a24" /></g>
        </svg>
      </template>
    </RabbitButton>
  </div>
</div>

長這樣!

基本的樣式都好了,現在我們來讓它深色起來吧

先從最外層的 div 下手,增加一個深色模式時背景色會變深的樣式:

<div :class="[
      'w-screen h-screen',
      'p-10',
      'flex flex-col items-center',
      'gap-10',
      'dark:bg-gray-900'
      'transition-all duration-300'
    ]"
  >
    <DarkModeSwitcher />
  ...

有沒有~ 不是不~
效果超級讚的啦~

那接著,一口氣把其他的樣式都改成符合深色模式看了不會不清楚或刺眼的顏色吧:

<DarkModeSwitcher  />
    
<h1 class="text-5xl dark:text-gray-300 font-bold transition-all duration-300">日夜切換功能</h1>
<span class="text-xl text-gray-500 dark:text-gray-400 transition-all duration-300 text-center"> 日夜切換功能,是讓小兔子的眼睛可以獲得充分的休息、減輕眼睛壓力,讓兔子們可以一直看的好遠! </span>
<div class="flex flex-col gap-4">
  <RabbitButton
    text="我超喜歡 Tailwind" color="gray"
    class="dark:bg-gray-600 dark:hover:bg-gray-500 dark:active:bg-gray-700 transition-all duration-300"
  >
    <template v-slot:iconLeft>
      <svg class="w-6 h-6 fill-current text-red-500 dark:text-pink-400 transition-all duration-300" viewBox="0 0 391.837 391.837" style="enable-background:new 0 0 391.837 391.837;" xml:space="preserve">
        <g><path d="M285.257,35.528c58.743,0.286,106.294,47.836,106.58,106.58               c0,107.624-195.918,214.204-195.918,214.204S0,248.165,0,142.108c0-58.862,47.717-106.58,106.58-106.58l0,0c36.032-0.281,69.718,17.842,89.339,48.065C215.674,53.517,249.273,35.441,285.257,35.528z"/></g>
      </svg>
    </template>        
  </RabbitButton>

  <RabbitButton
    text="贊助兔子們" color="blue"
    class="dark:bg-blue-600 dark:hover:bg-blue-500 dark:active:bg-blue-700 transition-all duration-300"
  >
    <template v-slot:iconLeft>
      <svg class="w-6 h-6" viewBox="0 0 771.62 771.62">
        <g><path d="M274.41,0l1.64.53c.55.18,1.12.36,1.59.54l2.94,1.07,2.94,1.07.74.27.66.26,1.34.54,2.66,1.07,2.48,1.07c1.63.71,3.33,1.43,4.78,2.14l4.49,2.14,4.12,2.14c.67.36,1.39.71,2,1.07L308.73,15c1.3.71,2.42,1.43,3.65,2.14a95.12,95.12,0,0,1,21.48,17.12A45,45,0,0,1,344,51.36c.45,1.42.74,2.85,1.06,4.28s.6,2.85.86,4.28q.82,4.28,1.4,8.56a132.6,132.6,0,0,1,.37,34.24A176.52,176.52,0,0,1,339.51,137c-3.85,11.42-8.21,22.83-12.37,34.24l-1.58,4.28-1.51,4.28c-1,2.86-2,5.71-3,8.56-1.92,5.71-3.65,11.42-5.77,17.12a227.59,227.59,0,0,1-16,34.24c-1.65,2.85-3.35,5.71-5.18,8.56s-3.72,5.71-5.78,8.56a148.13,148.13,0,0,1-14,17.12h-1a147.09,147.09,0,0,1-14-17.12c-2.07-2.85-3.91-5.71-5.79-8.56s-3.52-5.71-5.17-8.56a227.59,227.59,0,0,1-16-34.24c-2.12-5.7-3.85-11.41-5.77-17.12-.95-2.85-2-5.7-3-8.56l-1.5-4.28-1.58-4.28c-4.16-11.41-8.53-22.82-12.38-34.24a175.76,175.76,0,0,1-8.16-34.23,132.6,132.6,0,0,1,.37-34.24c.38-2.86.85-5.71,1.39-8.56.27-1.43.57-2.86.87-4.28s.61-2.86,1-4.28A45.18,45.18,0,0,1,214,34.24a95,95,0,0,1,21.49-17.12c1.22-.71,2.35-1.43,3.65-2.14L241,13.91c.64-.36,1.36-.71,2-1.07l4.12-2.14,4.49-2.14c1.45-.71,3.15-1.43,4.78-2.14l2.48-1.07,2.66-1.07,1.33-.54.67-.26.74-.27,2.94-1.07,2.94-1.07c.47-.18,1-.36,1.58-.54L273.41,0Z" style="fill:#39b54a" /><path d="M0,273.41l.53-1.65c.18-.54.36-1.11.54-1.58l1.07-2.94,1.07-2.94.27-.74.26-.67.54-1.33,1.07-2.66,1.07-2.48c.71-1.63,1.43-3.33,2.14-4.78l2.14-4.49L12.84,243c.36-.67.71-1.39,1.07-2L15,239.09c.71-1.3,1.43-2.43,2.14-3.65A95,95,0,0,1,34.24,214a45.18,45.18,0,0,1,17.12-10.13c1.42-.44,2.85-.74,4.28-1s2.85-.6,4.28-.87c2.85-.54,5.7-1,8.56-1.39a132.6,132.6,0,0,1,34.24-.37A175.76,175.76,0,0,1,137,208.3c11.42,3.85,22.83,8.22,34.24,12.38l4.28,1.58,4.28,1.5c2.86,1,5.71,2,8.56,3,5.71,1.92,11.42,3.65,17.12,5.77a227.59,227.59,0,0,1,34.24,16c2.85,1.65,5.71,3.35,8.56,5.17s5.71,3.72,8.56,5.79a147.09,147.09,0,0,1,17.12,14v1a148.13,148.13,0,0,1-17.12,14c-2.85,2.06-5.71,3.91-8.56,5.78s-5.71,3.53-8.56,5.18a227.59,227.59,0,0,1-34.24,16c-5.7,2.12-11.41,3.85-17.12,5.77-2.85.94-5.7,2-8.56,3l-4.28,1.51-4.28,1.58c-11.41,4.16-22.82,8.52-34.24,12.37a176.52,176.52,0,0,1-34.23,8.17,132.6,132.6,0,0,1-34.24-.37q-4.29-.57-8.56-1.4c-1.43-.26-2.86-.56-4.28-.86s-2.86-.61-4.28-1.06a45,45,0,0,1-17.12-10.13,95.12,95.12,0,0,1-17.12-21.48c-.71-1.23-1.43-2.35-2.14-3.65l-1.07-1.91c-.36-.64-.71-1.36-1.07-2l-2.14-4.12-2.14-4.49c-.71-1.45-1.43-3.15-2.14-4.78l-1.07-2.48-1.07-2.66-.54-1.34-.26-.66-.27-.74-1.07-2.94-1.07-2.94c-.18-.47-.36-1-.54-1.59L0,274.41Z" style="fill:#39b54a" /><path d="M23.43,22.72c4.48-1.86,8.48-3.25,12.3-4.46l2.86-.9,2.73-.77c1.81-.5,3.66-1.05,5.34-1.42l5.14-1.23c1.65-.33,3.32-.7,4.9-1,3.22-.61,6.26-1,9.25-1.42A104.3,104.3,0,0,1,96.82,12a64.07,64.07,0,0,1,22.85,8.51c6.27,4.17,12.24,8.66,18,13.33A220.74,220.74,0,0,1,169.29,65a281.92,281.92,0,0,1,25.59,37.11c7.73,13.18,15.1,26.71,22.6,40.11l2.81,5,2.85,5c1.91,3.32,3.8,6.66,5.76,9.92,3.87,6.58,7.85,13,11.58,19.77a341.68,341.68,0,0,1,20.07,42.64c1.44,3.79,2.85,7.6,4.17,11.5s2.6,7.86,3.75,11.93a189.78,189.78,0,0,1,5.79,25.57l-.7.7A189.78,189.78,0,0,1,248,268.47c-4.07-1.15-8-2.46-11.93-3.75s-7.71-2.73-11.5-4.17a341.68,341.68,0,0,1-42.64-20.07c-6.72-3.73-13.19-7.71-19.77-11.58-3.26-2-6.6-3.85-9.92-5.76l-5-2.85-5-2.81c-13.4-7.5-26.93-14.87-40.11-22.6A281.92,281.92,0,0,1,65,169.29a220.74,220.74,0,0,1-31.11-31.6c-4.67-5.78-9.16-11.75-13.33-18A64.07,64.07,0,0,1,12,96.82,104.3,104.3,0,0,1,11.55,66c.38-3,.81-6,1.42-9.25.27-1.58.64-3.25,1-4.9l1.23-5.14c.37-1.68.92-3.53,1.42-5.34l.77-2.73.9-2.86c1.21-3.82,2.6-7.82,4.46-12.3Z" style="fill:#00f444" /><path d="M755.88,768.61c-1.81.42-3.44.67-5.13,1s-3.28.51-4.9.75l-4.68.53-4.53.39c-5.92.39-11.49.43-16.87.28a144.61,144.61,0,0,1-29.2-4,119.35,119.35,0,0,1-12.75-3.84c-4.05-1.48-8-3-12-4.55-8-3-15.91-6.2-23.84-9.33-15.71-6.42-31.21-13-46.37-20s-30-14.21-44.7-21.65L528.94,697,507.1,685.61l-21.87-11.3c-7.32-3.74-14.58-7.54-22-11.22l-11-5.55-11.1-5.49L418.9,641.11c-14.83-7.29-29.43-14.81-43.5-22.86l-10.49-6.1-10.35-6.23q-10.31-6.28-20.49-12.7-20.34-12.83-39.21-27.13-9.47-7.14-18.67-14.51a149.44,149.44,0,0,1-16.9-16.28c-5.26-5.8-10.46-11.66-16.08-17.1a95.13,95.13,0,0,0-9-7.63,73.63,73.63,0,0,1-8.93-7.65,48.31,48.31,0,0,1-3.8-4.5c-1.16-1.6-2.31-3.22-3.42-4.88q-3.34-4.95-6.34-10.24c-4-7.06-7.47-14.65-11.12-22.06-.9-1.86-1.84-3.68-2.76-5.53S196,452,195,450.29c-2-3.52-4.37-6.69-6.51-10.08a37.85,37.85,0,0,1-5-11.54c-1.16-4.38-1.53-9.53-2.17-14.42-.32-2.45-.55-5-.79-7.5s-.52-5-.68-7.62c-.38-5.15-.64-10.42-.7-15.89s0-11.08.3-16.89l.18-4.32.28-4.43c.21-3,.37-5.9.61-8.91.53-6.05,1-12,1.62-18.21.21-1.58.33-3.09.61-4.75l.4-2.48.21-1.24.26-1.3c.17-.86.38-1.76.61-2.68s.47-1.86.73-2.8.58-2,.86-2.94.71-2.09,1.06-3.14l1.09-3.16,1.33-3.4,1.33-3.41,1.54-3.6c2-4.76,4.24-9.78,7.16-15.47l4.73-8.87,2.81-4.88,1.4-2.44.7-1.22.82-1.34L213,256l.81-1.33,1-1.49,1.94-3,3.89-6,1-1.49c.15-.24.33-.51.53-.8l.59-.84,2.33-3.37,12.72-12.72,3.37-2.33.84-.59.8-.53,1.49-1,6-3.89,3-1.94,1.49-1L256,213l5.33-3.26,1.34-.82,1.22-.7,2.44-1.4,4.88-2.81,8.87-4.73c5.69-2.92,10.71-5.18,15.47-7.16l3.6-1.54,3.41-1.33,3.4-1.33,3.16-1.09c1.05-.35,2.14-.75,3.14-1.06s2-.63,2.94-.86,1.91-.53,2.8-.73,1.82-.44,2.68-.61l1.3-.26,1.24-.21,2.48-.4c1.66-.28,3.17-.4,4.75-.61,6.2-.67,12.16-1.09,18.21-1.62,3-.24,5.94-.4,8.91-.61l4.43-.28,4.32-.18c5.81-.28,11.43-.37,16.89-.3s10.74.32,15.89.7c2.61.16,5.08.45,7.62.68s5.05.47,7.5.79c4.89.64,10,1,14.42,2.17a37.85,37.85,0,0,1,11.54,5c3.39,2.14,6.56,4.5,10.08,6.51,1.74,1,3.58,2,5.42,2.88s3.67,1.86,5.53,2.76c7.41,3.65,15,7.12,22.06,11.12q5.29,3,10.24,6.34c1.66,1.11,3.28,2.26,4.88,3.42a48.31,48.31,0,0,1,4.5,3.8,73.63,73.63,0,0,1,7.65,8.93,95.13,95.13,0,0,0,7.63,9c5.44,5.62,11.3,10.82,17.1,16.08a149.44,149.44,0,0,1,16.28,16.9q7.36,9.22,14.51,18.67,14.34,18.83,27.13,39.21,6.43,10.17,12.7,20.49l6.23,10.35,6.1,10.49c8,14.07,15.57,28.67,22.86,43.5l10.94,22.23,5.49,11.1,5.55,11c3.68,7.38,7.48,14.64,11.22,22l11.3,21.87L697,528.94l11.24,21.93q11.16,22,21.65,44.7c7,15.16,13.57,30.66,20,46.37,3.13,7.93,6.33,15.79,9.33,23.84,1.51,4,3.07,8,4.55,12a119.35,119.35,0,0,1,3.84,12.75,144.61,144.61,0,0,1,4,29.2c.15,5.38.11,11-.28,16.87l-.39,4.53-.53,4.68c-.24,1.62-.43,3.19-.75,4.9s-.56,3.32-1,5.13Z" style="fill:#f15a24" /></g>
      </svg>
    </template>
  </RabbitButton>
</div>

是不是很有趣呢? 這樣我們就算是完成啦~
 

carrotPoint 系統設定值

啊啊,差點就忘了!
我們還要做根據系統設定值的功能齁!

其實這個功能啊比較特別,我們要用 js 來讀取系統設定值是否是深色模式,我們在切換開關這個元件掛載時要來讀取系統設定值,然後改變撥鈕的狀態:

mounted() {
  const matchMedia =  window.matchMedia('(prefers-color-scheme: dark)')

  if(matchMedia.matches){
    this.checked = true
  }
}

這麼一來,就會根據系統的主題,在元件掛載時自動切換到對的顏色囉!

最後一個元件,也圓滿大成功啦~~
 

好的,30 天過去了,你們有覺得收穫滿滿嗎?

兔兔自己是覺得收穫滿滿哦! 平時雖然偶爾都會寫寫文章發發文章,但真的只是偶爾,這麼集中的做這件事情還是第一次呢,而且也體會到很多新東西以及在準備文章內容時重新複習到這些知識,發現又有不一樣的理解了~

很感謝大家的支持,也感謝我的隊友們!

本系列到這裡算是結束囉!
不過後面還有準備一些想分享的內容,就當作後記加碼給大家吧~ 如果兔兔還有力氣的話會照天數發文的 XDDD

carrotPoint 給你們的回家作業:


關於兔兔們:


 


( # 兔兔小聲說 )

齁,真的對大家很抱歉 XD

因為我發現內容好像越來越龐大,所以後面幾天我都整個快準備不過來,如果讓你們看到內容不完整的部分真的 sorry。 不過我都有補完囉! 有些地方也有做小修改,可以再回去看一遍。

最後,真的感謝大家的支持~


上一篇
Day 29:「欸!你填一下這張表!」- 彈跳視窗、Modal
下一篇
Day 31:「不夠吃了...哪裡還有紅蘿蔔?」- Tailwind 和 Vue 的資源分享
系列文
排版神器 Tailwind CSS~和兔兔一起快速上手漂亮的元件開發!32

尚未有邦友留言

立即登入留言