iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0
Modern Web

LV的全端開發體驗系列 第 23

Day23 再談前端組件設計-Button Component

  • 分享至 

  • xImage
  •  

昨天提到把一個題目的組件拆出來,讓它可以用在測驗和結果的顯示上,這讓我們在網頁的結構上和元件的使用上便利不少,不過一路看下來的朋友應該也注意到了,有不少的前端項目,比如 button 使用tailwind來建立外觀雖然很方便,但是原始碼的一堆 class 會讓有強迫症如我的人看了很不舒服,有些東西,不拆也沒關係,但拆得乾淨,自己晚上會睡得比較安穩...

Button

按鈕是很常使用的網頁元件,因為tailwind初始設定就把button的屬性都重設得乾乾淨的,所以如果你直接使用 button 標籤的話,只會看到文字而已:

既然我們知道拆組件除了把標籤和class封裝起,更可以加入屬性和行為,所以我們想來模仿 bootstrap 的按鈕,做出一個有彈性的按鈕,但我們先就外觀來做調整就好了,行為的部份可以日後再添加;
resources\js\QuizComponents\QuizButton.vue

<template>
    <button class="py-1.5 px-4 m-1.5 border rounded-lg bg-blue-300 text-blue-900 text-sm font-semibold shadow active:translate-x-0.5 active:translate-y-0.5">
        <slot />
    </button>
</template>

原始碼的 class 中還加上了 active 時的效果,點擊時的位移會有和原本button類似的動作,但因為我們是把這段原始碼封裝在組件中,所以實際頁面在引用時只需載入組件就好,<slot /> 是一個插槽的作用,用來放按鈕文件用的:
resources\js\Pages\Home.vue

<script setup>
import QuizButton from "@/QuizComponents/QuizButton.vue";
.....略
</script>
<template>
.....略
  <fieldset class="p-4 border rounded-lg w-1/3 mt-16">
    <legend class="px-2 py-1 text-xs shadow-sm bg-slate-200">按鈕測試</legend>
    <QuizButton>按鈕一</QuizButton>
    <QuizButton>按鈕二</QuizButton>
    <QuizButton>按鈕三</QuizButton>
    <QuizButton>按鈕四</QuizButton>
    <QuizButton>按鈕五</QuizButton>
  </fieldset>
</template>

但是如果這個組件只有一種樣子,那我想換不同顏色時不就要寫很多個按鈕組件?或是在外面再套上顏色?雖然的確可以組件標籤上直接寫class,但如果可以讓使用者用方便的方式來套上顏色不是更好,所以我們來設計一下如何帶入屬性及如何根據屬性來改變內部元件的 class :

resources\js\QuizComponents\QuizButton.vue

<script setup>
import { reactive } from 'vue';

const props=defineProps({color:{
                            type:String,
                            default:'blue',
                        }})
const colorSet=({
    slate:"bg-slate-300 text-slate-900",
    gray:"bg-gray-300 text-gray-900",
    zinc:"bg-zinc-300 text-zinc-900",
    neutral:"bg-neutral-300 text-neutral-900",
    stone:"bg-stone-300 text-stone-900",
    red:"bg-red-300 text-red-900",
    orange:"bg-orange-300 text-orange-900",
    amber:"bg-amber-300 text-amber-900",
    yellow:"bg-yellow-300 text-yellow-900",
    lime:"bg-lime-300 text-lime-900",
    emerald:"bg-emerald-300 text-emerald-900",
    teal:"bg-teal-300 text-teal-900",
    green:"bg-green-300 text-green-900",
    cyan:"bg-cyan-300 text-cyan-900",
    sky:"bg-sky-300 text-sky-900",
    blue:"bg-blue-300 text-blue-900",
    indigo:"bg-indigo-300 text-indigo-900",
    violet:"bg-violet-300 text-violet-900",
    purple:"bg-purple-300 text-purple-900",
    fuchsia:"bg-fuchsia-300 text-fuchsia-900",
    pink:"bg-pink-300 text-pink-900",
    rose:"bg-rose-300 text-rose-900",
})

