button組件幾乎是每個組件庫都有的;其實實現一個button組件是很簡單的。本篇文章將帶你一步一步的實現一個button組件。如果你想瞭解完整的組件庫搭建,你可以先看使用Vite和TypeScript帶你從零打造一個屬於自己的Vue3組件庫,這篇文章有詳細介紹。當然如果你只想知道一個button ...
button組件幾乎是每個組件庫都有的;其實實現一個button組件是很簡單的。本篇文章將帶你一步一步的實現一個button組件。如果你想瞭解完整的組件庫搭建,你可以先看使用Vite和TypeScript帶你從零打造一個屬於自己的Vue3組件庫,這篇文章有詳細介紹。當然如果你只想知道一個button組件如何開發出來的,只看這篇也就夠了。(樣式部分參造了elementui組件庫)。掃碼關註公眾號獲取Vue3組件庫完整搭建源代碼
首先我們先看下我們這個button組件要實現的功能
- 使用type,plain屬性來定義按鈕基本樣式
- round,size控制按鈕形狀大小
- 通過disabled來控制按鈕是否可點擊
- 支持icon加入圖標增強辨識度
type實現
我們的type可以傳入的值可以是primary, success, info,warning, danger分別展示不同按鈕顏色,type傳入text顯示文字按鈕(沒有邊框和背景色的按鈕)
這裡只展示了一個primary的樣式,因為其它值的樣式實現是一樣的。需要的話可以到button組件樣式進行查看。
所以在button/types.ts文件中我們定義一下type的類型:
import { ExtractPropTypes } from 'vue'
export const ButtonType = ['primary', 'success', 'info', 'warning', 'danger','text']
export const buttonProps = {
type: {
type: String,
validator(value: string) {
//這裡表示type只能接收這些值
return ButtonType.includes(value)
}
}
}
export type ButtonProps = ExtractPropTypes<typeof buttonProps>
接下來在button.vue中實現傳入不同值賦予不同類名,從而實現顯示不同效果。
<template>
<button class="k-button" :class="styleClass">
<slot />
</button>
</template>
<script lang="ts">
import './style/index.less'
import { defineComponent, computed } from 'vue'
import { buttonProps } from './types'
export default defineComponent({
name: 'k-button',
props: buttonProps,
setup(props) {
const styleClass = computed(() => {
return {
[`k-button--${props.type}`]: props.type
}
})
return {
styleClass
};
},
});
</script>
這樣一來傳入primary組件就會有個類名k-button--primary嗎,傳入其它值也一樣。然後我們就可以給它們寫樣式了。進入style/index.less:
.k-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: 0.1s;
font-weight: 500;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
&:hover {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
.k-button--primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
&:hover {
background: #66b1ff;
border-color: #66b1ff;
color: #fff;
}
}
.k-button--text {
border-color: transparent;
color: #409eff;
background: transparent;
padding-left: 0;
padding-right: 0;
&:hover {
color: #66b1ff;
border-color: transparent;
background-color: transparent;
}
}
plain(朴素按鈕)和round(圓角按鈕)
我們可以通過傳入plain和round來決定這個按鈕是否為朴素按鈕和圓角按鈕,很顯然它們是個布爾類型
//types.ts
...
export const buttonProps = {
type: {
type: String,
validator(value: string) {
return ButtonType.includes(value)
}
},
plain: Boolean,
round: Boolean
}
...
然後在button.vue定義我們的styleClass
//button.vue
const styleClass = computed(() => {
return {
[`k-button--${props.type}`]: props.type,
'is-plain': props.plain,
'is-round': props.round
}
})
最後在style/index.less寫上我們的樣式
...
.k-button--primary.is-plain {
color: #409eff;
background: #ecf5ff;
border-color: #b3d8ff;
&:hover {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
}
.is-round {
border-radius: 20px;
}
註意
兩個連在一起的類名如:.k-button--primary.is-plain 代表一個元素只有包含這兩個類名,定義的樣式才生效
禁用按鈕
同樣的,在types.ts定義disabled的類型
//types.ts
...
export const ButtonType = ['primary', 'success', 'info', 'warning', 'danger']
export const buttonProps = {
type: {
type: String,
validator(value: string) {
return ButtonType.includes(value)
}
},
plain: Boolean,
round: Boolean,
disabled: Boolean
}
...
然後在button.vue定義我們的styleClass
//button.vue
const styleClass = computed(() => {
return {
[`k-button--${props.type}`]: props.type,
'is-plain': props.plain,
'is-round': props.round,
'is-disabled': props.disabled
}
})
最後添加上我們的樣式
...
.k-button.is-disabled {
color: #c0c4cc;
cursor: not-allowed;
background-image: none;
background-color: #fff;
border-color: #ebeef5;
}
.k-button--primary.is-disabled,
.k-button--primary.is-disabled:active,
.k-button--primary.is-disabled:focus,
.k-button--primary.is-disabled:hover {
color: #fff;
background-color: #a0cfff;
border-color: #a0cfff;
}
//朴素按鈕禁用
.k-button--primary.is-disabled.is-plain,
.k-button--primary.is-disabled.is-plain:active,
.k-button--primary.is-disabled.is-plain:focus,
.k-button--primary.is-disabled.is-plain:hover {
color: #8cc5ff;
background-color: #ecf5ff;
border-color: #d9ecff;
}
...
size
通過size我們可以控制按鈕的大小,組件接收的size值有:midium, small, mini。實現方式和上面差不多,這裡就直接展示部分代碼了
- types.ts
//types.ts
...
export const ButtonSize = ['midium', 'small', 'mini'];
export const buttonProps = {
type: {
type: String,
validator(value: string) {
return ButtonSize.includes(value)
}
},
plain: Boolean,
round: Boolean,
disabled: Boolean
}
...
- button.vue
//button.vue
const styleClass = computed(() => {
return {
[`k-button--${props.type}`]: props.type,
'is-plain': props.plain,
'is-round': props.round,
'is-disabled': props.disabled,
[`k-button--${props.size}`]: props.size,
}
})
- style/index.less
//index.less
...
.k-button--medium {
padding: 10px 20px;
font-size: 14px;
border-radius: 4px;
}
.k-button--small {
padding: 9px 15px;
font-size: 12px;
border-radius: 3px;
}
.k-button--mini {
padding: 7px 15px;
font-size: 12px;
border-radius: 3px;
}
最後我們在項目中引用(examples)來查看效果;
<-- App.vue -->
<template>
<div>
<Button>預設按鈕</Button>
<Button type="primary">主要按鈕</Button>
<Button type="success">成功按鈕</Button>
<Button type="info">信息按鈕</Button>
<Button type="warning">警告按鈕</Button>
<Button type="danger">危險按鈕</Button>
<Button type="text">文字按鈕</Button>
<br>
<br>
<Button plain>朴素按鈕</Button>
<Button type="primary" plain>主要按鈕</Button>
<Button type="success" plain>成功按鈕</Button>
<Button type="info" plain>信息按鈕</Button>
<Button type="warning" plain>警告按鈕</Button>
<Button type="danger" plain>危險按鈕</Button>
<br>
<br>
<Button round>圓角按鈕</Button>
<Button type="primary" round>主要按鈕</Button>
<Button type="success" round>成功按鈕</Button>
<Button type="info" round>信息按鈕</Button>
<Button type="warning" round>警告按鈕</Button>
<Button type="danger" round>危險按鈕</Button>
<br>
<br>
<Button disabled>禁用按鈕</Button>
<Button type="primary" disabled>主要按鈕</Button>
<Button type="success" disabled>成功按鈕</Button>
<Button type="info" disabled>信息按鈕</Button>
<Button type="warning" disabled>警告按鈕</Button>
<Button type="danger" disabled>危險按鈕</Button>
<br>
<br>
<Button disabled>禁用按鈕</Button>
<Button type="primary" disabled plain>主要按鈕</Button>
<Button type="success" disabled plain>成功按鈕</Button>
<Button type="info" disabled plain>信息按鈕</Button>
<Button type="warning" disabled plain>警告按鈕</Button>
<Button type="danger" disabled plain>危險按鈕</Button>
<br>
<br>
<Button>預設按鈕</Button>
<Button size="medium">中等按鈕</Button>
<Button size="small">小型按鈕</Button>
<Button size="mini">超小按鈕</Button>
</div>
</template>
<script lang="ts" setup>
import { Button } from 'kitty-ui'
</script>
<style lang="less">
.k-button {
margin-right: 10px;
}
</style>
啟動項目我們就會在瀏覽器中看到我們的各式各樣的button組件了
圖標
通過icon屬性設置按鈕圖標,支持Icon組件里的所有圖標(Icon組件下一篇文章將會詳細介紹)。
- types.ts中設置icon類型
export const buttonProps = {
type: {
type: String,
validator(value: string) {
return ButtonType.includes(value)
}
},
plain: Boolean,
round: Boolean,
disabled: Boolean,
icon: String,
iconPosition: String,
size: {
type: String,
validator(value: string) {
return ButtonSize.includes(value)
}
}
}
- 修改button組件
icon可以傳入icon組件中定義的name,iconPosition可選right使圖標在按鈕右側。
<!-- button.vue -->
<template>
<button class="k-button" :class="styleClass">
<Icon class="icon" v-if="iconFont.iconName && iconFont.iconPosition != 'right'" :name="iconFont.iconName" />
<slot />
<Icon class="icon" v-if="iconFont.iconPosition == 'right' && iconFont.iconName" :name="iconFont.iconName" />
</button>
</template>
<script lang="ts">
import './style/index.less'
import { defineComponent, computed } from 'vue'
import { buttonProps } from './types'
import Icon from '../Icon/icon.vue'
export default defineComponent({
name: 'k-button',
props: buttonProps,
components: { Icon },
setup(props) {
const styleClass = computed(() => {
return {
[`k-button--${props.type}`]: props.type,
'is-plain': props.plain,
'is-round': props.round,
'is-disabled': props.disabled,
[`k-button--${props.size}`]: props.size,
}
})
//圖標
const iconFont = computed(() => {
const iconName = props.icon
const position = props.iconPosition
return {
iconName,
iconPosition
}
})
return {
styleClass,
Icon,
iconFont
};
},
});
</script>
然後在examples/App.vue使用並查看效果
<template>
<div>
<Button type="success" icon="edit">圖標按鈕</Button>
<Button type="primary" icon="map" icon-position="right">圖標按鈕</Button>
<Button type="primary" icon="ashbin"></Button>
</div>
</template>
<script lang="ts" setup>
import { Button } from 'kitty-ui'
</script>
<style lang="less">
.k-button {
margin-right: 10px;
}
</style>
最後
到這裡一個button組件的開發基本就結束了,看起來一個不起眼的button組件裡面其實還是包含些許內容的。關註我將不定期更新其它組件的實現。
如果你覺得本篇文章對你有幫助的話,動動指頭點個贊吧orz,你的鼓勵將會是我持續創作的動力。