无法使用 NextJS 实现 Materialize-CSS 初始化脚本

Unable to implement Materialize-CSS initialization scripts with NextJS

我正在使用 Materialize CSS to style a web app I'm working on. Am building the app using NextJS with ReactJS. I have already styled the navbar using the classes defined in the Materialize CSS file. However, I'm unable to implement the responsive sidebar functionality using the prescribed initialization script as instructed on the Materialize website

我的导航栏组件 (./components/Navbar.js) 如下所示:

import React, { Component, Fragment } from 'react';
import Link from 'next/link';
import $ from 'jquery';

class Navbar extends Component {
  constructor(props) {
    super(props)
    this.props = props;
  }

  componentDidMount = () => {
    document.addEventListener('DOMContentLoaded', function() {
      var elems = document.querySelectorAll('.sidenav');
      var instances = M.Sidenav.init(elems, options);
    });
  }

  render() {
    return (

      <Fragment>
        <nav>
          <div className="nav-wrapper blue">
            <Link prefetch href='/'>
              <a href="/" className="brand-logo">Project Coco</a>
            </Link>
            <a href="#" data-target="slide-out" className="sidenav-trigger"><i className="material-icons">menu</i></a>
            <ul id="nav-mobile" className="right hide-on-med-and-down">
              <li>
                <Link prefetch href='/'>
                  <a>Home</a>
                </Link>
              </li>
              <li>
                <Link prefetch href='/about'>
                  <a>About</a>
                </Link>
              </li>
              <li>
              </li>
            </ul>
          </div>
        </nav>
        {/* Sidenav markup */}
        <ul className="sidenav" id="slide-out">
          <li>
            <Link prefetch href='/'>
              <a>Home</a>
            </Link>
          </li>
          <li>
            <Link prefetch href='/about'>
              <a>About</a>
            </Link>
          </li>
        </ul>
      </Fragment>
    );
  }
}

export default Navbar;

很明显,此功能(边栏)需要 JQuery。所以我已经通过 yarn 添加了它并使用 import $ from 'jquery' 调用它。但是在 运行 上,它抛出一个错误说 sidenav 不是函数

我什至尝试完全取消 JQuery 并在 componentDidMount:

中使用 vanilla JS 版本的初始化脚本
document.addEventListener('DOMContentLoaded', function() {
    var elems = document.querySelectorAll('.sidenav');
    var instances = M.Sidenav.init(elems, options);
  });

但这一次,虽然没有错误,但该功能仍然无法正常工作,点击汉堡菜单不会触发 sidenav,它应该触发。

整个代码库已在 Github for reference and the prototype app is live at schandillia.com 上发布。有什么解决办法吗?

P.S.: 似乎问题是 ComponentDidMount 中的初始化代码在 MaterializeCSS.js 之前执行(被称为外部文件),它依赖于它。任何解决此问题的工作都可能是一个潜在的解决方案,尽管这只是一个假设。

您需要将 materialize-css 导入到您的组件中。遗憾的是,如果您尝试执行 import 'materialize-css',您将收到 window is undefined 错误。这是因为 Next.js 是通用的,这意味着它首先在 window 不存在 的服务器端执行代码。我用于此问题的解决方法如下:

安装 materialize-css 如果你还没有:

$ npm i materialize-css

仅当定义了 window 时,才将 materialize-css 导入您的组件:

if (typeof window !== 'undefined') {
    window.$ = $;
    window.jQuery = $;
    require('materialize-css');
}

然后,在您的 componentDidMount 方法中:

componentDidMount = () => {
    $('.sidenav').sidenav();
}

因此您的组件如下所示:

import React, { Component, Fragment } from 'react';
import Link from 'next/link';
import $ from 'jquery';

if (typeof window !== 'undefined') {
    window.$ = $;
    window.jQuery = $;
    require('materialize-css');
}

class Navbar extends Component {
    constructor(props) {
        super(props)
        this.props = props;
    }

    componentDidMount = () => {
        $('.sidenav').sidenav();
    }

    render() {
        return (
              <Fragment>
                <nav>
                    ...
                </nav>
                {/* Sidenav markup */}
                <ul className="sidenav" id="slide-out">
                    ...
                </ul>
              </Fragment>
        );
    }
}

export default Navbar;

来源:Next.js FAQ and this issue.

这个怎么样:-

  • _app.tsx
import 'materialize-css/dist/css/materialize.min.css';
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;

  • index.tsx
import React, { useEffect } from 'react';

const Index = () => {
  useEffect(() => {
    const M = require('materialize-css');
    M.toast({ html: 'worlds' });
  }, []);

  return (
    <div className='container'>
      <h1>hello</h1>
    </div>
  );
};

export default Index;