序言
在上一篇文章中,我們深入探索了 icon 組件從測試到全局注冊的全過程🎯,成功為其在項目中穩定運行筑牢了根基。此刻,組件庫的建設之旅仍在繼續,我們將目光聚焦于另一個關鍵組件 —— 按鈕組件。按鈕作為用戶與界面交互的核心紐帶🧐,其功能的完備性、樣式的美觀性以及操作的流暢性,都對用戶體驗起著至關重要的作用。接下來,讓我們一同深入剖析按鈕組件的實現過程,為組件庫增添強大助力,使其在前端開發的舞臺上綻放更加耀眼的光芒?。
UI
我們先借鑒 Element Plus 組件庫的樣式,著手實現一個基礎的按鈕組件。參考圖如下:
從圖中可以分析出,該按鈕具備default
、primary
、success
、info
、warning
、danger
這幾種場景,它們的區別主要體現在邊框顏色、字體顏色以及背景顏色上。結合我們的實際業務需求,我們開始打造自己的按鈕組件
準備工作
按照慣例,我們首先在packages/components/button/src
目錄下,新增button.ts
和button.vue
文件📄。
props屬性
在button.ts
文件中,定義我們所需的props
。這些屬性包括場景、大小、是否禁用、是否處于加載中、加載時的圖標、按鈕的前綴圖標、后綴圖標、按鈕形狀以及按鈕類型。
import { ExtractPropTypes, PropType } from 'vue'
import { useSceneProp, useSizeProp, useLoadingIconProp, useIconProp } from '@nova-ui/hooks'export const buttonShapes = ['round', 'circle'] as const
export type ButtonShapeType = typeof buttonShapes[number]export const buttonTypes = ['plain', 'text', 'link', 'dashed'] as const
export type ButtonTypeType = typeof buttonTypes[number]export const buttonProps = {scene: useSceneProp(),size: useSizeProp(),disabled: {type: Boolean,},loading: {type: Boolean,},loadingIcon: useLoadingIconProp(),prefixIcon: useIconProp(),suffixIcon: useIconProp(),shape: {type: String as PropType<ButtonShapeType>},type: {type: String as PropType<ButtonTypeType>}
} as constexport type ButtonType = ExtractPropTypes<typeof buttonProps>
相關代碼如上述所示。其中,scene
場景屬性很可能在多個組件中復用,因此我們將其單獨提取出來(這是一個良好的編程習慣,當相同代碼在多處使用時,建議提取以提高代碼的可維護性)。在packages/constants
目錄下新增scene.ts
文件,用于存儲場景的常量及其類型。同時,在packages/hooks/use-scene
目錄下新增index.ts
文件,編寫我們需要使用的props
屬性值。
// packages/constants/scene.ts
export const scenes = ['primary', 'success', 'warning', 'danger', 'error', 'info'] as const
export type Scene = typeof scenes[number]
// packages/hooks/use-scene/index.ts
import { PropType } from 'vue'
import { Scene } from '@nova-ui/constants'
export const useSceneProp = () => ({type: String as PropType<Scene>,
})
其它如size
、loadingIcon
、prefixIcon
、suffixIcon
等屬性的提取方式與之類似,在此不再一一贅述。
模板部分:構建按鈕的外觀與交互結構
首先來看看這段代碼的 HTML 模板部分,它決定了按鈕在頁面上的最終呈現效果,是按鈕組件的 “外觀設計師”👨?🎨。
<template><button:class="[ns.b(),ns.m(scene),ns.m(size),ns.is('disabled', disabled),ns.is('loading', loading),ns.is(!shape, !!shape),ns.is(!type, !!type),]"><template v-if="loading"><slot v-if="$slots.loading" name="loading"></slot><NIcon v-else :class="ns.e('loading')" :name="loadingIcon"></NIcon></template><template v-if="$slots.prefix || prefixIcon"><slot v-if="$slots.prefix" name="prefix"></slot><NIcon v-else-if="prefixIcon" :class="ns.e('prefix')" :name="prefixIcon"></NIcon></template><slot></slot><template v-if="$slots.suffix || suffixIcon"><slot v-if="$slots.suffix" name="suffix"></slot><NIcon v-else-if="suffixIcon" :class="ns.e('suffix')" :name="suffixIcon"></NIcon></template></button>
</template>
這段模板代碼定義了按鈕組件的可視化結構與交互元素。最外層的<button>
標簽構建了按鈕的基本框架,通過:class
綁定一系列動態類名,實現按鈕外觀的多樣化。
ns.b()
提供了按鈕的基礎類名,是按鈕樣式的基石。ns.m(scene)
與ns.m(size)
則根據傳入的scene
(場景)和size
(尺寸)參數,為按鈕添加相應的修飾類名,使按鈕能夠適配不同的使用場景與布局需求。
ns.is
系列函數依據傳入的布爾值屬性,動態添加對應的狀態類名。例如,ns.is('disabled', disabled)
在disabled
為true
時,為按鈕添加表示禁用狀態的類名,改變按鈕的外觀以提示用戶該按鈕當前不可操作。同理,ns.is('loading', loading)
根據loading
狀態添加或移除加載相關的類名,實現加載狀態下按鈕的視覺反饋。
在按鈕內容方面,代碼充分利用 Vue 的插槽機制與NIcon
組件,實現了高度的靈活性。當按鈕處于loading
狀態時,首先檢查是否存在名為loading
的插槽。若有,則渲染該插槽內容,允許開發者自定義加載狀態下的顯示元素;若沒有,則渲染NIcon
組件作為加載圖標,圖標類名由ns.e('loading')
生成,圖標名稱則由loadingIcon
屬性指定。
對于按鈕的前綴和后綴部分,同樣采用了靈活的判斷邏輯。先判斷是否存在prefix
插槽,若有則渲染插槽內容;若沒有但設置了prefixIcon
屬性,則渲染NIcon
組件作為前綴圖標,類名由ns.e('prefix')
生成,圖標名稱由prefixIcon
指定。后綴部分的邏輯與之相同,通過這種方式,按鈕可以輕松添加各種圖標或自定義內容,極大地增強了按鈕的功能性與美觀性。
腳本部分:賦予組件功能與數據交互能力
腳本部分是按鈕組件的核心,負責引入必要的模塊、定義組件的配置與屬性,如同為組件注入靈魂🧠。
<script lang="ts" setup>import { useNamespace } from '@nova-ui/hooks'import { buttonProps, ButtonType } from './button'import { NIcon } from '@nova-ui/components'const ns = useNamespace('button')defineOptions({name: 'NButton',})defineProps(buttonProps)
</script>
useNamespace
函數用于生成具有統一規范的類名,確保按鈕組件的樣式管理清晰且易于維護。buttonProps
和ButtonType
從./button
文件引入,其中buttonProps
定義了按鈕組件可接收的外部屬性,如disabled
、loading
、size
等,為組件與外部的數據交互提供了接口。
NIcon
組件從@nova-ui/components
引入,用于在按鈕中顯示各種圖標。通過const ns = useNamespace('button')
創建了按鈕組件專屬的樣式命名空間實例,供模板部分生成類名使用。
defineOptions({name: 'NButton'})
為按鈕組件定義了名稱NButton
,方便在 Vue 項目中進行識別與引用。defineProps(buttonProps)
則依據buttonProps
定義了組件可接收的屬性,將外部傳入的數據與組件內部邏輯連接起來,使組件能夠根據不同的屬性值呈現出相應的狀態與外觀。
綜上所述,這段代碼通過模板與腳本的協同工作,實現了一個功能豐富、可定制性強的 Vue 按鈕組件。它不僅能夠滿足各種常見的按鈕使用場景,還為開發者提供了靈活的擴展空間,在前端組件庫中具有重要的應用價值 。
🦀🦀感謝看官看到這里,如果覺得文章不錯的話🙌,點個關注不迷路?。
誠邀您加入我的微信技術交流群🎉,群里都是志同道合的開發者👨?💻,大家能一起交流分享摸魚🐟。期待與您在群里相見🚀,咱們攜手在開發路上共同進步? !
👉點我
感謝各位大俠一路相伴,實在感激! 不瞞您說,在下還有幾個開源項目 📦,它們就像精心培育的幼苗 🌱,急需您的澆灌。要是您瞧著還不錯,麻煩動動手指,給它們點亮幾顆 Star ?,您的支持就是它們成長的最大動力,在此謝過各位大俠啦!
Nova UI
組件庫:https://github.com/gmingchen/nova-ui- 基于 Vue3 + Element-plus 管理后臺基礎功能框架
- 預覽:https://admin.gumingchen.icu
- Github:https://github.com/gmingchen/agile-admin
- Gitee:https://gitee.com/shychen/agile-admin
- 基礎版后端:https://github.com/gmingchen/java-spring-boot-admin
- 文檔:http://admin.gumingchen.icu/doc/
- 基于 Vue3 + Element-plus + websocket 即時聊天系統
- 預覽:https://chatterbox.gumingchen.icu/
- Github:https://github.com/gmingchen/chatterbox
- Gitee:https://gitee.com/shychen/chatterbox
- 基于 node 開發的后端服務:https://github.com/gmingchen/node-server