【问题标题】:how can i create a page transition with preact如何使用 preact 创建页面转换
【发布时间】:2020-10-17 13:20:41
【问题描述】:

我正在尝试使用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>
  );
};

打字稿和/或preact-router 解决方案是可取的,但不是必需的。

【问题讨论】:

    标签: javascript typescript preact preact-router


    【解决方案1】:

    注意:这种方法可能不适用于嵌套路由。

    使用这种方法,您需要使用一个类将每个路由包装在一个 div 中,该类将为路由设置动画并将 key 和 path 属性设置为路由的路径,如下所示:

    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-routeronChange 事件并将outEl 设置为一个包装previousEl 的div,并具有一个动画路线出口的类,然后添加一个@ 987654327@ 监听器,这样您就可以将outEl 设置为null 一个out 动画完成,最后您需要将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)
    
    

    【讨论】:

      【解决方案2】:

      创建动画的最佳方法是引入另一个 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>
        );
      };
      

      您的实现代码类似于 - How to make transition animation

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-20
        • 2018-06-07
        • 2011-08-01
        • 2020-01-25
        • 2019-01-15
        • 1970-01-01
        相关资源
        最近更新 更多