react组件开发

本文分享一个react动画组件开发过程。以一个从底部弹出的弹框为例:
react组件开发_第1张图片
类似于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仿网易云音乐

你可能感兴趣的:(react)