《精通react/vue組件設計》之快速實現一個可定製的進度條組件

2020-12-24 酷扯兒

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

前言

這篇文章是筆者寫組件設計的第四篇文章,之所以會寫組件設計相關的文章,是因為作為一名前端優秀的前端工程師,面對各種繁瑣而重複的工作,我們不應該按部就班的去"辛勤勞動",而是要根據已有前端的開發經驗,總結出一套自己的高效開發的方法.作為數據驅動的領導者react/vue等MVVM框架的出現,幫我們減少了工作中大量的冗餘代碼, 一切皆組件的思想深得人心.所以, 為了讓工程師們有更多的時間去考慮業務和產品迭代,我們不得不掌握高質量組件設計的思路和方法.所以筆者將花時間去總結各種業務場景下的組件的設計思路和方法,並用原生框架的語法去實現各種常用組件的開發,希望等讓前端新手或者有一定工作經驗的朋友能有所收穫.

今天要來實現一個高可定製的進度條組件,在介紹組件設計之前,我們先牢記以下幾個原則.

每日一學: 組件設計三原則

高內聚, 低耦合(尤其是vue/react組件中, 降低組件之間的耦合尤為重要)組件邊界劃分清晰(每一個組件都有自己清晰的邊界劃分)單一職責(每一個組件只負責某一特定的表現或者功能)

正文

在開始組件設計之前希望大家對css3和js有一定的基礎.我們先看看實現後的組件效果:

上圖可以知道封裝後的進度條組件通過對外暴露的接口(react/vue裡面可以看做props屬性)可以很快的實現多個不同的表現和重用.我將會使用react帶大家實現這個進度條組件, 大家不用擔心技術棧不一樣,因為react實現的組件可以很快套用於vue項目中, 所以說底層原理非常重要.

1. 組件原理和設計思路

由於組件設計的前提還是基於需求, 所以我們第一步是要確認需求. 一個進度條組件一般都會有如下需求點:

通過進度控制進度條長度進度條總長度可以由用戶來控制隨時修改精度條的額顏色(來自於設計師或產品經理獨特而百變的審美)當進度為100%時進度條可以自動消失(可能的需求)進度提示文本(用戶想知道當前長度下的具體進度, 比如體溫計)對於不同的進度節點,需要有不同的進度條顏色(比如遊戲人物裡的血, 快沒血的時候為紅色, 血滿的時候為藍色)需求收集好之後,作為一個有追求的程式設計師, 會得出如下線框圖:

這也是一個健壯的react/vue組件應有的思考角度.對於react選手來說,如果沒用typescript,我建議大家都用PropTypes, 它是react內置的類型檢測工具,我們可以直接在項目中導入. vue有自帶的屬性檢測方式,筆者在這一點上認為vue還是很貼心的.

上面的思維導圖我們也知道了, 進度條組件的實現原理就是通過對外暴露一定的屬性,使用css先畫一個進度條, 最後通過屬性和樣式之間的調度來實現我們需求滿滿的進度條.至於如何畫進度條,下面會詳細介紹.

2. 基於react實現一個可定製的進度條組件

2.1. 實現進度條的靜態樣式

首先我們會有一個容器來包裹我們的進度條,進度條和進度提示文字分開(為了更靈活的配置), 這樣我們會得到一個如下的html結構:

<div className={styles.progressWrap}>

<div className={styles.progressBar}>

<div className={styles.progressInnerBar}></div>

</div>

<span className={styles.progressText}>{percent + '%'}</span>

}

</div>

.progressBar用來做進度條背景, .progressInnerBar用來做實際的進度條, .progressText為進度條文本.我們通過控制.progressInnerBar的寬度就能實現進度條的變化了, css代碼如下:

.progressWrap {

margin: 6px 3px;

display: inline-flex;

align-items: center;

.progressBar {

position: relative;

display: inline-block;

height: 10px;

background-color: #f0f0f0;

border-radius: 5px;

overflow: hidden;

.progressInnerBar {

position: absolute;

height: 100%;

}

}

.progressText {

margin-left: 6px;

margin-top: -2px;

font-size: 14px;

}

}

