本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫
前言
本文是筆者寫組件設計的第五篇文章,之所以會寫組件設計相關的文章,是因為作為一名前端優秀的前端工程師,面對各種繁瑣而重複的工作,我們不應該按部就班的去"辛勤勞動",而是要根據已有前端的開發經驗,總結出一套自己的高效開發的方法.作為數據驅動的領導者react/vue等MVVM框架的出現,幫我們減少了工作中大量的冗餘代碼, 一切皆組件的思想深得人心.所以, 為了讓工程師們有更多的時間去考慮業務和產品迭代,我們不得不掌握高質量組件設計的思路和方法.所以筆者將花時間去總結各種業務場景下的組件的設計思路和方法,並用原生框架的語法去實現各種常用組件的開發,希望等讓前端新手或者有一定工作經驗的朋友能有所收穫.
今天主要帶大家一起實現一個Tag組件和Empty(空狀態)組件,在介紹組件設計之前,先給大家介紹一個免費開源的圖標庫icomoon,
可以在線導入SVG格式字體,並進行編輯,然後下載來使用,在組件設計中有具體的使用介紹.
正文
在開始組件設計之前希望大家對css3和js有一定的基礎.我們先看看實現後的組件效果:
由圖可以知道tag組件可以自定義顏色主題(color theme), 可以手動關閉標籤, 空狀態主要是提供用戶數據展示用的, 實現起來很簡單,重點在圖標的使用上.
1. 組件設計思路
按照之前筆者寫的組件設計原則,我們第一步是要確認需求. 一個tag標籤組件一般都會有如下需求點:
可以改變標籤顏色提供關閉標籤的配置,讓用戶可以關閉標籤關閉標籤的回調,讓用戶能控制標籤關閉後觸發的動作
需求收集好之後,作為一個有追求的程式設計師, 會得出如下線框圖:
對於react選手來說,如果沒用typescript,建議大家都用PropTypes, 它是react內置的類型檢測工具,我們可以直接在項目中導入. vue有自帶的屬性檢測方式,這裡就不一一介紹了.
2. 基於react實現一個Tag組件
2.1. tag組件框架設計
首先我們先根據需求將組件框架寫好,這樣後面寫業務邏輯會更清晰:
import React from 'react'
import classnames from 'classnames'
import styles from './index.less'
/**
* 標籤組件
* @param {closable} boolean 是否可關閉
* @param {onClose} func 標籤關閉時的回調
* @param {color} string 標籤的顏色,不設置則為默認顏色
*/
export default function Tag(props) {
let { children, closable, onClose, color } = props
return <div
className={styles.xTag}
style={{ backgroundColor: color }}
{ children }
</div>
}
有了這個框架,我們來一步步往裡面實現內容吧. 根據需求,顏色這個屬性好實現,在上述代碼中已經實現了, 我們看看closable和onClose如何實現.我們要向關閉tag,實際上是需要將這個標籤隱藏,比如說使用display:none,或者從dom中移除, 筆者就參考antd的實現方式,通過display:none來實現.
首先我們要想在react的函數式組件操作dom, 最好的方式是使用ref, 關於ref的使用如果不熟悉的可以參考react官方文檔,這裡實現如下:
import React from 'react'
import classnames from 'classnames'
import styles from './index.less'
/**
* 標籤組件
* @param {closable} boolean 是否可關閉
* @param {onClose} func 標籤關閉時的回調
* @param {color} string 標籤的顏色,不設置則為默認顏色
*/
export default function Tag(props) {
let { children, closable, onClose, color } = props
let tag = React.createRef()
let handleClose = () => {
onClose && onClose()
tag.current.style.display = 'none'
}
return <div
className={classnames(styles.xTag, color ? styles.xTagHasColor : '')}
style={{ backgroundColor: color }}
ref={tag}>
{ children }
{ closable && <span className={styles.closeBtn} onClick={handleClose}>x</span> }
</div>
}
通過react的createRef API,我們很方便的拿到了當前的dom對象, 在handleClose可以進行屬性的分配. 組件的js代碼基本實現完成了,接下來看看css:
.xTag {
margin-bottom: 8px;
margin-right: 8px;
display: inline-block;
border-radius: 4px;
border: 1px solid #d9d9d9;
padding: 0 7px;
font-size: 12px;
line-height: 20px;
white-space: nowrap;
background-color: #fafafa;
&.xTagHasColor {
border-color: transparent;
color: #fff;
.closeBtn {
color: rgba(255, 255, 255, .6)
}
}
.closeBtn {
margin-left: 5px;
color: rgba(0, 0, 0, 0.45);
cursor: pointer;
}
}
健壯性支持:
import PropTypes from 'prop-types'
// ...
Tag.propTypes = {
color: PropTypes.string,
closable: PropTypes.bool,
onClose: PropTypes.func
}
是不是很簡單? 這樣一個可定製對的tag組件就完成了,關於代碼中的css module和classnames的使用大家可以自己去官網學習,非常簡單.
3. 基於react實現一個Empty(空狀態)組件
這個組件非常好寫, 目前常用的空狀態組件一般是圖片和文字組合, 圖片文字都可替換,具體實現如下:
import classnames from 'classnames'
import styles from './index.less'
/**
* 空狀態組件
* @param {className} string 自定義類名
* @param {text} string 空狀態文本
*/
export default function Empty(props) {
let { text, className } = props
return <div className={classnames(styles.emptyWrap, className)}>
<div className={styles.emptyInner}><span className="icon-finder"></span></div>
<p>{ text ? text : '空空如也'}</p>
</div>
}
這裡主要介紹icon-finder的由來.正如文章開始提到的,筆者採用icomoon作為圖標庫, 我們可以在其官網上定製自己的圖標,筆者大概選了40多了免費圖標,項目中使用基本夠用了.主要介紹一下他的具體功能:
可導入,下載,管理自己的圖標庫
可編輯圖標,生成svg圖標或者字體圖標
當然國內的iconfont也非常優秀,大家可以多嘗試.
我們將下載icomoon圖標文件後,會有一個html的demo文件,裡面有具體的使用方法和離線編輯功能,如下:
筆者在這裡就不多做介紹了, 其次我們也可以類似於antd一樣,將icon封裝成react的組件, 這樣用起來也非常方便.