【问题标题】:Unable to implement Materialize-CSS initialization scripts with NextJS无法使用 NextJS 实现 Materialize-CSS 初始化脚本
【发布时间】:2018-09-02 20:59:15
【问题描述】:

我正在使用Materialize CSS 来设置我正在开发的网络应用程序的样式。我正在使用 NextJS 和 ReactJS 构建应用程序。我已经使用 Materialize CSS 文件中定义的类设置了导航栏的样式。但是,我无法使用指定的初始化脚本 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 上供参考,原型应用程序在schandillia.com 上运行。有什么解决办法吗?

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

【问题讨论】:

    标签: materialize next.js


    【解决方案1】:

    您需要将 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 FAQthis issue

    【讨论】:

    • 感谢您提供出色的解决方案,劳尔。如果你不介意最后一个问题:如果我在多个组件中像这样导入物化,它会增加我的 JS 负载吗?我的意思是,每个组件都会向呈现的页面添加一个额外的库副本吗?
    • 不,不会。 Webpack 将为您处理:“每个 React 组件都会有自己的范围,当它需要/导入另一个模块时,webpack 将检查所需的文件是否已经包含在包中。”希望这可以帮助!来源:stackoverflow.com/questions/33313662/…
    • 请问它是否适用于 CSS 模块?在我继续我的样板之前
    【解决方案2】:

    这个怎么样:-

    • _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;
    
    

    【讨论】:

      猜你喜欢
      • 2019-05-13
      • 2019-05-04
      • 2018-10-28
      • 1970-01-01
      • 1970-01-01
      • 2021-08-28
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多