如何使用反应过渡组为中级菜单创建幻灯片动画?

时间:2020-05-15 03:04:56

标签: javascript css reactjs react-transition-group

需要进行以下操作:enter image description here

我所拥有的是:enter image description here

this amazing tutorial的帮助下,我通过稍微修改了代码创建了一个dropUP菜单。我的问题是,本教程中只有两个级别。

当只有两个级别时,例如A-> B,B和A只有一个输入和一个退出动画,因此可以轻松地使用其过渡类进行动画处理。

如果我想拥有5个级别,该怎么办?如果这些级别是这样的:A-> B-> C-> D-> E,我将不得不以4种方式对菜单C进行动画处理。

  1. 从B到C到D:C从右进入而向左退出
  2. 从B到C到B:C从右边进入,然后从右边退出
  3. 从D到C到B:C从左侧进入并向右退出
  4. 从D到C到D:C从左进入并向左退出

谢谢,我需要知道如何实现。

这是我的代码:

app.js

import './index.css';
import { ReactComponent as CaretIcon } from './icons/caret.svg';
import { ReactComponent as ChevronIcon } from './icons/chevron.svg';
import { ReactComponent as ArrowIcon } from './icons/arrow.svg';

import React, { useState, useEffect, useRef } from 'react';
import { CSSTransition } from 'react-transition-group';

function App() {
  return (
      <NavItem icon={<CaretIcon />}>
        <DropdownMenu></DropdownMenu>
      </NavItem>
  );
}

function NavItem(props) {
  const [open, setOpen] = useState(false);

  return (
    <div className="nav-item">
      <a href="#" className="icon-button" onClick={() => setOpen(!open)}>
        {props.icon}
      </a>

      {open && props.children}
    </div>
  );
}

function DropdownMenu() {
  const [activeMenu, setActiveMenu] = useState('main');
  const [menuHeight, setMenuHeight] = useState(null);
  const dropdownRef = useRef(null);

  useEffect(() => {
    setMenuHeight(dropdownRef.current?.firstChild.offsetHeight)
  }, [])

  function calcHeight(el) {
    const height = el.offsetHeight;
    setMenuHeight(height);
  }

  function DropdownItem(props) {
    return (
      <a href="#" className="menu-item" onClick={() => props.goToMenu && setActiveMenu(props.goToMenu)}>
        {props.leftIcon && <span className="icon-button">{props.leftIcon}</span>}
        {props.children}
        <span className="icon-right">{props.rightIcon}</span>
      </a>
    );
  }

  return (
    <div className="dropdown" style={{ height: menuHeight }} ref={dropdownRef}>

      <CSSTransition
        in={activeMenu === 'main'}
        timeout={500}
        classNames="menu-primary"
        unmountOnExit
        onEnter={calcHeight}>
        <div className="menu">
          <DropdownItem
            rightIcon={<ChevronIcon />}
            goToMenu="PLAYBACK SPEED">
            PLAYBACK SPEED
          </DropdownItem>
          <DropdownItem
            rightIcon={<ChevronIcon />}
            goToMenu="CLOSED CAPTIONS">
            CLOSED CAPTIONS
          </DropdownItem>

        </div>
      </CSSTransition>

      <CSSTransition
        in={activeMenu === 'PLAYBACK SPEED'}
        timeout={500}
        classNames="menu-secondary"
        unmountOnExit
        onEnter={calcHeight}>
        <div className="menu">
          <DropdownItem goToMenu="main" leftIcon={<ArrowIcon />}>
            <h4>PLAYBACK SPEED</h4>
          </DropdownItem>
          <DropdownItem >0.75x</DropdownItem>
          <DropdownItem >1x (Default)</DropdownItem>
          <DropdownItem >1.5x</DropdownItem>
          <DropdownItem >2x</DropdownItem>
        </div>
      </CSSTransition>

      <CSSTransition
        in={activeMenu === 'CLOSED CAPTIONS'}
        timeout={500}
        classNames="menu-secondary"
        unmountOnExit
        onEnter={calcHeight}>
        <div className="menu">
          <DropdownItem goToMenu="main" leftIcon={<ArrowIcon />}>
            <h4>CC SETTINGS</h4>
          </DropdownItem>
          <DropdownItem 
              rightIcon={<ChevronIcon />}
              goToMenu="FONT COLOR">
              FONT COLOR</DropdownItem>
          <DropdownItem rightIcon={<ChevronIcon />}>FONT SIIZE</DropdownItem>
          <DropdownItem rightIcon={<ChevronIcon />}>FONT STYLE</DropdownItem>
          <DropdownItem rightIcon={<ChevronIcon />}>BACKGROUND COLOR</DropdownItem>
          <DropdownItem rightIcon={<ChevronIcon />}>BACKGROUND OPACITY</DropdownItem>
        </div>
      </CSSTransition>

      <CSSTransition
        in={activeMenu === 'FONT COLOR'}
        timeout={500}
        classNames="menu-secondary"
        unmountOnExit
        onEnter={calcHeight}>
        <div className="menu">
          <DropdownItem goToMenu="CLOSED CAPTIONS" leftIcon={<ArrowIcon />}>
            <h4>FONT COLORS</h4>
          </DropdownItem>
          <DropdownItem >RED</DropdownItem>
          <DropdownItem >BLUE</DropdownItem>
          <DropdownItem >GREEN</DropdownItem>
          <DropdownItem >YELLOW</DropdownItem>
          <DropdownItem >BLACK</DropdownItem>
          <DropdownItem >WHITE (Default)</DropdownItem>
        </div>
      </CSSTransition>

    </div>
  );
}

