下一个 js 页面转换时的加载屏幕

Posted

技术标签:

【中文标题】下一个 js 页面转换时的加载屏幕【英文标题】:Loading Screen on next js page transition 【发布时间】:2019-09-01 15:05:52 【问题描述】:

我正在尝试在我的 Nextjs 应用程序中更改路由时实现加载屏幕,例如 /home -> /about。

我目前的实现如下。我将初始加载状态设置为 false,然后在 componentDidMount 上对其进行更改。我还在 componentDidMount 中调用 Router.events.on 函数来更改路由更改开始时的加载状态。

_app.js在页面文件夹中

class MyApp extends App 
  constructor(props) 
    super(props);
    this.state = 
      loaded: false,
    ;
  

  componentDidMount() 
    this.setState( loaded: true );
    Router.events.on('routeChangeStart', () => this.setState( loaded: false ));
    Router.events.on('routeChangeComplete', () => this.setState( loaded: true ));
  



  render() 
    const  Component, pageProps  = this.props;

    const  loaded  = this.state;

    const visibleStyle = 
      display: '',
      transition: 'display 3s',
    ;
    const inVisibleStyle = 
      display: 'none',
      transition: 'display 3s',
    ;
    return (
      <Container>
        <>
          <span style=loaded ? inVisibleStyle : visibleStyle>
            <Loader />
          </span>
          <span style=loaded ? visibleStyle : inVisibleStyle>
            <Component ...pageProps />
          </span>
        </>
      </Container>
    );
  

这工作得很好,但我觉得可能有更好的解决方案更优雅的解决方案。这是实现此加载功能不麻烦的唯一方法还是有替代方法?

【问题讨论】:

您可能希望将inVisibleStylevisibleStyle 移出render() 方法 【参考方案1】:

为什么不在_app.js中使用nprogress,如下所示

import React from 'react';
import Router from 'next/router';
import App,  Container  from 'next/app';
import NProgress from 'nprogress';

NProgress.configure( showSpinner: publicRuntimeConfig.NProgressShowSpinner );

Router.onRouteChangeStart = () => 
  // console.log('onRouteChangeStart triggered');
  NProgress.start();
;

Router.onRouteChangeComplete = () => 
  // console.log('onRouteChangeComplete triggered');
  NProgress.done();
;

Router.onRouteChangeError = () => 
  // console.log('onRouteChangeError triggered');
  NProgress.done();
;

export default class MyApp extends App  ... 

链接到nprogress。

您还需要包含样式文件。如果把css文件放在static目录下,那么就可以访问样式如下:

<link rel="stylesheet" type="text/css" href="/static/css/nprogress.css" />

确保 CSS 在所有页面中都可用...

它适用于您所有更改的路线。

【讨论】:

nprogress 不允许自定义加载器对吗?它只有顶部的加载条纹。 没错。但是,您可以将 nprogress 更改为您想要的任何其他内容。 我的意思是使用你的自定义组件 对于将来阅读本文的人,您可以通过从 nprogress.css(在 node_modules 中)复制样式并将其粘贴到您自己的 CSS/SCSS 文件中并导入您的 CSS 文件而不是_app.js 中的 nprogress.css 文件。您可以摆弄 CSS,因为动画非常基础。 对于使用 Next.js 的人,现在有这个:npmjs.com/package/nextjs-progressbar【参考方案2】:

使用新的钩子API, 我就是这样做的..

function Loading() 
    const router = useRouter();

    const [loading, setLoading] = useState(false);

    useEffect(() => 
        const handleStart = (url) => (url !== router.asPath) && setLoading(true);
        const handleComplete = (url) => (url === router.asPath) && setLoading(false);

        router.events.on('routeChangeStart', handleStart)
        router.events.on('routeChangeComplete', handleComplete)
        router.events.on('routeChangeError', handleComplete)

        return () => 
            router.events.off('routeChangeStart', handleStart)
            router.events.off('routeChangeComplete', handleComplete)
            router.events.off('routeChangeError', handleComplete)
        
    )
    
    return loading && (<div>Loading..../*I have an animation here*/</div>);

现在&lt;Loading/&gt; 将在路线发生变化时出现... 我使用 react-spring 对其进行动画处理,但您可以使用任何您喜欢的库来执行此操作。

您甚至可以更进一步,通过修改获得urlhandleStarthandleComplete 方法,在组件出现时进行修改。

【讨论】:

嗨,我想看看这是如何在完整的 _app.js 组件中实现的。如果您能提供该文件的链接,我将不胜感激。 如果使用动态路由,似乎使用router.asPath 而不是router.pathname 更准确。 router.asPath in handleComplete 似乎没有及时解析到目标路径。所以我决定不比较setLoading之前的url,它可以工作。 Hmm.. 不建议删除 URL 检查,因为即使 URL 没有变化,这也会更新状态。如果您查看 NextJS 文档,它会提到 router.asPath 不包括 basePath 和语言环境。所以请确认您是否在您的应用程序中使用了任何这些,以便我可以更新代码 就我而言,我没有比较 routeChangeComplete ,我只是将状态设置为 false。因为在routeChangeComplete 上,router.asPath 的值在第一次调用时不会改变,所以我必须调用它两次才能改变router.asPath 的值。【参考方案3】:

NProgress 的新更新:

import Router from 'next/router'
import Link from 'next/link'
import Head from 'next/head'
import NProgress from 'nprogress'

Router.events.on('routeChangeStart', (url) => 
  console.log(`Loading: $url`)
  NProgress.start()
)
Router.events.on('routeChangeComplete', () => NProgress.done())
Router.events.on('routeChangeError', () => NProgress.done())

export default function App( Component, pageProps ) 
  return (
    <>
      <Head>
        /* Import CSS for nprogress */
        <link rel="stylesheet" type="text/css" href="/nprogress.css" />
      </Head>
      <Component ...pageProps />
    </>
  )

如果您使用 Tailwind CSS,请从此处复制代码:https://unpkg.com/nprogress@0.2.0/nprogress.css 并将代码粘贴到您的全局 CSS 文件中。

如果您想禁用微调器,请在 _app.tsx/jsx 文件中添加以下代码并从 CSS 中删除微调器样式。

NProgress.configure( showSpinner: false );

来源链接:

https://github.com/rstacruz/nprogress https://nextjs.org/docs/api-reference/next/router

【讨论】:

以防万一,您必须将nprogress.css保存在/public【参考方案4】:

对于 2021 年遇到此问题的任何人,nextjs-progressbar 包让这一切变得超级简单。在您的 Next.js _app.js 中,只需添加:

import NextNProgress from 'nextjs-progressbar';

export default function MyApp( Component, pageProps ) 
  return (
    <>
      <NextNProgress />
      <Component ...pageProps />;
    </>
  );

完成了!

Demo 和截图:

【讨论】:

很好的答案。为我工作。 非常棒,开箱即用,代码最少。

以上是关于下一个 js 页面转换时的加载屏幕的主要内容,如果未能解决你的问题,请参考以下文章

node.js + mysql + ejs 数据插入后无需重新加载页面即可更新屏幕信息

如何在 Next.js 中实现加载屏幕

页面加载时的div动画

JS若何将在页面上取得的元素坐标转换成屏幕坐标??

加载应用程序时的离子调用功能

我想用JS HTML CSS JQuery创建一个预加载屏幕(可选),没有后端