沒錯,css代碼就這麼簡單, 我們用了css3比較流行的額彈性布局flex, css部分由於都比較簡單,這裡我只提一點就是.progressInnerBar的css,使用絕對定位, 因為這個部分未來可能會做動畫,所以我們把它做成離屏dom, 因為它只做展示,它的寬度完全由js控制,後面我們會將會看到.

2.2 實現組件外殼

我們根據我們收集到的需求, 可以對外暴露7個自定義屬性(props),所以我們的react組件一定是這樣的:

/**

* 進度條組件

* @param {themeColor} string 進度條的顏色

* @param {percent} number 進度值百分比

* @param {autoHidden} boolean 是否進度到100%時自動消失

* @param {hiddenText} boolean 是否影藏進度條文本

* @param {width} string|number 進度條的寬度

* @param {textColor} string 進度文本顏色

* @param {statusScope} array 狀態閾值,分別設置不同進度範圍的進度條顏色,最大允許設置3個值, 為一個二維數組

*/

function Progress(props) {

let {

themeColor = '#06f',

percent = 0,

autoHidden = false,

hiddenText = false,

width = 320,

textColor = '#666',

statusScope

} = props

return

<div className={styles.progressWrap}>

<div className={styles.progressBar} style={{ width: typeof width === 'number' ? width + 'px' : width }}>

<div

className={styles.progressInnerBar}

style={{

width: `${percent}%`

}}

>

</div>

</div>

{

!hiddenText && <span className={styles.progressText} style={{ color: textColor }}>{percent + '%'}</span>

}

</div>

}

根據我們收集到的額需求我們很快可以知道react組件需要暴露哪些屬性,而不會造成多餘的屬性,這一點是非常好的設計方法, 核心思想就是基於需求設計.所以我們當確定需求之後,其實組件已經實現了.這一經驗一致應用於筆者很多實際項目中,也清晰的指引著我組件的最終實現.剩幾個關鍵點如下:

設置進度區間進度為100%時進度條自動消失3. react組件細節和最終實現

react組件中,一個屬性不一定要顯性的賦值才能正常工作,比如上面代碼中的hiddenText屬性, 如果我們不設置false或者true, 那麼react會默認為false, 如果只寫了hiddenText屬性而不賦值, react會自動認為它的值為true.這是react的一個設計細節,希望大家能了解掌握. 設置進度區間這個需求是組件唯一比較複雜的地方(相對來說,實際項目中有更複雜的案例),對應的屬性為statusScope, 它的值為一個數組,之所以為數組是為了開發人員更容易理解和使用,它的值可能如下:

let scope = [[30, 'red'], [60, 'orange'], [80, 'blue']]

最大閾值為3,意思就是用戶可以設置4種不同的進度狀態.每一個狀態用不同的顏色代替.由於用戶可以不是按照從小到大的順序寫數組的,所以為了組件的可靠性和容錯性, 筆者專門寫了排序方法對用戶傳來的額二維數組進行排序.具體代碼邏輯如下:

// 升序排序

let sortArr = arr => arr.sort((a,b) => a[0] - b[0])

// 檢測值所對應的進度條顏色狀態

function checkStatus(scope, val, defaultColor) {

val = +val

// 從小到大排序

sortArr(scope)

if(scope.length === 1) {

return val < scope[0][0] ? scope[0][1] : defaultColor

}else if(scope.length === 2) {

return val < scope[0][0] ? scope[0][1]

: scope[0][0] < val && val < scope[1][0] ? scope[1][1]

: defaultColor

}else if(scope.length === 3) {

return val < scope[0][0] ? scope[0][1]

: scope[0][0] < val && val < scope[1][0] ? scope[1][1]

: scope[1][0] < val && val < scope[2][0] ? scope[2][1]

: defaultColor

}

}

筆者不認為checkStatus是最優的計算閾值顏色的方法, 大家可以用更優雅的方法實現它.該方法的作用就是通過傳入用戶配置的區間和當前的進度值,來得到當前進度條的顏色.

進度為100%時進度條自動消失的邏輯也很簡單,就是判斷有這個屬性,並且進度為100時將組件卸載就好了,所以相對完整的代碼如下:

import styles from './index.less'

// 升序排序

let sortArr = arr => arr.sort((a,b) => a[0] - b[0])

// 檢測值所對應的進度條顏色狀態