export default App;

index.css

body {
  margin: 0;
  background: #151616;
  font-family: roboto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

:root {
  --bg:  #rgba(0, 0, 0, 0.85);
  --bg-accent: #484a4d;
  --text-color: #dadce1;
  --nav-size: 60px;
  --border: 0px solid #474a4d;
  --border-radius: 2px;
  --speed: 500ms; 
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

a {
  color: var(--text-color);
  text-decoration: none;;
}

/* Top Navigation Bar */

/* <ul> */
.navbar-nav {
  max-width: 100%;
  height: 100%;
  display: flex;
  justify-content: flex-end;
}

#root{
  display: flex;
  align-items: center;
  justify-content: center;
}

/* <li> */
.nav-item {
  width: calc(var(--nav-size) * 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Icon Button */
.icon-button {
  --button-size: calc(var(--nav-size) * 0.5);
  width: var(--button-size);
  height: var(--button-size);
  background-color: #484a4d;
  border-radius: 50%;
  padding: 5px;
  margin: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: filter 300ms;
}

.icon-button:hover {
  filter: brightness(1.2);
}

.icon-button svg { 
  fill: var(--text-color);
  width: 20px;
  height: 20px;
}


/* Dropdown Menu */

.dropdown {
  position: absolute;
  bottom: 50%;
  width: 300px;
  transform: translateX(-45%);
  background-color: var(--bg);
  border: var(--border);
  border-radius: var(--border-radius);
  overflow: hidden;
  transition: height var(--speed) ease;
  outline: white solid 1px;
}

.menu {
  width: 100%;
  bottom: 0;
  position: absolute;
}

.menu-item {
  height: 40px;
  display: flex;
  align-items: center;
  border-radius: var(--border-radius);
  transition: background var(--speed);
  padding: 0.5rem;
}

.menu-item .icon-button {
  margin-right: 0.5rem;
}


.menu-item .icon-button:hover {
  filter: none;
}

.menu-item:hover {
  background-color: rgba(255, 255, 255, 0.1);
}

.icon-right {
  margin-left: auto;
}

/* CSSTransition classes  */
.menu-primary-enter {
  position: absolute;
  transform: translateX(-110%);
}
.menu-primary-enter-active {
  transform: translateX(0%);
  transition: all var(--speed) ease;
}
.menu-primary-exit {
  position: absolute;
}
.menu-primary-exit-active {
  transform: translateX(-110%);
  transition: all var(--speed) ease;
}


.menu-secondary-enter {
  transform: translateX(110%);
}
.menu-secondary-enter-active {
  transform: translateX(0%);
  transition: all var(--speed) ease;
}
.menu-secondary-exit {

}
.menu-secondary-exit-active {
  transform: translateX(110%);
  transition: all var(--speed) ease;
}

0 个答案:

没有答案