1.0.0 • Published 2 years ago

@vises/transition v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

解决的问题

1.动画未完成页面数字滚动,图表开始渲染 2.统一管理页面进场,出场. 3.出场动画时间不一样

TransitionWrap

TransitionPage的容器. TransitionWrap会获取子孙TransitionPage组件,value值等于TransitionPage的keys时渲染页面

属性说明类型默认
value渲染哪一个transitionPage页面string-
inEndFn整个页面进场动画结束回调Function-
outEndFn整个页面出场动画结束回调Function-

TransitionPage

页面容器

属性说明类型默认
page页面domdom-
keys页面标识string-

Transition

在show改变时会给Transition添加不同的类名

属性说明类型默认
name类名前缀stringdefault
className类名class-
style样式css-
inEndFn进场动画结束回调函数Function-
outEndFn出场动画结束回调函数Function-

过渡的类名

1.name-in: 在元素被插入之时生效,在元素被插入之后的下一帧移除。 2.name-in-active: 在元素被插入时生效 3.name-out-to: 在show改为false生效 4.name-out-active: 在show改为false生效

示例

项目入口文件 page/index.tsx

import { useState } from 'react';
import { TransitionWrap, TransitionPage } from '@/components/transition'; // 引入组件容器
import PageA from './PageA';
import PageB from './PageB';

const IndexPage = () => {
  const [pageName, setPageName] = useState('PageA'); // 当前页面

  // 出场动画结束回调
  let handlePage = () => {
    console.log('出场动画结束回调')
  };
  
  // 接收到中控发来消息
  const API_PageChange = (data: any) => {
    setPageName(data.page)
  }

  return (
    <TransitionWrap value={pageName} outEndFn={handlePage}>
      <button onClick={() => API_PageChange({ page: 'PageA' })}>切换到: PageA</button>
      <button onClick={() => API_PageChange({ page: 'PageB' })}>切换到: PageB</button>
      <TransitionPage keys="PageA" page={<PageA />} />
      <TransitionPage keys="PageB" page={<PageB />} />
    </TransitionWrap>
  );
}

export default IndexPage;

pageA页面中

import styles from './index.less';
import { Transition, TransitionWrap, TransitionPage } from '@/components/transition'; // 引入过渡组件
import CountUp from '@/components/CountUp';
import { useState } from 'react';


const pageA = () => {
  const [pageName, setPageName] = useState('right1'); // 当前页面

  // 接收到中控发来消息
  const API_PageChange = (data: any) => {
    setPageName(data.page)
  }

  return <div>
      <button onClick={() => API_PageChange({ page: 'right1' })}>切换到: right1</button>
      <button onClick={() => API_PageChange({ page: 'right2' })}>切换到: right2</button>
      

    
      <div className={styles.page}>

      <Transition name="left" className={styles.left} inEndFn={() => {console.log('进场动画结束')}}>
        name 为 left
        

        <CountUp end={100} />
      </Transition>

      <Transition name="center">
        <h1>PageA</h1>
        <h1>name 为 center</h1>
      </Transition>

      <TransitionWrap value={pageName}>
        <TransitionPage keys="right1" page={
          <Transition name="right" className={styles.right}>
            name 为 right1
            

            page 为 1
            

            <CountUp end={100} />
          </Transition>
        } />
        <TransitionPage keys="right2" page={
          <Transition name="right" className={styles.right}>
            name 为 right
            

            page 为 2
            

            <CountUp end={200} />
          </Transition>
        } />
      </TransitionWrap>
    </div>
  </div>
}

export default pageA;

// ---------------------styles---------------------
.page {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 40px;
  box-sizing: border-box;
  .left {
    box-sizing: border-box;
    width: 200px;
    height: 400px;
    background-color: #f00;
  }
  .right {
    box-sizing: border-box;
    width: 200px;
    height: 400px;
    background-color: #f0f;
  }
}

pageB页面中

import styles from './index.less';
import { Transition } from '@/components/transition'; // 引入过渡组件
import CountUp from '@/components/CountUp';


