如何用純css打造類materialUI的按鈕點擊動畫並封裝成react組件

2020-12-25 酷扯兒

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

前言

作為一個前端框架的重度使用者,在技術選型上也會非常注意其生態和完整性.筆者先後開發過基於vue,react,angular等框架的項目,碧如vue生態的elementUI, ant-design-vue, iView等成熟的UI框架, react生態的ant-design, materialUI等,這些第三方UI框架極大的降低了我們開發一個項目的成本和複雜度,使開發者更專注於實現業務邏輯和服務化.

但隨著對用戶體驗的越來越重視,對交互體驗要求的提高以及css3等新標準的出現,使得web更加大放異彩, 各種動效的實現都變得非常容易.筆者在研究materialUI框架時對於它的交互及其讚嘆.所以為了自己能實現一個類似materialUI的按鈕點擊動畫,並封裝到自己的UI庫中,筆者特地總結了一些思路,希望可以和廣大的前端工程師們一起探討.

正文

首先我們看一下materialUI的按鈕點擊效果:

本質上也是用了css3動畫的特性, 筆者查看原始碼和通過點擊發現materialUI會根據點擊位置不同而作不同位置的動畫,這個有點意思.我們先不講這麼複雜的例子,下面通過css3的方案來實現一個類似的效果.筆者實現的效果如下:

上圖已經是筆者基於react封裝好的一個按鈕Button組件,那麼我們就先一步步實現它吧.

1. 原理

這個動效的原理其實也很簡單,就是利用css3的transition過渡動畫,配合::after偽對象就可以實現,點擊的時候由於元素會激活:active偽類, 然後我們基於這個偽類, 在::after偽對象上做背景的動畫即可. 偽代碼如下:

.xButton {

position: relative;

overflow: hidden;

display: inline-block;

padding: 6px 1em;

border-radius: 4px;

color: #fff;

background-color: #000;

user-select:none; // 禁止用戶選中

cursor: pointer;

}

