本文是筆者寫組件設計的第八篇文章, 今天帶你們用5分鐘實現一個極具創意的加載(loading)組件.涉及的核心知識點主要是css3相關特性, 若是你們很是熟悉,可直接跳過介紹直接看正文.javascript
時刻問本身:是否具有創造力?css
因此咱們在設計組件系統的時候能夠參考如上分類去設計,該分類也是antd, element, zend等主流UI庫的分類方式.html
若是對於react/vue組件設計原理不熟悉的,能夠參考個人以前寫的組件設計系列文章:前端
筆者已經將組件庫發佈到npm上了, 你們能夠經過npm安裝的方式體驗組件.vue
在開始組件設計以前但願你們對css3和js有必定的基礎,並瞭解基本的react/vue語法.咱們先看看實現後的組件效果: java
由於動圖體積太大,就不給你們傳gif了,接下來咱們具體分析一下該組件的特色.按照以前筆者總結的組件設計原則,咱們第一步是要確認需求. 首先咱們設計的不是後臺管理系統專用的加載動畫,而是做爲一個C端產品的功用型加載動畫.咱們都知道加載動畫的做用是:在用戶等待網頁時能看到有用的信息,好比網站介紹,引導, 公司信息等,緩解用戶焦慮. 做爲一名產品經理或者用戶體驗師, 這種個性化的加載體驗效果每每是更好的.node
而加載動畫通常會分爲策略型加載動畫和通用加載動畫,通用加載動畫我就不說了,你們平時作的系統大部分應該都是通用型加載動畫. 我這裏介紹一下策略型加載動畫: 策略型加載動畫每每用在C端產品或者系統中,用來爲用戶提供更多的引導信息, 當用戶首次訪問系統或者網站時, 因爲某種主動型引導(網站在加載時或者切換頁面時故意給用戶看到的加載信息)或者環境緣由(網絡,帶寬限制致使的加載過慢,此時出現加載動畫), 這些加載信息每每帶有某種用途,好比對於我的博客網站, 這個加載動畫能夠是博主的介紹,博主的宣傳信息,github地址等, 對於企業來講,多是某個新功能的介紹, 網站服務信息的介紹,聯繫方式等.react
在瞭解完以上背景後, 咱們來看看組件設計的線框圖: webpack
對於react選手來講,若是沒用typescript,建議你們都用PropTypes, 它是react內置的類型檢測工具,咱們能夠直接在項目中導入. vue有自帶的屬性檢測方式,這裏就不一一介紹了.經過以上需求分析, 其實一個加載動畫很是簡單, 不會涉及到太多功能, 主要在於css3動畫的使用. 具體屬性有:css3
接下來咱們就來看看具體實現.
由於該組件不會涉及到太多的js代碼,主要是html和css,因此咱們直接先構建組件的結構:
/** * 骨架屏組件(SEO) * @param {isLoading} bool 加載狀態 * @param {loadingText} string 加載時的加載文本 */
export default function Skeleton(props) {
let { isLoading = true, loadingText = '正在爲您瘋狂加載...' } = props
return isLoading ? <div className={styles.skeletonWrap}> <div className={styles.skeletonContent} data-loadingText={loadingText}> 自定義的引導內容 </div> </div> : null
}
複製代碼
自定義的引導內容這裏我就不介紹了, 主要根據不一樣的網站性質靈活配置.我主要介紹加載動畫部分, 其實原理也很簡單, 咱們在skeletonContent元素上使用一個::after僞對象來實現窗簾動畫便可.
在實現動畫前你們最好對關鍵幀動畫有所瞭解,我相信你們都比較瞭解. 這種關窗簾動畫一種實現方式就是經過控制元素寬度, 從0到100%, 而後添加適當的要是優化便可. 動畫的代碼以下:
@keyframes spread {
0% {
width: 0;
}
100% {
width: 100%;
}
}
複製代碼
咱們只須要在::after裏直接這樣使用就行了:
&::after {
animation: spread 18s 3s infinite;
}
複製代碼
這樣動畫已經作完了, 可是爲了讓動畫更完整,咱們還要考慮一個事實, 若是窗簾寬度從0慢慢變化的過程當中, 加載動畫的文字一直保持一個顏色會很生硬, 以下圖:
因此說做爲一個好的交互設計來講, 要讓交互體驗更順暢,這裏提供一種方式,就是加載的文本在窗簾寬度變化的同時,文字的透明度從0變化到1,這樣就會柔和不少, 因此動畫能夠這麼改:&::after {
color: rgba(255, 255, 255, 0);
animation: spread 18s infinite;
}
@keyframes spread {
0% {
width: 0;
color: rgba(255, 255, 255, 0);
}
100% {
width: 100%;
color: rgba(255, 255, 255, 1);
}
}
複製代碼
效果以下:
最後咱們來實現loadingText. 這塊也涉及到一個知識點, 由於加載文本其實主要是用來修飾元素的,並無太多的語義化場景, 因此咱們會放在::after僞對象的content裏, 可是通常content是在css裏寫的,那麼如何實現動態文本呢? 咱們這裏就要採用css的屬性內容這個api. content不只僅能夠接收一個字符串,還能夠接收attr這個關鍵字,關鍵字裏面的內容是元素的自定義屬性, 好比:
<div data-tip="loading"></div>
複製代碼
那麼咱們在css裏能夠經過這種方式直接使用data-tip屬性的值:
div::after{
content: attr(data-tip)
}
複製代碼
經過以上的方式咱們能夠在::after裏直接拿到data-tip的內容了, content其實還有更多的功能,好比用純css實現一個計數器,你們能夠研究學習一下.
這樣,咱們的Loading組件就完成了, 還有一個問題是我代碼裏的組件命名,爲何叫骨架屏呢?其實咱們只要改變內容結構, 它立馬就能夠變成一個骨架屏,因此命名這塊能夠按照實際需求來肯定.
import PropTypes from 'prop-types'
// ...
Skeleton.propTypes = {
isLoading: PropTypes.bool,
loadingText: PropTypes.string
}
複製代碼
組件完整css代碼以下:
.skeletonWrap {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0,0,0, .6);
.skeletonContent {
position: relative;
margin: 200px auto 0;
padding: 20px;
width: 800px;
display: flex;
align-items: center;
border-radius: 8px;
overflow: hidden;
background-color: #fff;
&::after {
content: '正在爲您瘋狂加載...';
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 0;
height: 100%;
border-right: 2px solid #ccc;
box-shadow: 0 0 8px #000;
background: #096;
color: rgba(255, 255, 255, 0);
font-size: 24px;
white-space: nowrap;
animation: spread 18s 3s infinite;
}
@keyframes spread {
0% {
width: 0;
color: rgba(255, 255, 255, 0);
}
100% {
width: 100%;
color: rgba(255, 255, 255, 1);
}
}
.imgBox {
margin-right: 20px;
width: 400px;
.img {
width: 100%;
height: 200px;
background-color: #ccc;
}
img {
width: 100%;
}
}
.rightBox {
flex: 1;
.tit {
margin-top: 8px;
margin-bottom: 8px;
font-size: 22px;
}
.labelWrap {
span {
margin: 3px;
display: inline-block;
font-size: 12px;
padding: 2px 6px;
border-radius: 3px;
color: #fff;
background-color: #58bd6b;
}
}
.desc {
color: rgb(44, 44, 44);
font-size: 14px;
}
}
}
}
複製代碼
關於代碼中的css module和classnames的使用你們能夠本身去官網學習,很是簡單.若是不懂的能夠在評論區提問,筆者看到後會第一時間解答.
咱們能夠經過以下方式使用它:
<Skeleton loadingText="玩命加載中..." />
複製代碼
筆者已經將實現過的組件發佈到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庫截圖以下:
後續筆者將會繼續實現
等組件, 來複盤筆者多年的組件化之旅.
若是想獲取組件設計系列完整源碼, 或者想學習更多H5遊戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數據可視化等前端知識和實戰,歡迎在公號《趣談前端》加入咱們的技術羣一塊兒學習討論,共同探索前端的邊界。