首页 > 解决方案 > 无法使用 NextJS 实现 Materialize-CSS 初始化脚本

问题描述

我正在使用Materialize CSS来设置我正在开发的 Web 应用程序的样式。我正在使用 NextJS 和 ReactJS 构建应用程序。我已经使用 Materialize CSS 文件中定义的类设置了导航栏的样式。但是,我无法按照Materialize 网站上的说明使用规定的初始化脚本来实现响应式侧边栏功能。

我的导航栏组件 (./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 is not a function

我什至尝试完全取消 JQuery,只使用初始化脚本的 vanilla JS 版本componentDidMount

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

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

整个代码库都在Github上供参考,原型应用程序在shandillia.com上运行。有什么解决办法吗?

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

标签: materializenext.js

解决方案


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

如果您还没有安装 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这个问题


推荐阅读