《精通react/vue組件設計》之實現一個健壯的警告提示(Alert)組件

2020-12-23 酷扯兒

本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫

前言

本文是筆者寫組件設計的第七篇文章, 今天帶大家實現一個自帶主題且可關閉的Alert組件, 該組件在諸如Antd或者elementUI等第三方組件庫中都會出現,主要用來提供系統的用戶反饋.

之所以會寫組件設計相關的文章,是因為作為一名前端優秀的前端工程師,面對各種繁瑣而重複的工作,我們不應該按部就班的去"辛勤勞動",而是要根據已有前端的開發經驗,總結出一套自己的高效開發的方法.

前端組件一般會劃分為如下幾種類型:

通用型組件: 比如Button, Icon等.布局型組件: 比如Grid, Layout布局等.導航型組件: 比如麵包屑Breadcrumb, 下拉菜單Dropdown, 菜單Menu等.數據錄入型組件: 比如form表單, Switch開關, Upload文件上傳等.數據展示型組件: 比如Avator頭像, Table表格, List列表等.反饋型組件: 比如Progress進度條, Drawer抽屜, Modal對話框等.其他業務類型所以我們在設計組件系統的時候可以參考如上分類去設計,該分類也是antd, element, zend等主流UI庫的分類方式.

正文

在開始組件設計之前希望大家對css3和js有一定的基礎,並了解基本的react/vue語法.我們先看看實現後的組件效果:

1. 組件設計思路

按照之前筆者總結的組件設計原則,我們第一步是要確認需求. 一個警告提示(Alert)組件會有如下需求點:

能控制Alert組件的樣式能控制Alert組件的關閉按鈕是否顯示用戶可以自己輸入提示內容能控制關閉按鈕的文本,或者自定義關閉按鈕支持顯示提示內容的輔助文本內置提供不同類型的警告提示樣式,比如成功, 錯誤, 警告等關閉提示時能提供自定義事件需求收集好之後,作為一個有追求的程式設計師, 會得出如下線框圖:

對於react選手來說,如果沒用typescript,建議大家都用PropTypes, 它是react內置的類型檢測工具,我們可以直接在項目中導入. vue有自帶的屬性檢測方式,這裡就不一一介紹了.

通過以上需求分析, 我們發現實現一個Alert非常簡單, 它屬於反饋型組件,所以不會涉及到太多功能.接下來我們就來看看具體實現.

2. 基於react實現一個Alert組件

2.1. Alert組件框架設計

首先我們先根據需求將組件框架寫好,這樣後面寫業務邏輯會更清晰:

import classnames from 'classnames'

import styles from './index.less'

/**

* 警告提示組件

* @param {style} object 更改Alert樣式

* @param {closable} bool 是否顯示關閉按鈕, 默認不顯示

* @param {closeText} string|reactNode 自定義關閉按鈕

* @param {message} string 警告提示內容

* @param {description} string 警告提示的輔助性文字

* @param {type} string 警告的類型

* @param {onClose} func 關閉時觸發的事件

*/

function Alert(props) {

const {

style,

closable,

closeText,

message,

description,

type,

onClose

} = props

return <div className={styles.xAlertWrap}>

<div className={styles.alertMes}>{ message }</div>

<div className={styles.alertDesc}>{ description }</div>

<span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span>

</div>

}

export default Alert

有了這個框架,我們就來往裡面實現內容吧.

2.2 實現style,closeText,message, description,type

這幾個功能在框架搭建好之後已經部分實現了,是因為他們都比較簡單,不會牽扯到其他複雜邏輯.只需要對外暴露屬性並使用屬性即可. 具體實現如下:

function Alert(props) {

const {

style,

closable,

closeText,

message,

description,

type,

onClose

} = props

return <div

className={classnames(styles.xAlertWrap, styles[type] || styles.warning)}

style={{

...style

}}

>

<div className={styles.alertMes}>{ message }</div>

<div className={styles.alertDesc}>{ description }</div>

<span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span>

</div>

}

以上代碼可以發現筆者採用了classnames這個第三方工具, 他可以組合我們的class以實現更靈活的配置. 對於type的實現,我的思路是提前預製好幾種類型樣式, 通過用戶手動配置來匹配到對應的樣式:

.xAlertWrap {

box-sizing: border-box;

position: relative;

padding: 5px 12px;

margin-bottom: 16px;

border-radius: 3px;

&.success {

background-color: #f6ffed;

border: 1px solid #b7eb8f;

}

&.info {

background-color: #e6f7ff;

border: 1px solid #91d5ff;

}

&.error {

background-color: #fffbe6;

border: 1px solid #ffe58f;

}

&.warning {

background-color: #fff1f0;

border: 1px solid #ffa39e;

}

}

