有没有办法在 Next.js 中使用 Materialise CDN?

IT技术 css reactjs next.js materialize
2021-05-15 15:37:12

我正在构建 Next.js 应用程序,并希望将 Materialise CDN 与它一起使用。在 React 中,我只需在public/index.html文件中添加 CDN 链接就可以了。Next 似乎没有那个,我被困在如何做到这一点上。

我试过

npm install materialize-css@next --save

我将它导入pages/_app.tsx如下:

import 'materialize-css/dist/css/materialize.min.css';
import 'materialize-css'

当它只是第一次单独导入时,它运行良好,但是当我导入第二个以添加 JS 时,它会引发此错误:

Server Error
ReferenceError: window is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.

此外,通过这种导入,我无法对 CSS 进行任何自定义,这就是我想使用 CDN 的原因。我已经做了好几天了,但没有运气。

2个回答

而不是_app.tsx_document.js文件中进行。这个文件是你在 NextJS 项目中增加 html 和 body 标签的地方。需要注意的是,它必须是.js文件,而不是 .tsx。

默认情况下,此文件不存在于您的项目中,它由 nextJS 自动生成,但您可以在 pages 文件夹中创建它以覆盖默认文件并在那里导入 CDN。

您在官方文档中有 _document.js 模板和更多信息

通过 CDN 使用 Materialise

正如丹尼尔在他的回答中提到的,您可以在您的自定义中添加 CDN 链接_document,这样 CSS 和 JavaScript 都可以在浏览器中正确加载。

// /pages/_document.js

class MyDocument extends Document {
    render() {
        return (
            <Html lang="en">
                <Head>
                    <link
                        rel="stylesheet"
                        href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
                    />
                </Head>
                <body>
                    <Main />
                    <NextScript />
                    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
                </body>
            </Html>
        );
    }
}

由于Materialise公司使用Web API的内部,你需要访问连接到该实例Materialise的window内部useEffect这可以防止在ReferenceError: window is not definedNext.js 在服务器上预渲染页面时出现错误。

这是一个关于如何在呈现轮播的组件中使用 Materialize 的小示例。

const MaterializeCarousel = () => {
    useEffect(() => {
        const elems = document.querySelectorAll('.carousel');
        const instances = window.M.Carousel.init(elems);
    }, []);

    return (
        <div className="carousel">
            <a className="carousel-item" href="#one!"><img src="https://lorempixel.com/250/250/nature/1" /></a>
            <a className="carousel-item" href="#two!"><img src="https://lorempixel.com/250/250/nature/2" /></a>
            <a className="carousel-item" href="#three!"><img src="https://lorempixel.com/250/250/nature/3" /></a>
            <a className="carousel-item" href="#four!"><img src="https://lorempixel.com/250/250/nature/4" /></a>
            <a className="carousel-item" href="#five!"><img src="https://lorempixel.com/250/250/nature/5" /></a>
        </div>
    );
};

通过 npm 包使用 Materialize

另一种选择是通过其 npm 包使用库materialize-css

您首先需要导入全局 CSS,就像您所做的那样,在_app.

import 'materialize-css/dist/css/materialize.min.css';

此处无法加载 JavaScript 代码,如前所述,它使用了无法在服务器上运行的 Web API。

相反,以相同的轮播组件为例,您应该materialize-css在 a 内部动态导入useEffect以便它仅在客户端加载。

const MaterializeCarousel = () => {
    useEffect(() => {
        const init = async () => {
            const M = await import('materialize-css');
            const elems = document.querySelectorAll('.carousel');
            const instances = M.Carousel.init(elems);
        };
        init();
    }, []);

    return (
        <div className="carousel">
            <a className="carousel-item" href="#one!"><img src="https://lorempixel.com/250/250/nature/1" /></a>
            <a className="carousel-item" href="#two!"><img src="https://lorempixel.com/250/250/nature/2" /></a>
            <a className="carousel-item" href="#three!"><img src="https://lorempixel.com/250/250/nature/3" /></a>
            <a className="carousel-item" href="#four!"><img src="https://lorempixel.com/250/250/nature/4" /></a>
            <a className="carousel-item" href="#five!"><img src="https://lorempixel.com/250/250/nature/5" /></a>
        </div>
    );
};