Day 26:「按钮博物馆」- 轻松变化各种按钮元件

Day26-Banner

哈罗大家好~
不知道昨天的进度条做的怎麽样?

想要交作业的人可以贴在昨天的留言区给我呦!

那我们今天的内容也很简单,
二话不说,要开始罗?

carrotPoint 前置作业

跟昨天的环境相同,兔兔为了写文章方便是重新建立了一个,你们可以重新建立新的专案从头练习一次,也可以在昨天做完的专案直接多增加新的元件哦!
 

carrotPoint 建立空白元件

和昨天一样,先建立空白元件,所以在专案里的 ./src/components 资料夹中新增一个 RabbitButton.vue 的元件:

完成後,增添以下内容:

<template>
  
</template>

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

接着我们就可以把这个元件新增到画面中,打开 App.vue 然後内容跟昨天差不多:

<template>
  <div :class="[
      'w-screen h-screen',
      'flex flex-col',
      'justify-center items-center',
      'gap-5',
    ]"
  >
    <RabbitButton />
  </div>
</template>

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

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

这样准备工作大妥当,开始按钮博物馆导览啦!
 

carrotPoint 按钮

按钮的要素其实很简单,不外乎就是一个中间有字的矩形,滑鼠悬停时有颜色变化,最好的话连按下後也有相对应的效果,才是一个良好的互动。

那麽基於这些要素,我们就可以这麽做:

  • 保持按钮长宽比 - px-6py-3
  • 小米定律啦 - rounded-mdfont-bold
  • 从一般、滑鼠悬停到按下按钮後的基本灰色系变化开始 - bg-gray-400hover:bg-gray-300active:bg-gray-500
  • 进阶的华丽效果:滑鼠悬停时微微放大,按下後缩小 - hover:scale-105active:scale-95
  • 不来点过渡效果,看起来就像顶叩叩的空姐一样僵硬 - transition-all
  • 然後不知道按钮要有什麽文字,索性就写上 按钮 二字让它不会被误认吧?

所以综合起来,就会像是这样:

<template>
  <div
    :class="[
      'px-6 py-3',
      'rounded-md font-bold',
      'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
      'hover:scale-105 active:scale-95',
      'transition-all'
    ]"
  >
    按钮
  </div>
</template>

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


这麽快就有 fu 了吗?
哎呀後面还有更有趣的啦!

毕竟我们现在按钮还非常的单调,
让我们来帮它点缀一下!
 

carrotPoint 动起来

Yes,这麽快就来到了我们动起来的环节了。

别以为会这麽轻易地结束,
我们现在看到的按钮是这个样子:

可是兔兔期待的是这个样子:

哇,还是有点落差对吧?

「摁,是没错啦,但不就是差个 icon 和颜色而已嘛 ... 不过每次插入 svg 的 icon 都会觉得把结构弄得好杂乱 ...」

嘿嘿,这个立马帮你解决!

Slot

没错,这就是轮到不知道甚麽时候才能派上用场但现在就派上用场的 Slot 啦!

slot 可以把原本一直要替换的东西从内部解藕出来,那麽一来我们在外面替换时就不用一直修改元件的内部功能了~

现在在文字前後帮按钮加上两个 slot,分别取名为 iconLefticonRight,然後因为想要 icon 和文字可以横向排列且之间有点空隙,我们顺便加上 flex gap-2 的样式:

<!-- RabbitButton.vue -->

<div
  :class="[
    'flex gap-2',
    'px-6 py-3',
    'rounded-md font-bold',
    'text-white',
    'bg-blue-400 hover:bg-blue-300 active:bg-blue-500',
    'hover:scale-105 active:scale-95',
    'transition-all'
  ]"
>
  <slot name="iconLeft" />
  按钮
  <slot name="iconRight" />
</div>

这麽一来就可以轻松的在按钮文字的前或後加上 icon 啦!

然後啊,Tailwind 官方的专案中有个特别的网站,叫做 heroicons虽然里面的 icon 量真的不多,但是各个都是精心设计过,适合搭配 Tailwind 直接使用的 icon,还可以直接复制 svg,算是很方便啦~

我们回到 App.vue,兔兔这边要用的 icon 就是在 heroicons 上面找的 wifi icon (不是 wife,要认明。),然後包在指定 iconLeft 插槽 的 template 中:

<!-- App.vue -->

<div 
  :class="[
    'w-screen h-screen',
    'flex flex-col',
    'justify-center items-center',
    'gap-5',
  ]"
>
  <RabbitButton>
    <template v-slot:iconLeft>
      <svg  xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
      </svg>
    </template>
  </RabbitButton>
</div>

赞啦,这样真的很方便,把 icon 从元件中抽离之後就可以随时替换了!

可是 ...
(你这兔又来了,果然不管做的怎麽样都有话要说!)

就是真的需要提出来啦!
按钮的文字和颜色的改变的确是还不方便,所以我们就必须用到 ...

Props

对,就是 Props。

我们刚刚说到要改变文字和颜色,所以就帮 props 增加两个内容,但这两个内容都必须要有预设值:

<script>
export default {
  name: "RabbitButton",
  props:{
    text: {
      default: "按钮"
    },
    color: {
      default: "gray"
    },
  },
}
</script>

我们先来解决按钮文字的部分,把按钮的字样取代成 {{ text }}

