React 折騰記 - (2) 實現路由動效過渡,並解決過程中奇奇怪怪的問題

CRPER發表於2018-08-10

前言

寫這個只是更好的梳理下我實現過程中遇到的奇奇怪怪的問題..

因為著實浪費了我不少時間..肯定有不少也碰到過其中的問題

希望對小夥伴有所幫助


效果圖

  • 我命名為spread的效果,其實就是結合放大和旋轉以及透明度的特性

React 折騰記 - (2) 實現路由動效過渡,並解決過程中奇奇怪怪的問題

  • 漸隱漸現fade

React 折騰記 - (2) 實現路由動效過渡,並解決過程中奇奇怪怪的問題


基礎依賴

  • styled-components@3.4.2 : 寫樣式的
  • react-transition-group@2.4.0 : 路由過渡的,react官方的
  • react-router-dom@4.3.1 : react自家路由
  • react@16.4.2

問題有三,亦能解決

  • 元件堆疊問題..就是再次進入路由切換的時候,之前的元素還沒有消失,而新的元件渲染了,同時出現

    • 堆疊問題,只能用脫離文件流來解決,所以用position:absolute來負責渲染區域即可
    • 注意父層需要position:relative, 不然會一直往上找相對位置,實在找不到會相對視窗
  • 點選側邊欄,元件一直重複渲染的問題

    • 一開始想的是去子元件區域,用shouldComponentUpdate來判斷URL然後阻止渲染,發現不可行
    • 因為過渡外部用的location.key是隨機性的,所以元件每次都會重新渲染
    • 最終的解決方案,是改掉了側邊欄的Link元件,直接用事件繫結(history.push來跳轉),完美
  • 隨機切換效果

    • 這個結合CSSTransition的特性,因為location.key是隨機性的,不同值都會走一遍;
    • 那樣式的繫結給個隨機數就好了.隨機的範圍根據你新增的個數進行調整

注意: 這裡的樣式用的style-components來寫的,感興趣的可以自行了解下


程式碼

重複渲染的解決邏輯程式碼


    // 路由跳轉
    gotoUrl = itemurl => {
        // 拿到路由相關的資訊
        const { history, location } = this.props;
        // 判斷我們傳入的靜態路由表的路徑是否和路由資訊匹配
        // 不匹配則允許跳轉,反之打斷函式
        if (location.pathname === itemurl) {
            return;
        } else {
            history.push(itemurl);
        }
    };

複製程式碼

元件堆疊及過渡實現(包括隨機)


import React, { Component } from 'react';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { Route, Redirect, withRouter, Switch } from 'react-router-dom';
import styled from 'styled-components';
import { observer, inject } from 'mobx-react';
import asyncComponent from 'components/asyncComponent/asyncComponent';

const RouterAnimationClass = styled.div`
    .fade-appear,
    .fade-enter {
        opacity: 0;
    }

    .fade-appear-active,
    .fade-enter-active {
        transition: opacity 0.3s linear;
        opacity: 1;
    }

    .fade-exit {
        transition: opacity 0.2s linear;
        opacity: 1;
    }

    .fade-exit-active {
        opacity: 0;
    }

    .spread-appear,
    .spread-enter {
        opacity: 0.5;
        transform: scale(0) rotate(30deg);
    }

    .spread-appear-active,
    .spread-enter-active {
        opacity: 1;
        transform: scale(1) rotate(0);
        transition: transform 0.3s ease-in-out;
    }

    .spread-exit {
        transition: transform 0.2s ease-in-out;
        transform: scale(1.2) rotate(-30deg);
    }

    .spread-exit-active {
        transform: scale(0) rotate(0);
    }

    .page-content {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        right: 0;
        width: 100%;
    }
`;

const Monitor = asyncComponent(() => import('pages/DashBoard/Monitor'));
const Analyze = asyncComponent(() => import('pages/DashBoard/Analyze'));

import ErrorPage from 'pages/Error/Error'; // 報錯頁面
@inject('auth')
@withRouter
@observer
class Container extends Component {
    constructor(props) {
        super(props);
    }
    render() {
        const { location } = this.props;
        return (
            <RouterAnimationClass>
                <TransitionGroup>
                    <CSSTransition
                        key={location.key}
                        classNames={
                            ['fade', 'spread'][parseInt(Math.random() * 2, 10)]
                        }
                        timeout={1000}>
                        <div className="page-content">
                            <Switch location={location}>
                                <Route
                                    path="/dashboard/monitor"
                                    exact
                                    component={Monitor}
                                />
                                <Route
                                    path="/dashboard/analyze"
                                    exact
                                    component={Analyze}
                                />
                                <Redirect
                                    exact
                                    from="/"
                                    to="/dashboard/monitor"
                                />
                                <Route component={ErrorPage} />
                            </Switch>
                        </div>
                    </CSSTransition>
                </TransitionGroup>
            </RouterAnimationClass>
        );
    }
}

export default Container;


複製程式碼

僅供參考,部分你們沒用到的可以移除掉


總結

很多坑你在其中的時候,谷歌,官方文件,github issue都翻遍了也沒鳥用;

還有一些QQ群的群友給我一些不意思的思路,終於給摸索出來了;

發現寫法也就那樣..但是那消磨在裡面的,是我的青春~~~ 生命不息,折騰不止!

有不對之處請留言,會及時修正,謝謝閱讀

相關文章