function checkStatus(scope, val, defaultColor) {

val = +val

// 從小到大排序

sortArr(scope)

if(scope.length === 1) {

return val < scope[0][0] ? scope[0][1] : defaultColor

}else if(scope.length === 2) {

return val < scope[0][0] ? scope[0][1]

: scope[0][0] < val && val < scope[1][0] ? scope[1][1]

: defaultColor

}else if(scope.length === 3) {

return val < scope[0][0] ? scope[0][1]

: scope[0][0] < val && val < scope[1][0] ? scope[1][1]

: scope[1][0] < val && val < scope[2][0] ? scope[2][1]

: defaultColor

}

}

/**

* 進度條組件

* @param {themeColor} string 進度條的顏色

* @param {percent} number 進度值百分比

* @param {autoHidden} boolean 是否進度到100%時自動消失

* @param {hiddenText} boolean 是否影藏進度條文本

* @param {width} string|number 進度條的寬度

* @param {textColor} string 進度文本顏色

* @param {statusScope} array 狀態閾值,分別設置不同進度範圍的進度條顏色,最大允許設置3個值, 為一個二維數組

*/

function Progress(props) {

let {

themeColor = '#06f',

percent = 0,

autoHidden = false,

hiddenText = false,

width = 320,

textColor = '#666',

statusScope

} = props

return +percent === 100 && autoHidden ?

null :

<div className={styles.progressWrap}>

<div className={styles.progressBar} style={{ width: typeof width === 'number' ? width + 'px' : width }}>

<div

className={styles.progressInnerBar}

style={{

width: `${percent}%`,

backgroundColor: statusScope && statusScope.length ? checkStatus(statusScope, percent, themeColor) : themeColor

}}

>

</div>

</div>

{

!hiddenText && <span className={styles.progressText} style={{ color: textColor }}>{percent + '%'}</span>

}

</div>

}

大家也許覺得到這裡我們的組件就做好了.其實為了我們組件能夠健壯的執行,我們用propType來對屬性進行檢測.關於react的propTypes的用法,我們可以去react官網自行學習,用法也很簡單, 一下代碼我也會做完善的額注釋. 下面看看我們完整的效果演示:

完整代碼如下:

import PropTypes from 'prop-types'

import styles from './index.less'

// 升序排序

let sortArr = arr => arr.sort((a,b) => a[0] - b[0])

// 檢測值所對應的進度條顏色狀態

function checkStatus(scope, val, defaultColor) {

val = +val

// 從小到大排序

sortArr(scope)

if(scope.length === 1) {

return val < scope[0][0] ? scope[0][1] : defaultColor

}else if(scope.length === 2) {

return val < scope[0][0] ? scope[0][1]

: scope[0][0] < val && val < scope[1][0] ? scope[1][1]

: defaultColor

}else if(scope.length === 3) {

return val < scope[0][0] ? scope[0][1]

: scope[0][0] < val && val < scope[1][0] ? scope[1][1]

: scope[1][0] < val && val < scope[2][0] ? scope[2][1]

: defaultColor

}

}

/**

* 進度條組件

* @param {themeColor} string 進度條的顏色

* @param {percent} number 進度值百分比

* @param {autoHidden} boolean 是否進度到100%時自動消失

* @param {hiddenText} boolean 是否影藏進度條文本

* @param {width} string|number 進度條的寬度

* @param {textColor} string 進度文本顏色

* @param {statusScope} array 狀態閾值,分別設置不同進度範圍的進度條顏色,最大允許設置3個值, 為一個二維數組

*/

function Progress(props) {

let {

themeColor = '#06f',

percent = 0,

autoHidden = false,

hiddenText = false,

width = 320,

textColor = '#666',

statusScope

} = props

return +percent === 100 && autoHidden ?

null :

<div className={styles.progressWrap}>

<div className={styles.progressBar} style={{ width: typeof width === 'number' ? width + 'px' : width }}>

<div

className={styles.progressInnerBar}

style={{

width: `${percent}%`,

backgroundColor: statusScope && statusScope.length ? checkStatus(statusScope, percent, themeColor) : themeColor

}}

>

</div>

</div>

{

!hiddenText && <span className={styles.progressText} style={{ color: textColor }}>{percent + '%'}</span>

}

</div>

}