2.3 實現closable和onClose

closable主要是用來讓用戶能手動關閉Alert,onClose是對外暴露的關閉時的方法, 因為沒必要也不需要向外暴露屬性來讓Alert關閉, 所以最好的方式是在組件內部實現, 我們會通過useState這個鉤子來處理,代碼如下:

function Alert(props) {

const {

style,

closable,

closeText,

message,

description,

type,

onClose

} = props

let [visible, setVisible] = useState(true)

const handleColse = () => {

setVisible(false)

onClose && onClose()

}

return visible ?

<div

className={classnames(styles.xAlertWrap, styles[type] || styles.warning)}

style={{

opacity: visible ? '1' : '0',

...style

}}

>

<div className={styles.alertMes}>{ message }</div>

<div className={styles.alertDesc}>{ description }</div>

{

!!closable && <span className={styles.closeBtn} onClick={handleColse}>{ closeText ? closeText : 'x' }</span>

}

</div> : null

}

通過控制visible來控制Alert的出現和消失, 並且當點擊關閉按鈕時能調用外部暴露的onClose方法.

2.4 健壯性支持, 我們採用react提供的propTypes工具:

import PropTypes from 'prop-types'

// ...

Alert.propTypes = {

style: PropTypes.object,

closable: PropTypes.bool,

closeText: PropTypes.oneOfType([

PropTypes.string,

PropTypes.element

]),

message: PropTypes.string,

description: PropTypes.string,

type: PropTypes.string,

onClose: PropTypes.func

}

關於prop-types的使用官網上有很詳細的案例,這裡說一點就是oneOfType的用法, 它用來支持一個組件可能是多種類型中的一個. 組件完整css代碼如下:

.xAlertWrap {

box-sizing: border-box;

position: relative;

padding: 5px 12px;

margin-bottom: 16px;

border-radius: 3px;

&.success {

background-color: #f6ffed;

border: 1px solid #b7eb8f;

}

&.info {

background-color: #e6f7ff;

border: 1px solid #91d5ff;

}

&.error {

background-color: #fffbe6;

border: 1px solid #ffe58f;

}

&.warning {

background-color: #fff1f0;

border: 1px solid #ffa39e;

}

.alertMes {

margin-bottom:5px;

color: rgba(0, 0, 0, 0.85);

font-size: 14px;

line-height: 1.5em;

}

.alertDesc {

color: rgba(0, 0, 0, 0.65);

font-size: 14px;

line-height: 1.5em;

word-break: break-all;

}

.closeBtn {

position: absolute;

right: 8px;

top: 5px;

color: rgba(0, 0, 0, 0.4);

cursor: pointer;

}

}

通過以上步驟, 一個健壯的的Alert組件就完成了,關於代碼中的css module和classnames的使用大家可以自己去官網學習,非常簡單.如果不懂的可以在趣談前端技術群裡提問,筆者看到後會第一時間解答.

2.5 使用Alert組件

我們可以通過如下方式使用它:

<Alert message="溫馨提示,你忘帶口罩了" />

<Alert message="溫馨提示,你註冊成功" type="success" />

<Alert message="錯誤提示,你沒洗手了" type="error" />

<Alert message="提示: 我們開始吧" type="info" />

<Alert message="提示: 我可以關閉了" type="info" closable onClose={() => { alert(111) }} /><Alert message="註冊成功" description="你在本網站已經註冊成功,謝謝您的支持和反饋,多交流真正的技術吧" closable type="success" />

筆者已經將實現過的組件發布到npm上了,大家如果感興趣可以直接用npm安裝後使用,方式如下:

npm i @alex_xu/xui

// 導入xui

import {

Button,

Skeleton,

Empty,

Progress,

Tag,

Switch,

Drawer,

Badge,

Alert

} from '@alex_xu/xui'

該組件庫支持按需導入,我們只需要在項目裡配置babel-plugin-import即可,具體配置如下:

// .babelrc

"plugins": [

["import", { "libraryName": "@alex_xu/xui", "style": true }]

]

npm庫截圖如下:

最後

後續筆者將會繼續實現

modal(模態窗),badge(徽標),table(表格),tooltip(工具提示條),Skeleton(骨架屏),Message(全局提示),form(form表單),switch(開關),日期/日曆,二維碼識別器組件等組件, 來復盤筆者多年的組件化之旅.