</script>
<template>
<!--綁定屬性參數來取出對應的顏色參數-->
<button class="py-1.5 px-4 m-1.5 border rounded-lg text-sm font-semibold 
                shadow active:translate-x-0.5 active:translate-y-0.5"
        :class="colorSet[color]">
    <slot />
</button>
</template>

tailwind 的22種顏色樣式都寫上去,要注意的是目前似乎無法解析以變數方式表達的樣式字串,所以在顏色物件中要寫入完整的 class 字串(後來我又加上了深色模式,一共有44種按鈕顏色可以選):

....略
  <fieldset class="p-4 border rounded-lg w-1/3 mt-16">
    <legend class="px-2 py-1 text-xs shadow-sm bg-slate-200">按鈕測試</legend>
    <QuizButton>按鈕一</QuizButton>
    <QuizButton color="red">按鈕二</QuizButton>
    <QuizButton color="green">按鈕三</QuizButton>
    <QuizButton color="orange">按鈕四</QuizButton>
    <QuizButton color="purple">按鈕五</QuizButton>
  </fieldset>

另外,<button> 如果使用在表單中,預設是 submit 的功能,所以我們多加一個 type 的屬性讓使用者可以自己決定要怎麼使用,可設定的字串會有 submitresetbutton,預設會是 button

最後,按鈕不會只有一種大小,所以我們可以把 size 代入,依不同的大小來變更按鈕的邊距及字型大小等等:

<script setup>
import { reactive } from 'vue';

const props=defineProps({color:{ type:String,
                                 default:'blue'},
                         type:{ type:String,
                                default:'button'},
                         size:{ type:String,
                                default:'md'})
const btnSize=reactive({
    sm:"py-1 px-2 m-1 rounded-md text-xs font-bold",
    md:"py-1.5 px-4 m-1.5 rounded-lg text-sm font-semibold",
    lg:"py-1.5 px-5 m-1.5 rounded-lg text-base",
    xl:"py-2 px-6 m-2 rounded-xl text-lg"
})     

const colorSet=({ .....略 })

</script>
<template>
<!--綁定屬性參數來取出對應的 class 內容-->
<button class="border shadow active:translate-x-0.5 active:translate-y-0.5"
        :class="[colorSet[color],btnSize[size]]"
        :type="type">
    <slot />
</button>
</template>

接著就可以把組件拿去取代前面的 <button> 標籤,未來就算有需要加功能或其它屬性,也只需要改元件檔案就可以了,其他頁面中使用的組件都會同步更新;

也可以拿來包 Inertia 的 Link 組件,省掉寫class的工夫。
resources\js\Pages\Home.vue

//原本的
<Link :href="route('test.start', testSelect)"
        class="px-6 py-2 border rounded-lg bg-blue-700 text-blue-100">
        開始
  </Link>

//套用自訂按鈕組件
<QuizButton>
    <Link :href="route('test.start', testSelect)">開始</Link>
</QuizButton>

也可以用在 v-for 來重覆按鈕:
resources\js\Pages\Home.vue

//原本的
<div>瀏灠題庫:</div>

    <Link v-for="bank in banks" 
          :key="bank.id"
          :href="route('quiz.browser', bank.id)"
          class="ml-4 border py-3 px-6 rounded-lg text-lime-900 dark:text-gray-500 inline-block bg-lime-100 font-bold">
      {{ bank.name }}{{ bank.levelC }}級
    </Link>
</div>

//套用自訂按鈕組件
<div>瀏灠題庫:</div>

    <QuizButton  v-for="bank in banks" :key="bank.id" size="xl" color="green">
        <Link :href="route('quiz.browser', bank.id)">
          {{ bank.name }}{{ bank.levelC }}級
        </Link>
    </QuizButton>
</div>

以上就是今天的內容,雖然不難,但很實用,我自己每做一個案子就會累積一些這樣的組件,慢慢的增進其通用性,形成自己的組件庫。


上一篇
Day22 查看測驗紀錄-組件的組件的組件,聊聊重覆利用的設計
下一篇
Day24 前後端分離後的分頁 - Laravel Paginate & Vue
系列文
LV的全端開發體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言