Progress.propTypes = {

themeColor: PropTypes.string,

percent: PropTypes.number,

autoHidden: PropTypes.bool,

textAlign: PropTypes.string,

hiddenText: PropTypes.bool,

width: PropTypes.oneOfType([

PropTypes.string,

PropTypes.number

]),

statusScope: PropTypes.array

}

export default Progress

關於如何使用,我就不做過多說明了,這裡舉2個例子:

<Progress

percent={percent}

width={240}

autoHidden

/>

<Progress

percent={10}

themeColor="#6699FF"

statusScope={[[18, 'red'], [40, 'orange']]}

/>

相關焦點

  • 《精通react/vue組件設計》之實現一個健壯的警告提示(Alert)組件
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫前言本文是筆者寫組件設計的第七篇文章, 今天帶大家實現一個自帶主題且可關閉的Alert組件, 該組件在諸如Antd或者elementUI等第三方組件庫中都會出現,主要用來提供系統的用戶反饋
  • 精通react/vue組件設計教你實現一個極具創意的加載(Loading)組件
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫前言本文是筆者寫組件設計的第八篇文章, 今天帶大家用5分鐘實現一個極具創意的加載(loading)組件.涉及的核心知識點主要是css3相關特性, 如果大家非常熟悉,可直接跳過介紹直接看正文
  • 精通React/Vue系列之帶你實現一個功能強大的通知提醒框
    本文將會使用React來開發該組件,也會使用到Javascript中常用的一些設計模式,比如單例模式,但是不管你使用什麼框架來實現,原理都是通用的,如果感興趣的朋友可以用vue也實現以一下。正文在開始組件設計之前希望大家對css3和js有一定的基礎,並了解基本的react/vue語法.我們先來解構一下Notification組件, 一個Notification分為以下幾個部分:每一個區塊都可以自定義配置, 也可以組合其他組件.並且我們可以配置提醒框出現的位置,就像antd
  • 基於jsoneditor二次封裝一個可實時預覽的json編輯器組件react版
    ,這樣一方面可以提高組件復用性和可擴展性,另一方面也帶來了項目開發的靈活性和可維護,方便多人開發協作.接下來文章將介紹如何使用react,開發一個自定義json編輯器組件.我們這裡使用了jsoneditor這個第三方庫,官方地址: jsoneditor 通過實現一個json在線編輯器,來學習如何一步步封裝自己的組件(不限於react,vue,原理類似).
  • 2020年5個最佳Vue移動端組件庫|UI框架
    小夥伴們平時開發vue,react或是angular項目,都喜歡使用的什麼UI組件庫呢?今天,就來盤點下,幾個熱門優質的Vue.js移動端UI組件庫。,能夠滿足日常的移動端開發需要可按需加載組件。標準規範:遵循統一的設計交互標準,高度還原設計效果。擴展性強:支持按需引入,輕量靈活;擴展性強,可以方便地實現二次開發。
  • 如何用純css打造類materialUI的按鈕點擊動畫並封裝成react組件
    , ant-design-vue, iView等成熟的UI框架, react生態的ant-design, materialUI等,這些第三方UI框架極大的降低了我們開發一個項目的成本和複雜度,使開發者更專注於實現業務邏輯和服務化.
  • 輕鬆使用純css3打造有點意思的故障藝術(附React加強組件版)
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫前言很早之前就看到國外很多酷炫的網站在實踐"故障藝術", 或者錯位動畫", 感覺非常有意思, 現在APP端的抖音啟動界面有著這種設計的影子, 作為一名用於探索未知的前端工程師, 有必要好好實踐一下這一設計.
  • 快速在你的vue/react應用中實現ssr(服務端渲染)
    默認情況下,可以在瀏覽器中輸出自定義組件,進行生成 DOM和操作 DOM, 也就是我們常說的客戶端渲染, 並且我們大部分主流的場景都是SPA(單頁面)應用, 而隨著 SPA尤其是 React、Vue、Angular 為代表的前端框架的流行
  • Element - 餓了麼團隊出品的神級桌面 UI 組件庫
    一套著名的桌面端的組件庫,同時提供Sketch、Axure模板資源文件方便快速產品設計。設計師可以下載設計文件,在做設計圖時直接使用模板,既能快速出圖,也保證了前端還原實現。我是一個喜歡研究前端開發的愛好者,當我第一次看到element時,臥槽真漂亮!
  • vue組件keep-alive知識詳解
    keep-alive是vue內置的一個組件,而這個組件的作用就是能夠緩存不活動的組件,我們能夠知道,一般情況下,組件進行切換的時候,默認會進行銷毀,如果有需求,某個組件切換後不進行銷毀,而是保存之前的狀態,那麼就可以利用keep-alive來實現
  • vue網頁聊天室|Vue+ElementUI仿微信界面
    項目介紹基於vue2+vuex+vue-cli+element-ui+swiper等技術開發仿微信pc端界面聊天應用,實現了發送消息+表情(動圖gif)、圖片/視頻預覽、右鍵長按菜單、紅包/朋友圈、截圖發送等功能。
  • 基於Vue實現一個有點意思的拼拼樂小遊戲
    cd pinpinle && yarn start複製代碼關於vue-cli3配置實戰,可以移步 一張圖教你快速玩轉vue-cli3H5遊戲核心功能介紹目前筆者主要整理樂如下核心功能,接下來筆者會一一帶大家實現
  • 如何使用React Hooks實現容器組件?
    今天,我們就來通過使用React Hooks實現容器組件。在開始使用React Hooks實現容器組件之前,先來簡單了解一下到底什麼是React Hooks和容器組件。> )}exportdefault DumbComponent;viewrawdumbComponent.jsx hosted with by GitHub因此,上面的代碼片段論證了如何在React組件中實現容器組件
  • 前端: 如何利用Qrcode製作一個二維碼生成器?
    玲琅滿目的二維碼在我們的都市和朋友圈中隨處可見, 很多平臺都提供了定製二維碼的服務, 那麼作為一名程式設計師, 我們如何自己實現一個簡單的二維碼生成器呢? 接下來筆者就來帶大家一起利用Qrcode實現一個二維碼生成器.
  • Vue-router路由系統詳細介紹
    single page application(單頁應用程式)前端路由錨點值監視ajax獲取動態數據核心點是錨點值前端框架 Vue/angular/react都很適合開發單頁應用基本使用vue-router其是vue的核心插件1:下載 npm i vue-router -
  • Vue.js布局
    (但假設有一個結帳流程,您不想顯示導航。或者您可能有帶側邊欄的產品頁面和沒有側邊欄的其他頁面等等)面對這種多樣性要求,我們要怎麼做來滿足業務需求的同時,保持代碼的可維護、易擴展呢?下面一起來探討。靜態布局包裝器組件:使用普通組件(包含布局不同部分的一個或多個插槽)作為視圖的包裝器,它提供了很大的靈活性,並且感覺不像條件渲染方法那麼髒。
  • 在vue項目中使用vuex實現狀態管理的案例
    說明:其實如果項目不是很龐大很複雜,沒有涉及到很多狀態值需要被很多頁面或組件共用;或者某個頁面或組件的行為會對其他頁面或組件造成依賴性的影響。並不需要使用vuex。vuex的使用與否在實際開發中應該視項目情況而定。
  • 如何正確地設計J2EE應用系統持久層中的各個組件結構及組件間關係
    (2)數據訪問邏輯組件(包括接口和對應的實現類)數據訪問邏輯組件是一個無狀態的物理資料庫系統訪問功能操作類,調用之間不存在狀態之間的傳遞。在結構和功能設計方面的主要目標如下:首先,數據訪問邏輯組件在結構設計方面要提供接口和對接口中定義的各個功能方法的實現類;其次,數據訪問邏輯組件在接口內定義的各個功能方法主要要處理以下的數據訪問技術實現的細節和為上層的業務層組件提供對應的功能服務:1)實現對目標資料庫表中數據的「增、
  • 2020年 16 個很有用的 Vue UI庫
    Vuetify (⭐️ 24k)網站:https://vuetifyjs.com/zh-Hans/github: https://github.com/vuetifyjs/vuetifyVuetify 是一個 Vue UI 庫,包含手工製作的精美材料組件。不需要設計技能 - 創建令人驚嘆的應用程式所需的一切都觸手可及。
  • 前端組件/庫打包利器rollup使用與配置實戰
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫目前主流的前端框架vue和react都採用rollup來打包,為了探索rollup的奧妙,接下來就讓我們一步步來探索,並基於rollup搭建一個庫打包腳手架,來發布自己的庫和組件。