《精通react/vue組件設計》之5分鐘教你實現一個極具創意的加載(Loading)組件

前言

本文是筆者寫組件設計的第八篇文章, 今天帶你們用5分鐘實現一個極具創意的加載(loading)組件.涉及的核心知識點主要是css3相關特性, 若是你們很是熟悉,可直接跳過介紹直接看正文.javascript

時刻問本身:是否具有創造力?css

[筆記]前端組件的通常分類:

  • 通用型組件: 好比Button, Icon等.
  • 佈局型組件: 好比Grid, Layout佈局等.
  • 導航型組件: 好比麪包屑Breadcrumb, 下拉菜單Dropdown, 菜單Menu等.
  • 數據錄入型組件: 好比form表單, Switch開關, Upload文件上傳等.
  • 數據展現型組件: 好比Avator頭像, Table表格, List列表等.
  • 反饋型組件: 好比Progress進度條, Drawer抽屜, Modal對話框等.
  • 其餘業務類型

因此咱們在設計組件系統的時候能夠參考如上分類去設計,該分類也是antd, element, zend等主流UI庫的分類方式.html

若是對於react/vue組件設計原理不熟悉的,能夠參考個人以前寫的組件設計系列文章:前端

筆者已經將組件庫發佈到npm上了, 你們能夠經過npm安裝的方式體驗組件.vue

正文

在開始組件設計以前但願你們對css3和js有必定的基礎,並瞭解基本的react/vue語法.咱們先看看實現後的組件效果: java

由於動圖體積太大,就不給你們傳gif了,接下來咱們具體分析一下該組件的特色.

1. 組件設計思路

按照以前筆者總結的組件設計原則,咱們第一步是要確認需求. 首先咱們設計的不是後臺管理系統專用的加載動畫,而是做爲一個C端產品的功用型加載動畫.咱們都知道加載動畫的做用是:在用戶等待網頁時能看到有用的信息,好比網站介紹,引導, 公司信息等,緩解用戶焦慮. 做爲一名產品經理或者用戶體驗師, 這種個性化的加載體驗效果每每是更好的.node

而加載動畫通常會分爲策略型加載動畫和通用加載動畫,通用加載動畫我就不說了,你們平時作的系統大部分應該都是通用型加載動畫. 我這裏介紹一下策略型加載動畫: 策略型加載動畫每每用在C端產品或者系統中,用來爲用戶提供更多的引導信息, 當用戶首次訪問系統或者網站時, 因爲某種主動型引導(網站在加載時或者切換頁面時故意給用戶看到的加載信息)或者環境緣由(網絡,帶寬限制致使的加載過慢,此時出現加載動畫), 這些加載信息每每帶有某種用途,好比對於我的博客網站, 這個加載動畫能夠是博主的介紹,博主的宣傳信息,github地址等, 對於企業來講,多是某個新功能的介紹, 網站服務信息的介紹,聯繫方式等.react

在瞭解完以上背景後, 咱們來看看組件設計的線框圖: webpack

對於react選手來講,若是沒用typescript,建議你們都用PropTypes, 它是react內置的類型檢測工具,咱們能夠直接在項目中導入. vue有自帶的屬性檢測方式,這裏就不一一介紹了.

經過以上需求分析, 其實一個加載動畫很是簡單, 不會涉及到太多功能, 主要在於css3動畫的使用. 具體屬性有:css3

  • 加載動畫出現時的加載文本
  • 控制加載狀態的state

接下來咱們就來看看具體實現.

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

由於該組件不會涉及到太多的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組件就完成了, 還有一個問題是我代碼裏的組件命名,爲何叫骨架屏呢?其實咱們只要改變內容結構, 它立馬就能夠變成一個骨架屏,因此命名這塊能夠按照實際需求來肯定.

3. 健壯性支持, 咱們採用react提供的propTypes工具:

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的使用你們能夠本身去官網學習,很是簡單.若是不懂的能夠在評論區提問,筆者看到後會第一時間解答.

4 使用Skeleton組件

咱們能夠經過以下方式使用它:

<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庫截圖以下:

最後

後續筆者將會繼續實現

  • modal(模態窗),
  • badge(徽標),
  • table(表格),
  • tooltip(工具提示條),
  • Skeleton(骨架屏),
  • Message(全局提示),
  • form(form表單),
  • switch(開關),
  • 日期/日曆,
  • 二維碼識別器組件

等組件, 來複盤筆者多年的組件化之旅.

若是想獲取組件設計系列完整源碼, 或者想學習更多H5遊戲, webpacknodegulpcss3javascriptnodeJScanvas數據可視化等前端知識和實戰,歡迎在公號《趣談前端》加入咱們的技術羣一塊兒學習討論,共同探索前端的邊界。

更多推薦

相關文章
相關標籤/搜索