我如何使用 preact 创建页面转换
how can i create a page transition with preact
我正在尝试使用 preact-router
进行页面转换,我已经尝试使用 preact-transition-group
包和 preact-css-transition-group
包,这给了我一个错误,无论如何这是我的基本设置:
import { h, FunctionComponent } from 'preact';
import Router from 'preact-router';
const App: FunctionComponent = () => {
return (
<Router>
<div path="/1" style="padding: 50px">
page 1 <a href="/2">page 2</a>
</div>
<div path="/2" style="padding: 50px">
page 2 <a href="/1">page 1</a>
</div>
</Router>
);
};
打字稿 and/or preact-router
解决方案是可取的,但不是必需的。
创建动画的最佳方法是引入另一个 HOC - 包装您的页面并将其用作路由器目标的高阶组件。它会是这样的:
import { h, FunctionComponent } from 'preact';
import Router from 'preact-router';
const App: FunctionComponent = () => {
return (
<Router>
<PageAnimation path="/1">
<div style="padding: 50px">
page 1 <a href="/2">page 2</a>
</div>
</PageAnimation>
<PageAnimation path="/2">
<div style="padding: 50px">
page 2 <a href="/1">page 1</a>
</div>
</PageAnimation>
</Router>
);
};
您的实现代码类似于 -
如何制作转场动画.
Note: that this approach probably dosn't work with nested routes.
使用这种方法,您需要用 class 将每条路由包装在 div 中,这将使路由具有动画效果,并将键和路径属性设置为路由的路径,如下所示:
function wrapRoute(route: h.JSX.Element): h.JSX.Element {
return ( // the in class is the animation and the page class is makes sure that the old and new routes overlap
<div path={route.props.path} class="in page" key={route.props.path}>
{route}
</div>
);
}
然后你需要像这样添加两个反应变量:
const [previousEl, setPreviousEl] = useState<ComponentChildren | null>(null);
const [outEl, setOutEl] = useState<JSX.Element | null>(null);
之后你可以监听 preact-router
的 onChange
事件并将 outEl
设置为 div 包装 previousEl
并且有一个class 将动画化路由的出口,然后添加一个 onAnimationEnd
侦听器,以便您可以将 outEl
设置为 null
出口动画已经完成,最后一件事需要将 previousEl
设置为 e.current.props.children
,您的路由器组件侦听器应如下所示:
<Router onChange={(e) => {
if (previousEl) {
setOutEl(
<div class="out page" key={e.previous} onAnimationEnd={() => setOutEl(null)}>
{previousEl}
</div>
);
}
if (e.current) {
setPreviousEl(e.current.props.children);
}
}}
>
{routes} // this is an array containing all the wrapped routes.
</Router>
您需要做的最后一件事是创建动画,请查看下面的 app.sass
示例。
这里是完整的例子:
app.tsx
import { h, FunctionComponent, JSX, ComponentChildren, Fragment } from 'preact';
import Router from 'preact-router';
import { useState } from 'preact/hooks';
import './app.sass'
const routes = [
<div style="padding: 50px; background: red" path="/1">
page 1 <a href="/2">page 2</a> <a href="/3">page 3</a>
</div>,
<div style="padding: 50px; background: blue" path="/2">
page 2 <a href="/1">page 1</a> <a href="/3">page 3</a>
</div>,
<div style="padding: 50px; background: green" path="/3">
page 2 <a href="/1">page 1</a> <a href="/2">page 2</a>
</div>,
].map((route) => wrapRoute(route));
function wrapRoute(route: h.JSX.Element): h.JSX.Element {
return (
<div path={route.props.path} class="in page" key={route.props.path}>
{route}
</div>
);
}
const App: FunctionComponent = () => {
const [previousEl, setPreviousEl] = useState<ComponentChildren | null>(null);
const [outEl, setOutEl] = useState<JSX.Element | null>(null);
return (
<Fragment>
<Router
onChange={(e) => {
if (previousEl) {
setOutEl(
<div class="out page" key={e.previous} onAnimationEnd={() => setOutEl(null)}>
{previousEl}
</div>
);
}
if (e.current) {
setPreviousEl(e.current.props.children);
}
}}
>
{routes}
</Router>
{outEl}
</Fragment>
);
};
export default App;
app.sass
.page
position: absolute
top: 0
bottom: 0
left: 0
right: 0
.out
animation: out 200ms forwards
@keyframes out
0%
opacity: 1
transform: translateX(0)
100%
opacity: 0
transform: translateX(100vw)
.in
animation: in 200ms forwards
@keyframes in
0%
opacity: 0
transform: translateX(-100vw)
100%
opacity: 1
transform: translateX(0)
我正在尝试使用 preact-router
进行页面转换,我已经尝试使用 preact-transition-group
包和 preact-css-transition-group
包,这给了我一个错误,无论如何这是我的基本设置:
import { h, FunctionComponent } from 'preact';
import Router from 'preact-router';
const App: FunctionComponent = () => {
return (
<Router>
<div path="/1" style="padding: 50px">
page 1 <a href="/2">page 2</a>
</div>
<div path="/2" style="padding: 50px">
page 2 <a href="/1">page 1</a>
</div>
</Router>
);
};
打字稿 and/or preact-router
解决方案是可取的,但不是必需的。
创建动画的最佳方法是引入另一个 HOC - 包装您的页面并将其用作路由器目标的高阶组件。它会是这样的:
import { h, FunctionComponent } from 'preact';
import Router from 'preact-router';
const App: FunctionComponent = () => {
return (
<Router>
<PageAnimation path="/1">
<div style="padding: 50px">
page 1 <a href="/2">page 2</a>
</div>
</PageAnimation>
<PageAnimation path="/2">
<div style="padding: 50px">
page 2 <a href="/1">page 1</a>
</div>
</PageAnimation>
</Router>
);
};
您的实现代码类似于 - 如何制作转场动画.
Note: that this approach probably dosn't work with nested routes.
使用这种方法,您需要用 class 将每条路由包装在 div 中,这将使路由具有动画效果,并将键和路径属性设置为路由的路径,如下所示:
function wrapRoute(route: h.JSX.Element): h.JSX.Element {
return ( // the in class is the animation and the page class is makes sure that the old and new routes overlap
<div path={route.props.path} class="in page" key={route.props.path}>
{route}
</div>
);
}
然后你需要像这样添加两个反应变量:
const [previousEl, setPreviousEl] = useState<ComponentChildren | null>(null);
const [outEl, setOutEl] = useState<JSX.Element | null>(null);
之后你可以监听 preact-router
的 onChange
事件并将 outEl
设置为 div 包装 previousEl
并且有一个class 将动画化路由的出口,然后添加一个 onAnimationEnd
侦听器,以便您可以将 outEl
设置为 null
出口动画已经完成,最后一件事需要将 previousEl
设置为 e.current.props.children
,您的路由器组件侦听器应如下所示:
<Router onChange={(e) => {
if (previousEl) {
setOutEl(
<div class="out page" key={e.previous} onAnimationEnd={() => setOutEl(null)}>
{previousEl}
</div>
);
}
if (e.current) {
setPreviousEl(e.current.props.children);
}
}}
>
{routes} // this is an array containing all the wrapped routes.
</Router>
您需要做的最后一件事是创建动画,请查看下面的 app.sass
示例。
这里是完整的例子:
app.tsx
import { h, FunctionComponent, JSX, ComponentChildren, Fragment } from 'preact';
import Router from 'preact-router';
import { useState } from 'preact/hooks';
import './app.sass'
const routes = [
<div style="padding: 50px; background: red" path="/1">
page 1 <a href="/2">page 2</a> <a href="/3">page 3</a>
</div>,
<div style="padding: 50px; background: blue" path="/2">
page 2 <a href="/1">page 1</a> <a href="/3">page 3</a>
</div>,
<div style="padding: 50px; background: green" path="/3">
page 2 <a href="/1">page 1</a> <a href="/2">page 2</a>
</div>,
].map((route) => wrapRoute(route));
function wrapRoute(route: h.JSX.Element): h.JSX.Element {
return (
<div path={route.props.path} class="in page" key={route.props.path}>
{route}
</div>
);
}
const App: FunctionComponent = () => {
const [previousEl, setPreviousEl] = useState<ComponentChildren | null>(null);
const [outEl, setOutEl] = useState<JSX.Element | null>(null);
return (
<Fragment>
<Router
onChange={(e) => {
if (previousEl) {
setOutEl(
<div class="out page" key={e.previous} onAnimationEnd={() => setOutEl(null)}>
{previousEl}
</div>
);
}
if (e.current) {
setPreviousEl(e.current.props.children);
}
}}
>
{routes}
</Router>
{outEl}
</Fragment>
);
};
export default App;
app.sass
.page
position: absolute
top: 0
bottom: 0
left: 0
right: 0
.out
animation: out 200ms forwards
@keyframes out
0%
opacity: 1
transform: translateX(0)
100%
opacity: 0
transform: translateX(100vw)
.in
animation: in 200ms forwards
@keyframes in
0%
opacity: 0
transform: translateX(-100vw)
100%
opacity: 1
transform: translateX(0)