const pageB = () => {
  return <div className={styles.page}>
    <Transition name="left2" className={styles.left} inEndFn={() => {console.log('进场动画结束')}}>
      name 为 left2
      

      <CountUp end={100} />
    </Transition>

    <Transition name="center2">
      <h1>PageB</h1>
      <h1>name 为 center2</h1>
    </Transition>
    
    <Transition name="right2" className={styles.right}>
      name 为 right2
    </Transition>
  </div>
}

export default pageB;

// ---------------------styles---------------------
  .page {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 40px;
    box-sizing: border-box;
    .left {
      box-sizing: border-box;
      width: 200px;
      height: 400px;
      background-color: #f00;
    }
    .right {
      box-sizing: border-box;
      width: 200px;
      height: 400px;
      background-color: #f0f;
    }
  }

此时的Transition的css为:

.left-in, .left-out-to {
  transform: translateX(-150%);
}

.left-in-active, .left-out-active {
  transition: transform 1.8s;
}

.right-in, .right-out-to {
  transform: translateX(150%);
}

.right-in-active, .right-out-active {
  transition: transform .8s;
}

.center-in-active {
  animation: centerIn .8s linear;
}

.center-out-active {
  animation: centerOut .8s linear forwards;
}

@keyframes centerIn {
  0% { transform: scale(0) }
  100% { transform: scale(1); }
}

@keyframes centerOut {
  0% { transform: scale(1) }
  100% { transform: scale(0); }
}

.left2-in-active {
  animation: left2In .8s linear;
}

@keyframes left2In {
  0% { 
    transform: translateX(-150%);
    height: 20px;
    overflow: hidden;
  }
  40% { 
    transform: translateX(0%);
    height: 20px;
    overflow: hidden;
  }
  100% { 
    transform: translateX(0%);
    height: 400px;
    overflow: hidden;
  }
}

.left2-out-active {
  animation: left2Out .8s linear;
}

@keyframes left2Out {
  0% { 
    transform: translateX(0%);
    height: 400px;
    overflow: hidden;
  }
  40% { 
    transform: translateX(0%);
    height: 20px;
    overflow: hidden;
  }
  100% { 
    transform: translateX(-150%);
    height: 20px;
    overflow: hidden;
  }
}


.center2-in, .center2-out-to {
  transform: translateY(-250%);
}

.center2-in-active, .center2-out-active {
  transition: transform .8s;
}

.right2-in-active {
  animation: right2In .8s linear;
}

@keyframes right2In {
  0% { 
    opacity: 0;
    border-radius: 100%;
    width: 0;
    height: 0;
    overflow: hidden;
  }
  100% { 
    opacity: 1;
    border-radius: 0%;
    overflow: hidden;
  }
}

.right2-out-active {
  animation: right2Out .8s linear;
}

@keyframes right2Out {
  0% { 
    border-radius: 0%;
    overflow: hidden;
  }
  100% { 
    width: 0;
    height: 0;
    opacity: 0;
    border-radius: 100%;
    overflow: hidden;
  }
}

.left-in, .left-out-to {
  transform: translateX(-110%);
}

.left-in-active, .left-out-active {
  transition: transform .8s;
}

.right-in, .right-out-to {
  transform: translateX(110%);
}

.right-in-active, .right-out-active {
  transition: transform .8s;
}

Transition下的组件获取页面进场结束 如 CountUp 组件

import ReactCountUp from 'react-countup';
import { CountUpProps } from 'react-countup/build/CountUp';
import { useTransitionEnd } from '@/components/transition'; // 页面进场结束use
import { useState } from 'react';
const CountUp: React.FC<CountUpProps> = (props) => {
    const [flag, setFlag] = useState(false);
    useTransitionEnd(() => { setFlag(true); console.log('进场动画结束') });
  return <ReactCountUp  duration={2.75} {...props} end={!flag ? 0 : props.end}></ReactCountUp>;
};

export default CountUp;

demo下载

demo.zip