<div
  :class="[
    'flex gap-2',
    'px-6 py-3',
    'rounded-md font-bold',
    'text-white',
    'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
    'hover:scale-105 active:scale-95',
    'transition-all'
  ]"
>
  <slot name="iconLeft" />
  {{ text }}
  <slot name="iconRight" />
</div>

再来,就要解释到为什麽 color 要有预设值且预设值是字串了。 因为我们要利用物件 (字典) 的特性来快速的切换按钮的色系!

为了方便监控和节省资源,我们先在 computed 中建立一个 colorSelector 函数,并返回一个空白物件。

<script>
export default {
  name: "RabbitButton",
  props:{
    text: {
      default: "按钮"
    },
    color: {
      default: "gray"
    },
  },
  computed: {
    colorSelector() {
      return {}
    }
  }
}
</script>

建立好之後,我们把元件中颜色的那一行 tailwind 语法加到物件中并命名为 gray,且在物件後加上 [this.color] 来让函数找到并返回指定名称为 gray 的内容:

<script>
export default {
  name: "RabbitButton",
  props:{
    text: {
      default: "按钮"
    },
    color: {
      default: "gray"
    },
  },
  computed: {
    colorSelector() {
      return {
        gray: 'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
      }[this.color]
    }
  }
}
</script>

然後把 colorSelector 函数加回 class 列表,并测试一次:

<div
  :class="[
    'flex gap-2',
    'px-6 py-3',
    'rounded-md font-bold',
    'text-white',
    colorSelector,
    'hover:scale-105 active:scale-95',
    'transition-all'
  ]"
>
  <slot name="iconLeft" />
  {{ text }}
  <slot name="iconRight" />
</div>

看起来没什麽变化是正常的,但至少这表示没写错!
打铁要趁热,我们接着来追加其他颜色吧~

最後追加完,完整的 code 可能会是这个样子:

<template>
  <div
    :class="[
      'flex gap-2',
      'px-6 py-3',
      'rounded-md font-bold',
      'text-white',
      colorSelector,
      'hover:scale-105 active:scale-95',
      'transition-all'
    ]"
  >
    <slot name="iconLeft" />
    {{ text }}
    <slot name="iconRight" />
  </div>
</template>

<script>
export default {
  name: "RabbitButton",
  props:{
    text: {
      default: "按钮"
    },
    color: {
      default: "gray"
    },
  },
  computed: {
    colorSelector() {
      return {
        gray: 'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
        green: 'bg-green-400 hover:bg-green-300 active:bg-green-500',
        blue: 'bg-blue-400 hover:bg-blue-300 active:bg-blue-500',
        red: 'bg-red-400 hover:bg-red-300 active:bg-red-500',
        yellow: 'bg-yellow-400 hover:bg-yellow-300 active:bg-yellow-500',
      }[this.color]
    }
  }
}
</script>

然後这边值得注意的是,为什麽不用变数取代 bg-XXX-400hover:bg-XXX-300 就好了呢? 为何还要这样大费周章地去把 class 名称都写过一遍?

因为要让 purge 读取到要编译的 class 的话,class 名称必须保持完整,不能被拆开!

所以为了要让样式能正确被读取到且被编译,不能使用 "bg-" + color + "500" 或是 "opacity-" + number 这种组合过的形式,这对 Tailwind 来说是不合法的 class 名称哦。

既然完成了,我们就快点来测试吧!
好兴奋啊!

 

carrotPoint 最後测试

最後的测试环境,我们来做三个按钮吧!

然後为了美化中的美化,我们可以在按钮元件中加上 cursor-pointer 让它看起来更像样!

第一个按钮,就是最普通的按钮啦!

<RabbitButton />

再来是让人看起来很连网路的 wifi 按钮!

<RabbitButton text="wifi" color="blue">
  <template v-slot:iconLeft>
    <svg  xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
    </svg>
  </template>
</RabbitButton>

最後,是安装软件时会出现的下一步按钮~

<RabbitButton text="下一步" color="green">
  <template v-slot:iconRight>
    <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
    </svg>
  </template>
</RabbitButton>

OK,超成功的啦!
 

今天是不是也很轻松简单啊?

兔兔觉得这样做按钮又美、弹性又高!
以後遇到再多状况也只要小修改就能够继续使用了,
这有再度登场的机会正是做元件的目的!

希望你们都能够试试看,如果有更好方法或建议 ...

做成作业留言给我看嘿!!!!
 

carrotPoint 给你们的回家作业:


关於兔兔们:


 


( # 兔兔小声说 )

不是兔兔偷懒,兔兔只是陪富坚去取材。


<<:  Day 27 - Kotlin的类别继承和覆写

>>:  第二十二天:为测试产生覆盖率报告

Day 11:将你的 Hexo 部落格部属到 Github Pages

我相今天的篇章是大家期待已久的,因为经过前面十天的努力,今天终於要将我们的部落格公开在世人面前啦!不...

Day 23 - 前端开发工具 - HBuilder X

Day 23 - 前端开发工具 - HBuilder X 完成了後端开发,接下来就要将透过前端跨平台...

TypeScript 能手养成之旅 Day 5 原始型别

前言 前一天大致上了解一下,TypeScript 有支援哪些型别,从今天开始,将一一来每一个型别的定...

Alpine Linux Porting (1.999) The light at the end of tunnel

一样先上进度log: + exec /bin/busybox switch_root /sysroo...

Day03,Model摸象

正文 我预计做的是一个很简易的post/get application,而目前只预计会有4只极度简陋...