相關焦點

  • 精通react/vue組件設計之配合React Portals實現一個(Drawer)組件
    通過組件的設計過程,大家會接觸到一個完成健壯的組件設計思路和方法,也能在實現組件的過程逐漸對react/vue的高級知識和技巧有更深的理解和掌握,並且在企業實際工作做遊刃有餘.作為數據驅動的領導者react/vue等MVVM框架的出現,幫我們減少了工作中大量的冗餘代碼, 一切皆組件的思想深得人心.
  • 《精通react/vue組件設計》之快速實現一個可定製的進度條組件
    今天要來實現一個高可定製的進度條組件,在介紹組件設計之前,我們先牢記以下幾個原則.每一個組件只負責某一特定的表現或者功能)正文在開始組件設計之前希望大家對css3和js有一定的基礎.我們先看看實現後的組件效果:上圖可以知道封裝後的進度條組件通過對外暴露的接口(react/vue裡面可以看做
  • 精通react/vue組件設計之實現一個Tag(標籤)和Empty(空狀態)組件
    "辛勤勞動",而是要根據已有前端的開發經驗,總結出一套自己的高效開發的方法.作為數據驅動的領導者react/vue等MVVM框架的出現,幫我們減少了工作中大量的冗餘代碼, 一切皆組件的思想深得人心.所以, 為了讓工程師們有更多的時間去考慮業務和產品迭代,我們不得不掌握高質量組件設計的思路和方法.所以筆者將花時間去總結各種業務場景下的組件的設計思路和方法,並用原生框架的語法去實現各種常用組件的開發,希望等讓前端新手或者有一定工作經驗的朋友能有所收穫
  • 精通React/Vue系列之帶你實現一個功能強大的通知提醒框
    本文將會使用React來開發該組件,也會使用到Javascript中常用的一些設計模式,比如單例模式,但是不管你使用什麼框架來實現,原理都是通用的,如果感興趣的朋友可以用vue也實現以一下。正文在開始組件設計之前希望大家對css3和js有一定的基礎,並了解基本的react/vue語法.我們先來解構一下Notification組件, 一個Notification分為以下幾個部分:每一個區塊都可以自定義配置, 也可以組合其他組件.並且我們可以配置提醒框出現的位置,就像antd
  • 如何寫一個vue組件專題及常見問題 - CSDN
    轉自:https://www.cnblogs.com/pengchenggang/p/10880437.html如何寫好一個vue組件一個適用性良好的組件,一種是可配置項很多,另一種就是容易覆寫,從而擴展功能Vue 組件的 API 來自三部分——prop、事件和插槽:prop 允許外部環境傳遞數據給組件event 允許從組件內觸發外部環境的副作用slot
  • Vue3 & React Hooks 新UI組件原理:Modal 彈窗
    然後又無意間刷到「Portal」,才知道Modal的實現還有如此妙的方式,順而想著乾脆把UI組件庫的實現原理看完。❝以下引自:《Vue 中的 Portal 技術》❞以vue-dom-portal為例,代碼非常簡單無非就是將當前的 dom 移動到指定地方:
  • 基於Vue實現一個有點意思的拼拼樂小遊戲
    vue的第三方移動端ui庫,筆者推薦如下:Mint 餓了麼推出的移動端ui庫NutUI 一套京東風格的移動端組件庫muse-ui 基於MaterialUI風格的移動端UI組件cube-ui滴滴團隊開發的移動端UI組件庫vant 有贊團隊的電商風格的移動端組件庫atom-design atom風格的移動端ui組件庫mand-mobile 滴滴團隊研發的基於金融場景的移動端ui組件庫
  • vuex實現預熱篇-vue插件開發
    #泛舟計劃·讓知識更好看#1.如何引用vue插件呢?Vue.use(Vuex)2.use做了什麼事呢?構造函數和{size:1000} console.log('logger in outputing')}Vue.use(MyLoggerPlugin, {size: 1000})以上就是咱們完成的一個列印的vue插件,是不是很簡單4.一個插件你可以看成是一個組件,一個組件也是一個完成的vue實例,所以vue實例有的他都有// Myplugin作為對象傳入const
  • GitHub上star超1.2k的vue表格組件,功能太多又實用
    組件名稱:vxe-table項目地址:Github:https://github.com/xuliangzhan/vxe-table>碼云:https://gitee.com/xuliangzhan_admin/vxe-table一個基於 vue 的表格組件,支持增刪改查、虛擬滾動、懶加載、快捷菜單、數據校驗、樹形結構、列印導出、表單渲染、數據分頁、模態窗口、自定義模板、賊靈活的配置項、豐富的擴展插件等面向現代瀏覽器
  • 前端組件/庫打包利器rollup使用與配置實戰
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫目前主流的前端框架vue和react都採用rollup來打包,為了探索rollup的奧妙,接下來就讓我們一步步來探索,並基於rollup搭建一個庫打包腳手架,來發布自己的庫和組件。
  • React組件之間的8種通訊方式
    最簡單的方式是在父組件中傳遞一個函數給子組件,子組件可以使用這個函數來把數據傳給它的父組件。在父組件中可以這樣把一個函數作為屬性傳給子組件,例如:然後子組件可以這樣調用這個函數:最後不要忘記在子組件的 propTypes 中聲明這個函數:4.事件冒泡事件冒泡並非 React 的概念,而是瀏覽器中 DOM 的事件機制。和回調函數類似,它也可以把數據從子組件發送到父組件。
  • React 靈魂 23 問,你能答對幾個?
    但是之前數據結構不支持這樣的實現異步 diff,於是 React 實現了一個類似鍊表的數據結構,將原來的 遞歸diff 變成了現在的 遍歷diff,這樣就能做到異步可更新了。虛擬dom 相當於在 JS 和真實 dom 中間加了一個緩存,利用 diff 算法避免了沒有必要的 dom 操作,從而提高性能。9、錯誤邊界是什麼?它有什麼用?在 React 中,如果任何一個組件發生錯誤,它將破壞整個組件樹,導致整頁白屏。這時候我們可以用錯誤邊界優雅地降級處理這些錯誤。
  • 又一款基於Vue的數據可視化組件庫,Github上star超1.4k,太酷炫
    組件庫名稱:DataV項目地址:https://github.com/DataV-Team/DataVDataV是一個基於Vue的數據可視化組件庫(當然也有React版本)提供用於提升頁面視覺效果的SVG邊框和裝飾提供常用的圖表如折線圖等飛線圖/輪播表等其他組件npm安裝$ npm install @jiaminghi/data-view使用import
  • 10個簡單的技巧讓你的 vue.js 代碼更優雅 - 酷扯兒
    任何其他非字符串值都可能出錯,並會觸發警告。任何其它非字符串類型的值都將會觸發一個警告。<!-- 這會觸發一個編譯警告 且 無效 --><a v-bind:['foo' + bar]="value"> ... </a>變通的辦法是使用沒有空格或引號的表達式,或用計算屬性替代這種複雜表達式。@hook那些事處理組件內定時器的步驟。
  • 專欄l 利用數字孿生和創成設計實現單色器狹縫組件的正向設計
    單色器的狹縫是一個關鍵組件,狹縫的開口平行性、對稱性以及開閉的均勻性、狹縫寬度和解析度等指標的精度直接影響單色器的光譜解析度和/或空間分辨能力。特別是最窄的狹縫是決定單色器解析度的關鍵因素。這個精度要求很難通過加工或拼裝來達到,需要通過機電結合的方法來實現。通常的做法是通過高精度機構加上閉環伺服控制系統實現狹縫寬度的連續可變,可以滿足技術指標的要求,但是成本很高。如何以低成本實現高精度要求,是本文面臨的課題。從國外的一款高端產品中發現的可借鑑的機構,但只能看到機構,而隱藏在後面的控制系統是無法知曉的。圖2 國外單色器的狹縫組件。
  • 18GW電池+8GW組件!蘇州愛康光電發布高效異質結電池及組件項目設計...
    近日,蘇州愛康光電科技有限公司發布18GW高效異質結太陽能電池項目及8GW組件項目設計招標公告。
  • 我發現了 Vue.js 中的性能陷阱
    所有這些警告均來自我創建的、用來顯示名為 Cards.vue 選項的組件,因此這個組件可能需要大量重寫。我決定按順序解決這些控制臺警告。使用它時,我們需要一個 :key 才能有效地重渲染組件。但我們將一個對象用作了一個鍵,這是非原始值,因此導致了這個錯誤。我決定將 index.description 用作一個新鍵,因為它是一個字符串,並且在值發生更改時可以更好地重新渲染。
  • 準備將您的Vue應用遷移到Vue 3
    看起來不錯,因為您可以在模板語法中實現它。/helper/filter'// your vue object{methods: { toCurrency }}注意:只是toCurrency可以使用;)感謝ES6對象屬性的簡寫將組件重構model為.sync根據RFC文檔,Vue 3將棄用modelVue組件中的選項,並將其替換sync為multiple model。
  • Vue超好玩的新特性:DOM傳送門
    我們來解釋一下:「目的地」:任意門的使用方法是"在打開門時要想著目的地,否則將通向無法預知的地區"「受目的地環境的影響」:假如你的目的地是一個極寒之地,那麼你就會像下圖這樣:這麼做完全可以實現,事實上以前我們大家一直都是這樣實現類似需求的。
  • jquery技巧之讓任何組件都支持類似DOM的事件管理
    發布-訂閱模式很多博客包括書本上都說javascript要實現組件的自定義事件的話,可以採用發布-訂閱模式,起初我也是堅定不移地這麼認為的,於是用jquery的$.Callbacks寫了一個:define(function(require, exports, module) {     var $ = require('jquery