前言
作為一個前端框架的重度使用者,在技術選型上也會非常注意其生態和完整性.筆者先后開發過基于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:6px1em;
- 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,#fff10%,transparent11%);
- background-repeat:no-repeat;
- background-position:50%;
- transform:scale(12,12);
- opacity:0;
- transition:transform.6scubic-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, 代碼很簡單, 我們來看看吧.
- importclassnamesfrom'classnames'
- importstylesfrom'./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(默認)
- */
- exportdefaultfunctionButton(props){
- let{children,onClick,className,type,shape,block}=props
-
return
- className={classnames(styles.xButton,styles.ripple,styles[type],styles[shape],block?styles.block:'',className)}
- onClick={onClick}
- >
- {children}
- }
這是button的js部分,也是組件設計的核心, 按鈕組件對外暴露了onClick, className, type, shape, block這幾個props, className用于修改組件類名以便控制組件樣式, type主要是控制組件的風格, 類似于antd的primary等樣式, shape用來控制是否是圓形按鈕還是圓角按鈕, block用來控制按鈕是否是塊.具體形式如下:
經過優化后的css長這樣:
- .xButton{
- box-sizing:border-box;
- display:inline-block;
- padding:6px1em;
- 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:1pxsolid#ccc;
- color:rgba(0,0,0,0.65);
- background-color:#fff;
- &::after{
- background-image:radial-gradient(circle,#ccc10%,transparent11%);
- }
- }
- //形狀
- &.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,#fff10%,transparent11%);
- 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'
- importstylesfrom'./index.css'
- exportdefaultfunction(){
- return(
-
-
default -
"warning" >warning -
"primary" >primary -
"info" >info -
"pure" >pure -
"primary" shape="circle">circle -
"primary" block>primary&block -
"warning" shape="circle"blockonClick={()=>{alert('block')}}>circle&block -
- )
- }
之前我們看到的按鈕樣式就是通過如上代碼生成的,是不是很簡單呢? 來我們再次看看點擊的動效:
其實不僅僅是react, 我們使用同樣的原理也可以實現一個vue版的按鈕組件或者一個angular版的組件,變得只是語法而已.這樣的組件設計思路和元素被官方用在很多ui庫中, 比如單一職責原理, 組件的開閉原則, 去中心,可組合等,希望對大家今后設計組件有所幫助。
原文鏈接:https://mp.weixin.qq.com/s/12RK-qqnXKxawZMIa_ViRA