没有 React-Router 的页面转换
page transitions without React-Router
这应该很简单,但我已经为此伤脑筋好几天了。我正在尝试为我的页面转换设置动画。问题是文档很烂。我一遍又一遍地关注他们并尝试了各种方法,但无法让它发挥作用。
我想做的是优雅地向右或向左滑动我的页面,然后淡化正在卸载的页面在它后面。简单吧?我的页面没有使用 React Router。
我已经尝试了多种解决方案,但问题似乎出在卸载上。当页面被替换时,现有页面在它可以转换出之前被卸载。我正在发布我对 react-transition-group 的尝试,但在这一点上,我会接受任何其他有效的解决方案。我不确定 react-transition-group 实际上是否在积极维护,因为还有许多其他帖子需要 0 条回复的帮助。
所以在我的应用程序容器上我想放这样的东西:
<App>
<PageSlider>
<Page key={uniqueId} /> <==this will be "swapped" through (Redux) props
</PageSlider>
因此,根据我的阅读,我必须为此使用 TransitionGroup 容器作为我的 PageSlider,以便它管理我的页面的进入和退出。所以这里是:
class PageSlider extends Component {
constructor(props) {
super(props);
}
render() {
return (
<TransitionGroup
component="div"
id="page-slider"
childFactory={child => React.cloneElement(child,
{classNames: `page-${this.props.fromDir}`, timeout: 500}
)}
>
{this.props.children}
</TransitionGroup>
);
}
}
我还读到我需要做一个 "child Factory" 来启用现有的东西。我在文档中绝对找不到这方面的例子。由于页面将来自不同的方向,我将向此传递我想要滑动页面的方向,这将告诉页面它得到什么class。
现在,至于页面本身,我已将其包装在 CSSTransition 中,就像这样。文档中没有很好的例子说明这一切是如何传递的,所以我真的很困惑在这里做什么:
class Page extends Component {
constructor(props) {
super(props);
}
render() {
return (
<CSSTransition> <==????????
{this.props.children} Do props get passed down?
</CSSTransition> Which ones?
); Does "in" get taken care of?
}
}
并且只是为了完成样式将应用在 CSS 中,如下所示:
.page {
display: flex;
flex-direction: column;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
-webkit-transition: all 500ms ease-in-out;
transition: all 500ms ;
}
//go from this
.page-right-enter {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
//to this
.page-right-enter-active {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
//exiting go from this
.page-right-exit {
opacity: 1;
}
//to this
.page-right-exit-active {
opacity: 0;
}
所有这些组件都将通过 Redux 连接,因此它们知道何时触发了新页面以及调用了哪个方向。
有人可以帮我解决这个问题吗?我真的花了几天时间尝试了那里的每个图书馆。我不喜欢反应过渡组!任何在卸载 上运行的库 我都会尝试。为什么这不容易?
好的。好吧,我为此苦苦挣扎了 WAAAAY 太久了。我终于抛弃了 react-transition-group,变得纯粹 CSS。这是我的解决方案。
PageSlider.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
require('./transitions.scss');
const BlankPage = (props) => <div className="placeholder"></div>;
class PageSlider extends Component {
constructor(props) {
super(props);
this.state = {
nextRoute: props.page,
pages: {
A: {key: 'A', component: BlankPage, className: 'placeholder'},
B: {key: 'B', component: BlankPage, className: 'placeholder'},
},
currentPage: 'A'
};
}
componentDidMount() {
//start initial animation of incoming
let B = {key: 'b', component: this.state.nextRoute, className: 'slideFromRight'}; //new one
let A = Object.assign({}, this.state.pages.A, {className: 'slideOutLeft'}); //exiting
this.setState({pages: {A: A, B: B}, currentPage: 'B'});
}
componentWillReceiveProps(nextProps) {
if (nextProps.page != this.state.nextRoute) {
this.transition(nextProps.page, nextProps.fromDir);
}
}
transition = (Page, fromDir) => {
if (this.state.nextRoute != Page) {
let leavingClass, enteringClass;
let pages = Object.assign({}, this.state.pages);
const current = this.state.currentPage;
const next = (current == 'A' ? 'B' : 'A');
if (fromDir == "right") {
enteringClass = 'slideFromRight';
leavingClass = 'slideOutLeft';
} else {
enteringClass = 'slideFromLeft';
leavingClass = 'slideOutRight';
}
pages[next] = {key: 'unique', component: Page, className: enteringClass};
pages[current].className = leavingClass;
this.setState({pages: pages, nextRoute: Page, currentPage: next});
}
}
render() {
return (
<div id="container" style={{
position: 'relative',
minHeight: '100vh',
overflow: 'hidden'
}}>
{React.createElement('div', {key: 'A', className: this.state.pages.A.className}, <this.state.pages.A.component />)}
{React.createElement('div', {key: 'B', className: this.state.pages.B.className} , <this.state.pages.B.component />)}
</div>
);
}
}
PageSlider.propTypes = {
page: PropTypes.func.isRequired,
fromDir: PropTypes.string.isRequired
};
export default PageSlider;
transition.scss
.placeholder {
position: absolute;
left: 0;
width: 100vw;
height: 100vh;
background: transparent;
-webkit-animation: slideoutleft 0.5s forwards;
-webkit-animation-delay: 10;
animation: slideoutleft 0.5s forwards;
animation-delay: 10;
}
.slideFromLeft {
position: absolute;
left: -100vw;
width: 100vw;
height: 100vh;
-webkit-animation: slidein 0.5s forwards;
-webkit-animation-delay: 10;
animation: slidein 0.5s forwards;
animation-delay: 10;
}
.slideFromRight {
position: absolute;
left: 100vw;
width: 100vw;
height: 100vh;
-webkit-animation: slidein 0.5s forwards;
-webkit-animation-delay: 10;
animation: slidein 0.5s forwards;
animation-delay: 10;;
}
.slideOutLeft {
position: absolute;
left: 0;
width: 100vw;
height: 100vh;
-webkit-animation: slideoutleft 0.5s forwards;
-webkit-animation-delay: 10;
animation: slideoutleft 0.5s forwards;
animation-delay: 10;
}
.slideOutRight {
position: absolute;
left: 0;
width: 100vw;
height: 100vh;
-webkit-animation: slideoutright 0.5s forwards;
-webkit-animation-delay: 10;
animation: slideoutright 0.5s forwards;
animation-delay: 10;
}
@-webkit-keyframes slidein {
100% { left: 0; }
}
@keyframes slidein {
100% { left: 0; }
}
@-webkit-keyframes slideoutleft {
100% { left: -100vw; opacity: 0 }
}
@keyframes slideoutleft {
100% { left: -100vw; opacity: 0}
}
@-webkit-keyframes slideoutright {
100% { left: 100vw; opacity: 0}
}
@keyframes slideoutright {
100% { left: 100vw; opacity: 0}
}
传入下一个组件,这是我的反应页面组件,这样调用:
app.js
<div id="app">
<PageSlider page={this.state.nextRoute} fromDir={this.state.fromDir}/>
</div>
这应该很简单,但我已经为此伤脑筋好几天了。我正在尝试为我的页面转换设置动画。问题是文档很烂。我一遍又一遍地关注他们并尝试了各种方法,但无法让它发挥作用。
我想做的是优雅地向右或向左滑动我的页面,然后淡化正在卸载的页面在它后面。简单吧?我的页面没有使用 React Router。
我已经尝试了多种解决方案,但问题似乎出在卸载上。当页面被替换时,现有页面在它可以转换出之前被卸载。我正在发布我对 react-transition-group 的尝试,但在这一点上,我会接受任何其他有效的解决方案。我不确定 react-transition-group 实际上是否在积极维护,因为还有许多其他帖子需要 0 条回复的帮助。
所以在我的应用程序容器上我想放这样的东西:
<App>
<PageSlider>
<Page key={uniqueId} /> <==this will be "swapped" through (Redux) props
</PageSlider>
因此,根据我的阅读,我必须为此使用 TransitionGroup 容器作为我的 PageSlider,以便它管理我的页面的进入和退出。所以这里是:
class PageSlider extends Component {
constructor(props) {
super(props);
}
render() {
return (
<TransitionGroup
component="div"
id="page-slider"
childFactory={child => React.cloneElement(child,
{classNames: `page-${this.props.fromDir}`, timeout: 500}
)}
>
{this.props.children}
</TransitionGroup>
);
}
}
我还读到我需要做一个 "child Factory" 来启用现有的东西。我在文档中绝对找不到这方面的例子。由于页面将来自不同的方向,我将向此传递我想要滑动页面的方向,这将告诉页面它得到什么class。
现在,至于页面本身,我已将其包装在 CSSTransition 中,就像这样。文档中没有很好的例子说明这一切是如何传递的,所以我真的很困惑在这里做什么:
class Page extends Component {
constructor(props) {
super(props);
}
render() {
return (
<CSSTransition> <==????????
{this.props.children} Do props get passed down?
</CSSTransition> Which ones?
); Does "in" get taken care of?
}
}
并且只是为了完成样式将应用在 CSS 中,如下所示:
.page {
display: flex;
flex-direction: column;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
-webkit-transition: all 500ms ease-in-out;
transition: all 500ms ;
}
//go from this
.page-right-enter {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
//to this
.page-right-enter-active {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
//exiting go from this
.page-right-exit {
opacity: 1;
}
//to this
.page-right-exit-active {
opacity: 0;
}
所有这些组件都将通过 Redux 连接,因此它们知道何时触发了新页面以及调用了哪个方向。
有人可以帮我解决这个问题吗?我真的花了几天时间尝试了那里的每个图书馆。我不喜欢反应过渡组!任何在卸载 上运行的库 我都会尝试。为什么这不容易?
好的。好吧,我为此苦苦挣扎了 WAAAAY 太久了。我终于抛弃了 react-transition-group,变得纯粹 CSS。这是我的解决方案。
PageSlider.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
require('./transitions.scss');
const BlankPage = (props) => <div className="placeholder"></div>;
class PageSlider extends Component {
constructor(props) {
super(props);
this.state = {
nextRoute: props.page,
pages: {
A: {key: 'A', component: BlankPage, className: 'placeholder'},
B: {key: 'B', component: BlankPage, className: 'placeholder'},
},
currentPage: 'A'
};
}
componentDidMount() {
//start initial animation of incoming
let B = {key: 'b', component: this.state.nextRoute, className: 'slideFromRight'}; //new one
let A = Object.assign({}, this.state.pages.A, {className: 'slideOutLeft'}); //exiting
this.setState({pages: {A: A, B: B}, currentPage: 'B'});
}
componentWillReceiveProps(nextProps) {
if (nextProps.page != this.state.nextRoute) {
this.transition(nextProps.page, nextProps.fromDir);
}
}
transition = (Page, fromDir) => {
if (this.state.nextRoute != Page) {
let leavingClass, enteringClass;
let pages = Object.assign({}, this.state.pages);
const current = this.state.currentPage;
const next = (current == 'A' ? 'B' : 'A');
if (fromDir == "right") {
enteringClass = 'slideFromRight';
leavingClass = 'slideOutLeft';
} else {
enteringClass = 'slideFromLeft';
leavingClass = 'slideOutRight';
}
pages[next] = {key: 'unique', component: Page, className: enteringClass};
pages[current].className = leavingClass;
this.setState({pages: pages, nextRoute: Page, currentPage: next});
}
}
render() {
return (
<div id="container" style={{
position: 'relative',
minHeight: '100vh',
overflow: 'hidden'
}}>
{React.createElement('div', {key: 'A', className: this.state.pages.A.className}, <this.state.pages.A.component />)}
{React.createElement('div', {key: 'B', className: this.state.pages.B.className} , <this.state.pages.B.component />)}
</div>
);
}
}
PageSlider.propTypes = {
page: PropTypes.func.isRequired,
fromDir: PropTypes.string.isRequired
};
export default PageSlider;
transition.scss
.placeholder {
position: absolute;
left: 0;
width: 100vw;
height: 100vh;
background: transparent;
-webkit-animation: slideoutleft 0.5s forwards;
-webkit-animation-delay: 10;
animation: slideoutleft 0.5s forwards;
animation-delay: 10;
}
.slideFromLeft {
position: absolute;
left: -100vw;
width: 100vw;
height: 100vh;
-webkit-animation: slidein 0.5s forwards;
-webkit-animation-delay: 10;
animation: slidein 0.5s forwards;
animation-delay: 10;
}
.slideFromRight {
position: absolute;
left: 100vw;
width: 100vw;
height: 100vh;
-webkit-animation: slidein 0.5s forwards;
-webkit-animation-delay: 10;
animation: slidein 0.5s forwards;
animation-delay: 10;;
}
.slideOutLeft {
position: absolute;
left: 0;
width: 100vw;
height: 100vh;
-webkit-animation: slideoutleft 0.5s forwards;
-webkit-animation-delay: 10;
animation: slideoutleft 0.5s forwards;
animation-delay: 10;
}
.slideOutRight {
position: absolute;
left: 0;
width: 100vw;
height: 100vh;
-webkit-animation: slideoutright 0.5s forwards;
-webkit-animation-delay: 10;
animation: slideoutright 0.5s forwards;
animation-delay: 10;
}
@-webkit-keyframes slidein {
100% { left: 0; }
}
@keyframes slidein {
100% { left: 0; }
}
@-webkit-keyframes slideoutleft {
100% { left: -100vw; opacity: 0 }
}
@keyframes slideoutleft {
100% { left: -100vw; opacity: 0}
}
@-webkit-keyframes slideoutright {
100% { left: 100vw; opacity: 0}
}
@keyframes slideoutright {
100% { left: 100vw; opacity: 0}
}
传入下一个组件,这是我的反应页面组件,这样调用:
app.js
<div id="app">
<PageSlider page={this.state.nextRoute} fromDir={this.state.fromDir}/>
</div>