本文分享一个react动画组件开发过程。以一个从底部弹出的弹框为例:
类似于actionSheet一样的从底部弹出的弹框。
1、点击按钮底部弹出弹框
2、同时遮罩背景显示
3、点击遮罩背景时弹框向下弹出去,背景消失。
一、背景遮罩实现
考虑到遮罩在多个地方使用,故封装成组件。结合redux开发,代码如下:
//app.js 在全局app中引入mask组件,全局可用
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Header from './components/Header'
import Footer from './containers/Footer'
import Find from './components/Find'
import Slidebar from './components/Slidebar'
import PlayList from './containers/PlayList'
import Mask from './containers/Mask'
class App extends Component {
render() {
return (
'header-div'>
this.props.location.pathname} />
);
}
}
export default App;
//containers目录下的mask组件容器。负责与redux建立连接
import { connect } from 'react-redux'
import Mask from '../components/Mask'
//将state映射成组件的props
const mapStateToProps = (state, ownProps) => ({
isShowPop:state.showPopReducer.isShowPop
})
export default connect(mapStateToProps)(Mask)
components下的mask 负责ui显示
import React, {Component} from 'react'
import {showPop} from '../actions/popAction'
export default class Mask extends Component {
statusName = 'fade-enter'
render() {
return (
<div
ref='maskDiv'
className = {this.props.isShowPop?'':''}
onClick={e=> this.clickHandle(e)}>div>
)
}
componentDidMount() {
this.refs.maskDiv.className = 'mask fade-enter';
}
componentWillUpdate(nextProps, nextState) {
if(nextProps.isShowPop){
this.refs.maskDiv.className = 'mask fade-enter-active'
}else{
this.refs.maskDiv.className = 'mask fade-leave-active'
}
setTimeout(()=>{
if(nextProps.isShowPop){
//this.refs.maskDiv.className = 'mask fade-enter';
}else{
this.refs.maskDiv.className = 'mask fade-leave';
}
},600)
}
clickHandle(e) {
const {dispatch} = this.props;
//分发action ,表示离场
dispatch(showPop(false))
}
}
//遮罩样式
.mask{
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
content: '';
background: rgba(0,0,0,.5);
z-index:10001;
}
//遮罩进场离场过度动画
.fade-enter-active {
z-index: 10001!important;
opacity: 1;
transition: opacity 600ms ease-in;
}
.fade-enter ,.fade-leave {
z-index: -1!important;
opacity: 0;
}
.fade-leave-active {
z-index: 10001!important;
opacity: 0;
transition: opacity 600ms ease-in;
}
//popAction.js
import * as actionTypes from '../constants/constant'
export function showPlayListAction(isShow){
return{
type:actionTypes.SHOW_PLAYLIST_POP,
isShow
}
}
function startAnimate(startAnimate){
return{
type:actionTypes.SHOW_POP,
startAnimate
}
}
export function showPop(showPop){
//使用这种分发方式参考异步数据流action分发 ,需要引用中间件redux-thunk,可参考官网例子
return (dispatch,getState) =>{
if(showPop){
dispatch(showPlayListAction(showPop))
dispatch(startAnimate(showPop));
}else{
dispatch(startAnimate(showPop));
dispatch(showPlayListAction(showPop));
// setTimeout(() => {
// dispatch(showPlayListAction(showPop))
// }, 600);
}
}
}
弹框组件开发
//animation.js 动画包裹组件
import React, { Component } from 'react'
export default class Animation extends Component {
render(slot,isShow,name) {
return (
<div className={isShow?'animation '+name+'-enter-active':'animation '+name+'-leave-active'}>
{slot}
div>
)
}
componentWillUpdate(nextProps, nextState) {
console.log(nextProps, nextState)
}
}
//要执行动画的子组件。
import React, {Component} from 'react'
import {fetchMusicData} from '../actions/musicDataAction'
import {showPop} from '../actions/popAction'
import Animation from './Animation'
import {selectSong} from '../actions/playMusicAction'
export default class PlayList extends Animation {
constructor(props) {
super(props)
this.state = {
isShow: false
}
}
render() {
//return (
return super.render(
<div className='play-list-wraper' onClick={e => this.clickHandle(e)}>
<div
className={this.props.isShowPop
? 'play-list '
: 'play-list '}>
<div className='header-bar'>
<div className='play-type'>
'icon icon-music-random'/>
{'列表循环'}({33})
div>
<div className='op-div'>
div>
div>
<div className='play-content'>
{this
.props
.tracks
.map((item, index) => <div key={index} onClick={e=> this.playSong(e,item.hash)} className='music-item'>
<div className='music-name'>
div>
<div className='music-name'>div>
div>)}
div>
div>
div>, this.props.isShowPop, 'slide')
}
clickHandle(e) {
if (e.target.className.indexOf('play-list-wraper') !== -1) {
const {dispatch} = this.props;
dispatch(showPop(false))
}
}
playSong(e,index){
const {dispatch} = this.props;
dispatch(selectSong(index));
}
componentWillMount() {
const {dispatch} = this.props;
dispatch(fetchMusicData());
}
}
//动画css
.animation{
position: fixed;
z-index: 10002;
width: 100%;
bottom: 0;
transform: translate3d(0,100%,0)
}
.slide-enter-active{
transition: transform 0.6s;
transform:translate3d(0,0,0)!important;
}
.slide-leave-active{
transition: transform 0.6s;
transform:translate3d(0,100%,0)!important;
}
上述只是部分代码,还有结合redux的使用的代码没贴出,完整代码请查看react仿网易云音乐