ReactJS переходы страниц - PullRequest
       11

ReactJS переходы страниц

0 голосов
/ 04 октября 2019

Я новичок в ReactJS, так что это может быть простым и простым делом, но я хотел сделать переходы страниц такими, как они есть в нативном приложении. Например, в Chrome (по крайней мере, для Android), если вы проведете пальцем по панели навигации, вы можете переключаться между страницами, именно такой переход мне нужен.

Это компонент, которыйотобразит страницы и анимации между ними:

import React from 'react';
import { Back, Answer } from './elements';
import './mobileApp.css';
import './animations.css'
import Swipe from 'react-easy-swipe';
import { Route, Link, Switch, withRouter } from 'react-router-dom';
import { CSSTransition, TransitionGroup } from 'react-transition-group';

const botNavStyle = {
    width: window.innerWidth/3,
    margin: 0
}

const webStyle = {
    fontSize: '1.2em',
    margin: 0,
    position: 'fixed',
    zIndex: 69
}

class MobileAppAnswer extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            num: 0,
            lastNum: (this.props.answers).length
        }
        this.backClick = this.backClick.bind(this);
        this.nextClick = this.nextClick.bind(this);
        this.swipeNext = this.swipeNext.bind(this);
        this.swipeBack = this.swipeBack.bind(this);
    }

    backClick(){
        this.setState({num: this.state.num - 1, swipe: 'Right'});
        document.scrollingElement.scrollTo(0,0)
    }

    nextClick(){
        this.setState({num: this.state.num + 1, swipe: 'Left'});
        document.scrollingElement.scrollTo(0, 0);
    }

    swipeNext(){
        if (this.state.num < this.state.lastNum - 1){
            this.nextClick();
            this.props.history.push(`/answer${this.state.num + 1}`)
        }
    }

    swipeBack(){
        if (this.state.num > 0){
            this.backClick();
            this.props.history.push(`/answer${this.state.num - 1}`)
        }
    }

    componentDidMount(){
        let websitePosition = document.getElementById('websitePosition').getBoundingClientRect();
        this.pos = {top: websitePosition.top, left: websitePosition.left};
    }

    render(){
        const back = this.state.num > 0;
        const next = this.state.num < this.state.lastNum - 1;
        return (
            <div style={{minHeight: window.innerHeight}}>
                <header className="top" style={{height: Math.round(window.innerHeight/11)}}>
                    <Back handleClick={this.props.backClick} />
                    <p style={{fontSize: '1.2em', margin: 0, visibility: 'hidden'}} id="websitePosition">{this.props.websites[0]}</p>
                </header>
                <Route render={({location}) => (
                    <TransitionGroup>
                        <CSSTransition
                            timeout={1000}
                            classNames="fade"
                            key={location.key}
                        >
                            <Switch location={location}>
                                <Route path="/answer0" render={() => (
                                    <p style={{...webStyle, ...this.pos}}>{this.props.websites[0]}</p>
                                )} />

                                <Route path="/answer1" render={() => (
                                    <p style={{...webStyle, ...this.pos}}>{this.props.websites[1]}</p>
                                )} />

                                <Route path="/answer2" render={() => (
                                    <p style={{...webStyle, ...this.pos}}>{this.props.websites[2]}</p>
                                )} />

                                <Route path="/answer3" render={() => (
                                    <p style={{...webStyle, ...this.pos}}>{this.props.websites[3]}</p>
                                )} />

                                <Route path="/answer4" render={() => (
                                    <p style={{...webStyle, ...this.pos}}>{this.props.websites[4]}</p>
                                )} />

                                <Route path="/" render={() => (
                                    <p style={{...webStyle, ...this.pos}}>{this.props.websites[0]}</p>
                                )} />
                            </Switch>
                        </CSSTransition>
                    </TransitionGroup>
                )} />
                <Swipe
                    onSwipeLeft={this.swipeNext}
                    onSwipeRight={this.swipeBack}
                    tolerance={100}
                >
                    <Route render={({location}) => (
                        <TransitionGroup>
                            <CSSTransition
                                timeout={1000}
                                classNames={"crunch"}
                                key={location.key}
                            >
                                <Switch location={location}>
                                    <Route path={'/answer0'} render={() => (
                                        <Answer question={this.props.question} answer={this.props.answers[0]} />
                                    )} />

                                    <Route path={'/answer1'} render={() => (
                                        <Answer question={this.props.question} answer={this.props.answers[1]} />
                                    )} />

                                    <Route path={'/answer2'} render={() => (
                                        <Answer question={this.props.question} answer={this.props.answers[2]} />
                                    )} />

                                    <Route path={'/answer3'} render={() => (
                                        <Answer question={this.props.question} answer={this.props.answers[3]} />
                                    )} />

                                    <Route path={'/answer4'} render={() => (
                                        <Answer question={this.props.question} answer={this.props.answers[4]} />
                                    )} />

                                    <Route path={'/'} render={() => (
                                        <Answer question={this.props.question} answer={this.props.answers[0]} />
                                    )} />
                                </Switch>
                            </CSSTransition>
                        </TransitionGroup>
                    )} />
                </Swipe>
                <div className="bot">
                    {back ?
                    <Link to={`answer${this.state.num-1}`}>
                        <p className="botItem button" style={{...botNavStyle, opacity: 1}} onClick={this.backClick}>{'< Back'}</p>
                    </Link>:
                    <p className="botItem button" style={{...botNavStyle, opacity: 0.5}}>{'< Back'}</p>}

                    <p className="botItem" style={botNavStyle}>Answer {this.state.num + 1}</p>

                    {next ?
                    <Link to={`answer${this.state.num+1}`}>
                        <p className="botItem button" style={{...botNavStyle, opacity: 1}} onClick={this.nextClick}>{'Next >'}</p>
                    </Link> :
                    <p className="botItem button" style={{...botNavStyle, opacity: 0.5}}>{'Next >'}</p>}
                </div>
            </div>
        )
    }
}

export default withRouter(MobileAppAnswer);

Второй Switch, который визуализирует компоненты Answer, имеет базовую анимацию, которая просто меняет высоту с 0 до 100% или наоборот. Код для компонента Answer:

export function Answer(props){
    return (
        <div style={container}>
            <div className="info" style={infoStyle} id="question">
                <p style={{margin: 0}}>{props.question}</p>
            </div>
            <div className="info" style={infoStyle}>
                <p className="notCenter">{props.answer}</p>
            </div>
        </div>
    )
}

container и infoStyle являются просто объектами, которые задают некоторый стиль.

animations.css содержит только анимацию, необходимую длязаставить CSSTransition работать:

.fade-enter, .fade-appear {
    opacity: 0;
}

.fade-enter-active {
    opacity: 1;
    transition: opacity 600ms linear 400ms;
}

.fade-exit {
    opacity: 1;
}

.fade-exit-active {
    opacity: 0;
    transition: opacity 400ms linear;
}


.crunch-enter, .crunch-appear {
    height: 0%;
}

.crunch-enter-active {
    height: 100%;
    transition: all 600ms ease-out 400ms;
}

.crunch-exit {
    height: 100%;
}

.crunch-exit-active {
    height: 0%;
    transition: all 400ms ease-in
}

Вот полный код и

Это github.io wesbite (youllнужно открыть сайт на телефоне, если вы хотите его увидеть)

...