《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件

徐小夕 等级 363 0 0

前言

作为一个前端框架的重度使用者,在技术选型上也会非常注意其生态和完整性.笔者先后开发过基于vue,react,angular等框架的项目,碧如vue生态的elementUI, ant-design-vue, iView等成熟的UI框架, react生态的ant-design, materialUI等,这些第三方UI框架极大的降低了我们开发一个项目的成本和复杂度,使开发者更专注于实现业务逻辑和服务化.

但随着对用户体验的越来越重视,对交互体验要求的提高以及css3等新标准的出现,使得web更加大放异彩, 各种动效的实现都变得非常容易.笔者在研究materialUI框架时对于它的交互及其赞叹.所以为了自己能实现一个类似materialUI的按钮点击动画,并封装到自己的UI库中,笔者特地总结了一些思路,希望可以和广大的前端工程师们一起探讨.

正文

首先我们看一下materialUI的按钮点击效果: 《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件 本质上也是用了css3动画的特性, 笔者查看源代码和通过点击发现materialUI会根据点击位置不同而作不同位置的动画,这个有点意思.我们先不讲这么复杂的例子,下面通过css3的方案来实现一个类似的效果.笔者实现的效果如下: 《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件 上图已经是笔者基于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这个在线工具,他可以生成各种不同形式的贝塞尔曲线.工具长这样: 《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件

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用来控制按钮是否是块.具体形式如下:

《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件 经过优化后的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组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件 其实不仅仅是react, 我们使用同样的原理也可以实现一个vue版的按钮组件或者一个angular版的组件,变得只是语法而已.这样的组件设计思路和元素被官方用在很多ui库中, 比如单一职责原理, 组件的开闭原则, 去中心,可组合等,希望对大家今后设计组件有所帮助.

最后

如果想了解本文完整的思维导图, 更多H5游戏, webpacknodegulpcss3javascriptnodeJScanvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们一起学习讨论,共同探索前端的边界。

《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件

更多推荐

收藏
评论区

相关推荐

React Hooks 快速上手
React Hook 快速上手 一、 Hook 简介 1.1 Hook历史 在React Hook出现之前的版本中,组件主要分为两种:函数式组件和类组件。其中,函数式组件通常只考虑负责UI的渲染,没有自身的状态也没有业务逻辑代码,是一个纯函数。而类组件则不同,类组件有自己的内部
前端组件/库打包利器rollup使用与配置实战
目前主流的前端框架vue和react都采用rollup来打包,为了探索rollup的奥妙,接下来就让我们一步步来探索,并基于rollup搭建一个库打包脚手架,来发布自己的库和组件。 (https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/16cb1c297071015523fb08d9e0f
基于jsoneditor二次封装一个可实时预览的json编辑器组件(react版)
前言 做为一名前端开发人员,掌握vue/react/angular等框架已经是必不可少的技能了,我们都知道,vue或react等MVVM框架提倡组件化开发,这样一方面可以提高组件复用性和可扩展性,另一方面也带来了项目开发的灵活性和可维护,方便多人开发协作.接下来文章将介绍如何使用react,开发一个自定义json编辑器组件.我们这里使用了jsoneditor
《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件
前言 作为一个前端框架的重度使用者,在技术选型上也会非常注意其生态和完整性.笔者先后开发过基于vue,react,angular等框架的项目,碧如vue生态的elementUI, antdesignvue, iView等成熟的UI框架, react生态的antdesign, materialUI等,这些第三方UI框架极大的降低了我们开发一个项目的成本和
《精通react/vue组件设计》之配合React Portals实现一个功能强大的抽屉(Drawer)组件
前言 本文是笔者写组件设计的第六篇文章,内容依次从易到难,今天会用到react的高级API React Portals,它也是很多复杂组件必用的方法之一. 通过组件的设计过程,大家会接触到一个完成健壮的组件设计思路和方法,也能在实现组件的过程逐渐对react/vue的高级知识和技巧有更深的理解和掌握,并且在企业实际工作做游刃有余. 之所以会写组件设计相关
轻松使用纯css3打造有点意思的故障艺术(附React/Vue加强组件版)
前言 很早之前就看到国外很多酷炫的网站在实践"故障艺术", 或者错位动画", 感觉非常有意思, 现在APP端的抖音启动界面有着这种设计的影子, 作为一名用于探索未知的前端工程师, 有必要好好实践一下这一设计. 正文 接下来笔者将带大家使用纯Css3来实现"故障动画", 并将这一特效封装成React/vue组件, 供大家学习和使用. 先来看看实现的效果:
25、react入门教程
25、react入门教程 25、react入门教程 0. React介绍 0.1 什么是React? React(有时称为React.js 或ReactJS)是一
CSS Modules 解决 react 项目 css 样式互相影响的问题
CSS Modules 解决 react 项目 css 样式互相影响的问题 CSS Modules 解决 react 项目 css 样式互相影响的问题 (http
Taro 入门教程
简介 Taro 是一个遵循 React 语法规范的开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/
快速了解 React Hooks 原理
为了保证的可读性,本文采用意译而非直译。 我们大部分 React 类组件可以保存状态,而函数组件不能? 并且类组件具有生命周期,而函数组件却不能? React 早期版本,类组件可以通过继承PureComponent来优化一些不必要的渲染,相对于函数组件,React 官网没有提供对应的方法来缓存函数组件以减少一些不必要的渲染,直接 16.6 出来的 Rea
有关CSS预编译、管理工具和网络安全的相关面试题
我经常会听到一些想入行前端的人问,前端开发需要学习哪些技术?其实,除了核心的HTML、CSS、JavaScript技术外,像CSS预编译、前端框架,如Vue,React、Node、Angular;代码管理工具,如git,代码编辑器,sublime text,还有测试,网络安全等相关技术也是需要会一些。当然要求可能不会那么高,但至少要懂一些。所有今天准备了一些
【Flutter实战】状态管理
3.2 状态管理响应式的编程框架中都会有一个永恒的主题——“状态(State)管理”,无论是在React/Vue(两者都是支持响应式编程的Web开发框架)还是Flutter中,他们讨论的问题和解决的思想都是一致的。所以,如果你对React/Vue的状态管理有了解,可以跳过本节。言归正传,我们想一个问题,StatefulWidget的状态应该被谁管理?
React之集成测试 – 测试概览
你可以用像测试其他 JavaScript 代码类似的方式测试 React 组件。现在有许多种测试 React 组件的方法。大体上可以被分为两类: 渲染组件树 在一个简化的测试环境中渲染组件树并对它们的输出做断言检查。 运行完整应用 在一个真实的浏览器环境中运行整个应用(也被称为“端到端(endtoend)”测试)。本章节主要专
React 之Virtual DOM 及内核
什么是 Virtual DOM?Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。这一过程叫做。这种方式赋予了 React 声明式的 API:您告诉 React 希望让 UI 是什么状态,React 就确保 DOM 匹
新手学习 React 迷惑的点
网上各种言论说 React 上手比 Vue 难,可能难就难不能深刻理解 JSX,或者对 ES6 的一些特性理解得不够深刻,导致觉得有些点难以理解,然后说 React 比较难上手,还反人类啥的,所以我打算写两篇文章来讲新手学习 React 的时候容易迷惑的点写出来,如果你还以其他的对于学习 React 很迷惑的点,可以在留言区里给我留言。为什么要引入 Reac