.ripple {

&::after {

content: "";

display: block;

position: absolute;

width: 100%;

height: 100%;

top: 0;

left: 0;

background-image: radial-gradient(circle, #fff 10%, transparent 11%);

background-repeat: no-repeat;

background-position: 50%;

transform: scale(12, 12);

opacity: 0;

transition: transform .6s cubic-bezier(.75,.23,.43,.82), opacity .6s;

}

&:active::after {

transform: scale(0, 0);

opacity: .5;

}

}

複製代碼

以上代碼就是通過設置transform的scale以及透明度, 並且設置一個漸變的徑向背景圖像來實現水波紋動畫的為了實現更優雅的動畫,上面的css動畫的實現可以藉助cubic-bezier這個在線工具,他可以生成各種不同形式的貝塞爾曲線.工具長這樣:

2. 組件設計思路

僅僅用上述代碼雖然可以實現一個按鈕點擊的動畫效果,但是並不通用, 也不符合作為一個經驗豐富的程式設計師的風格,所以接下來我們要一步步把它封裝成一個通用的按鈕組件,讓它無所不用.

組件的設計思路我這裡參考ant-design的模式, 基於開閉原則,我們知道一個可擴展的按鈕組件一般都具備如下特點:

允許用戶修改按鈕樣式對外暴露按鈕事件方法提供按鈕主題和外形配置可插拔,可組合 基於以上幾點,我們來設計這個react組件.3. 基於react和css3的button組件具體實現

首先,我們的組件是採用react實現, 技術點我會採用比較流行的umi腳手架, classnames庫以及css Module, 代碼很簡單, 我們來看看吧.

import classnames from 'classnames'

import styles from './index.less'

/**

* @param {onClick} func 對外暴露的點擊事件

* @param {className} string 自定義類名

* @param {type} string 按鈕類型 primary | warning | info | default | pure

* @param {shape} string 按鈕形狀 circle | radius(默認)

* @param {block} boolean 按鈕展示 true | false(默認)

*/

export default function Button(props) {

let { children, onClick, className, type, shape, block } = props

return <div

className={classnames(styles.xButton, styles.ripple, styles[type], styles[shape], block ? styles.block : '', className)}

onClick={onClick}

>

{ children }

</div>

}

複製代碼

這是button的js部分,也是組件設計的核心, 按鈕組件對外暴露了onClick, className, type, shape, block這幾個props, className用於修改組件類名以便控制組件樣式, type主要是控制組件的風格, 類似於antd的primary等樣式, shape用來控制是否是圓形按鈕還是圓角按鈕, block用來控制按鈕是否是塊.具體形式如下:

經過優化後的css長這樣:

.xButton {

box-sizing: border-box;

display: inline-block;

padding: 6px 1em;

border-radius: 4px;

color: #fff;

font-family: inherit;

background-color: #000;

user-select:none; // 禁止用戶選中

cursor: pointer;

text-align: center;

&.primary {

background-color: #09f;

}

&.warning {

background-color: #F90;

}

&.info {

background-color: #C03;

}

&.pure {

border: 1px solid #ccc;

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

background-color: #fff;

&::after {

background-image: radial-gradient(circle, #ccc 10%, transparent 11%);

}

}

// 形狀

&.circle {

border-radius: 1.5em;

}

// 適應其父元素

&.block {

// width: 100%;

display: block;

}

}

.ripple {

position: relative;

overflow: hidden;

&::after {

content: "";

display: block;

position: absolute;

width: 100%;

height: 100%;

top: 0;

left: 0;

pointer-events: none;

background-image: radial-gradient(circle, #fff 10%, transparent 11%);

background-repeat: no-repeat;

background-position: 50%;

transform: scale(12, 12);

opacity: 0;

transition: transform .6s, opacity .6s;

}

&:active::after {

transform: scale(0, 0);

opacity: .3;

//設置初始狀態

transition: 0s;

}

}

複製代碼

我們實現按鈕樣式的切換完全是用css module帶來的高靈活性, 使其讓屬性和類名高度關聯. 接下來看看我們如何使用吧:

// index.js

import { Button } from '@/components'

import styles from './index.css'

export default function() {

return (

<div className={styles.normal}>

<Button className={styles.btn}>default</Button>

<Button className={styles.btn} type="warning">warning</Button>

<Button className={styles.btn} type="primary">primary</Button>

<Button className={styles.btn} type="info">info</Button>

<Button className={styles.btn} type="pure">pure</Button>

<Button className={styles.btn} type="primary" shape="circle">circle</Button>

<Button className={styles.mb16} type="primary" block>primary&block</Button>

<Button type="warning" shape="circle" block onClick={() => { alert('block')}}>circle&block</Button>

</div>

)

}

複製代碼

之前我們看到的按鈕樣式就是通過如上代碼生成的,是不是很簡單呢? 來我們再次看看點擊的動效:

其實不僅僅是react, 我們使用同樣的原理也可以實現一個vue版的按鈕組件或者一個angular版的組件,變得只是語法而已.這樣的組件設計思路和元素被官方用在很多ui庫中, 比如單一職責原理, 組件的開閉原則, 去中心,可組合等,希望對大家今後設計組件有所幫助.

相關焦點

  • 精通react/vue組件設計之配合React Portals實現一個(Drawer)組件
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫前言本文是筆者寫組件設計的第六篇文章,內容依次從易到難,今天會用到react的高級API React Portals,它也是很多複雜組件必用的方法之一.
  • 一個在線css三角形生成器
    在線css三角形生成器預覽由預覽動畫我們可以看到通過在線工具我們可以輕鬆配置各種想要的三角形, 並且能實時查看css代碼. 開發完這個工具之後筆者再也不用擔心還需要手寫三角形代碼了.(上班摸魚也成了可能, 確實很多時候就是不想寫代碼還想要有錢拿) 在文末筆者會附上css工具的在線地址, 接下來我們來看看具體實現流程.
  • 不要再在JavaScript中寫 CSS了
    為了完全透明,我還要指出我是 react-css-modules 和 babel-plugin-react-css-modules 的作者。 你能知道這些組件會渲染成什麼 HTML 標籤嗎?不,你不知道。
  • React SSR 同構入門與原理
    兼容路由同構項目中當在瀏覽器中輸入 URL 後,瀏覽器是如何找到對應的界面?redux 都添加完畢後,最後我們在組件中使用 redux 的方式獲取數據,改造 Home 組件:import React from"react";import { Link } from"react-router-dom";import { connect } from"react-redux
  • 「首席架構師推薦」關於React生態系統的一系列精選資源(2)
    - 使用CSS為React設置動畫的加載指示符集合rheostat - 使用React構建的可訪問滑塊組件qrcode.react - 用於React的QR組件做出React 命令行react-magic - 利用React的強大功能自動AJAXify純HTMLreact-toolbox - 一組實現Google Material Design規範的React組件tcomb-react - 允許您檢查React組件的所有道具的庫
  • 十大最受歡迎的 React Native 應用開發編輯器
    點擊上方「 CSDN 」,選擇「置頂公眾號」關鍵時刻,第一時間送達!作者丨 Murtaza Basrai譯者 丨 安翔市面上用於開發工作的編輯器非常多,筆者會經常因為不同的程式語言該如何選擇好用的編輯器而感到糾結。
  • react中關於hook介紹及其使用
    前言最近由於公司的項目開發,就學習了在react關於hook的使用,對其有個基本的認識以及如何在項目中去應用hook。能夠解決你在不使用class組件的情況下去體現react的特性需要注意的一點就是hook和class組件是不能夠同時使用的,在實際的使用過程中一定要注意,否則就會出現報錯那麼接下來所要介紹的部分就是如何去使用hookstate hook
  • 高世代光伏組件用封裝玻璃極限尺寸探討
    【能源人都在看,點擊右上角加'關注'】北極星太陽能光伏網訊:摘要:隨著光伏組件發電功率的增加,光伏組件的尺寸增大,相應的組件用封裝玻璃尺寸也逐漸增大。本文從光伏玻璃產能、組件重量及運輸方式三個方面對光伏組件用封裝玻璃尺寸的影響進行分析,並對光伏組件用封裝玻璃尺寸的發展現狀進行了概述,根據市場的發展情況,對光伏組件用封裝玻璃未來的發展方向進行了探討。
  • 關於GraphQL使用「React」(阿波羅)創建應用程式
    然而,解決者是用你選擇的語言寫的;在這種情況下,JavaScript。GraphQL——在客戶端在客戶端,第一步將連接到GraphQL伺服器和包裝根組件與提供者(ApolloProvider react-apollo):import React from 'react';import ReactDOM from
  • 手把手教你打造一個純CSS圖標庫
    通常做法就兩種: 直接使用圖片; 使用css/svg直接在瀏覽器中繪製圖標。 方案1:由於圖標圖片比較多,而且體積很小,為了減少請求所以很多時候我們會用雪碧圖這種技術來將圖標拼湊在同一張圖片裡面。你也能想到,一堆圖標的雪碧圖,修改維護會相當麻煩!現在比較好的方案是使用webpack引入圖片,小圖直接轉換成base64插入css中。
  • 微信小程序抽獎轉盤組件怎麼做?
    微信小程序轉盤抽獎組件的實現思路1.界面樣式實現從抽獎轉盤的圖中我們可以看出,抽獎轉盤由外圓、扇面抽獎選項、抽獎按鈕組成,其中外圓不難實現,大家在處理微信小程序頭像的時候估計都已經用過了,那就是利用border-radius:50%來將一個正方形變成圓,這是外圓實現的關鍵
  • 如何使用React Hooks實現容器組件?
    React Hooks是React功能組件中能夠管理狀態和組件生命周期的組件。它能夠有效地使組件都具有功能性,甚至可以說大大減少了對基於類的組件的需求。容器組件中的容器到底是什麼?「對數據獲取,然後將數據呈現在相應的子組件中。這就是容器。」
  • 有趣的CSS小示例:好看的皮囊千篇一律,有趣的靈魂萬裡挑一
    文字加載...動畫html正在加載中<dot>...原來是dot元素,沿著Y軸在循環位移,隱藏掉就讓你看到了加載的動畫效果。border 實現邊框當你需要這樣一個上傳文件,按鈕時,你考慮的是找設計弄個圖片,還是自己寫一個???其實CSS寫,也很簡單的。
  • 純css瀑布流樣式探索
    最近做項目時又遇到瀑布流的樣式需求,陌生又熟悉,首先想到的就是用Multi-columns布局方式:關鍵樣式代碼如下
  • 前端學習——匯集了大量 CSS 的使用和學習的示例代碼
    :hover實現純 CSS 方式控制動畫的暫停與播放偽類:checked實現純 CSS 方式控制動畫的暫停與播放偽類:target實現純 CSS 方式控制動畫的暫停與播放偽元素實現邊界智能判斷移動偽元素實現打點 loading 效果偽元素遮罩實現線條 loading 效果
  • Vue中使用animate.css實現動畫效果
    在實際開發過程中,有些頁面需要一些炫酷的動畫效果這時我們可以通過animate來實現Animate是一個非常實用的動畫庫官網: https://animate.style/Animate動畫庫裡面有很多實用的動畫效果展示如下:應用實例效果展示:使用方法:在vue中使用animate.css第一步:安裝
  • 官宣:ReactNative導航庫重大更新
    基於配置的組件在之前的版本中,我們創建一些導航路由,比如創建堆棧導航,底部Tab導航,都是採用的靜態的配置navigationOptions選項來完成的。但是在React Navigation 5.0中是做了基於組件的動態配置的鑫的方式,和以前的版本完全不一樣。
  • 強大的CSS原生樣式支持,不費吹灰之力就搞定註冊頁面
    實施步驟詳解首先,打開報表設計器,先拖動輸入框組件和按鈕組件,把需要製作的樣式排版好。其次,既然要高大上,那深沉高級的背景肯定不能少。我們選中編輯界面的表單組件,然後打開自定義樣式設置對話框:在這裡寫的css樣式就會自動適用於組件上啦!
  • 利用CSS、JavaScript及Ajax實現圖片預加載的三大方法
    方法一:用CSS和JavaScript實現預加載實現預加載圖片有很多方法,包括使用CSS、JavaScript及兩者的各種組合。這些技術可根據不同設計場景設計出相應的解決方案,十分高效。相反,我更喜歡使用純JavaScript來實現圖片的預加載。下面將提供兩種這樣的預加載方法,它們可以很漂亮地工作於所有現代瀏覽器之上。
  • B端設計指南03——按鈕,究竟應該如何設計
    ,去除這類反饋,會導致用戶無法用方向鍵控制光標位置,在很大程度上降低用戶使用的可能性。 難點二:禁用與激活狀態的切換,比如在一個註冊頁面中,需要姓名與電話必填,當用戶沒有填寫完成姓名與電話時,應該將按鈕置灰,提示用戶不可以點擊,當用戶填寫完成必填欄位後,將禁用按鈕轉變為激活按鈕,提示用戶可以點擊登錄。