【问题标题】:TypeError: Cannot read properties of null (reading 'classList')TypeError:无法读取 null 的属性(读取“classList”)
【发布时间】:2022-01-12 07:37:58
【问题描述】:

我正在使用 nextjs 应用程序。我只是想制作一个下拉菜单。

这是我的完整代码:

import React from 'react'
import Link from 'next/link'
import styles from './header.module.css'

const Header = () => {
    /* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
    const myFunction =()=>{
        document.getElementById(styles.myDropdown).classList.toggle("show");
    }

    // Close the dropdown menu if the user clicks outside of it
    if (typeof window !== "undefined") {
        window.onclick = function (event) {
            if (!event.target.matches('.dropbtn')) {
                var dropdowns = document.getElementsByClassName("dropdown-content");
                var i;
                for (i = 0; i < dropdowns.length; i++) {
                    var openDropdown = dropdowns[i];
                    if (openDropdown.classList.contains('show')) {
                        openDropdown.classList.remove('show');
                    }
                }
            }
        }
      }

    return (
        <div className={styles.header}>
            <div className={styles.logoLink}>
                <img src="images/itacs.png" alt="" className={styles.logo} />
            </div>
            <div className={styles.services}>
                <ul>
                    <li><Link href="/page">Docs</Link></li>
                    <li><Link href="/page">Learn</Link></li>
                    <li><Link href="/page">Projects</Link></li>
                    <li><Link href="/page">Blog</Link></li>
                    <div className={styles.dropdown}>
                        <button onClick={myFunction} className={styles.dropbtn}>Dropdown</button>
                        <div id={styles.myDropdown} className={styles.dropdownContent}>
                            <a href="/">Link 1</a>
                            <a href="/">Link 2</a>
                            <a href="/">Link 3</a>
                        </div>
                    </div>
                </ul>
            </div>
            <form action="" className={styles.headerForm}>
                <a href="/" className={styles.logIn}>Log In</a>
                <a href="/" className={styles.getStarted}>Get Started</a>
            </form>
        </div>
    )
}

export default Header

这里我刚刚在div的id中添加了classlist! 当按钮被单击为下拉菜单时,我试图显示下面的 div。 我无法弄清楚这一点!

对于任何想知道 css 文件中存在什么的人:

/* dropdown */
/* Dropdown Button */
.dropbtn {
    background-color: #3498DB;
    color: white;
    padding: 16px;
    font-size: 16px;
    border: none;
    cursor: pointer;
  }
  
  /* Dropdown button on hover & focus */
  .dropbtn:hover, .dropbtn:focus {
    background-color: #2980B9;
  }
  
  /* The container <div> - needed to position the dropdown content */
  .dropdown {
    position: relative;
    display: inline-block;
  }
  
  /* Dropdown Content (Hidden by Default) */
  .dropdownContent {
    display: none;
    position: absolute;
    background-color: #f1f1f1;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
  }
  
  /* Links inside the dropdown */
  .dropdownContent a {
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
  }
  
  /* Change color of dropdown links on hover */
  .dropdownContent a:hover {background-color: #ddd}
  
  /* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */
  .show {display:block;}

任何帮助将不胜感激!

【问题讨论】:

  • styles.dropdownContent{styles.myDropdown} 设置在哪里?如果您使用变量在标记中设置 id 和 className,您可能应该在脚本中使用相同的变量,例如 document.getElementById(${styles.myDropdown}).classList.toggle("show");

标签: javascript reactjs next.js typeerror dropdown


【解决方案1】:

应该是&lt;div className="dropdown"&gt; 而不是&lt;div class="dropdown"&gt;&lt;div id={styles.myDropdown} className={styles.dropdownContent}&gt;

你也应该避免在 react/next 应用中使用 vanilla js。

你会得到一个像这样的反应状态:

const [dropdownToggled, toggleDropdown] = useState(false);
  
const handleClick = () => {
  toggleDropdown(!dropdownToggled);
};

并且有一个条件是你的 jsx 是否有一个 className hidden 设置 display: none

类似这样的:

     <div
      className={`${styles.dropdownContent} 
      ${dropdownToggled ? styles.hidden : ""}`}
     >
       <a href="/">Link 1</a>
       <a href="/">Link 2</a>
       <a href="/">Link 3</a>
     </div>

要在用户在外部点击时关闭下拉菜单,您需要这样的 div:

<div
  className={styles.backdrop}
  onClick={() => toggleDropdown(true)}
></div>

样式如下:

.backdrop {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: -1;
}

现在,由于此 div 占据整个屏幕,并且当用户单击页面上的任何位置时绝对定位,所以 onClick 将触发并切换下拉菜单。

Working CodeSandbox.

【讨论】:

  • 你是对的!我没有看到这一点,因为代码看起来像 HTML,而它不是 HTML,而是他妈的 JSX。感谢您指出!确保变量内容实际上与 getElementByIdgetElementsByClassName 中的静态字符串匹配也是很好的,除了那些 vanilla JS DOM 函数可能不是“React 方式”的代码风格。
  • 确实,我建议避免在 react/next 项目中做 vanilla js 的东西,你会改为按钮上的 onClick 道具并使用反应状态来知道下拉菜单何时是或不是切换。用一个例子更新了答案,你会怎么做
  • 我添加了我的答案,非常感谢@whygee 的帮助!它有效,但需要进行一些配置!
  • @whygee 您的方法绝对有效,但我有一个小问题。当我单击按钮时,它会打开并保持打开状态,直到我再次单击它。当用户点击其他地方时,有什么方法可以关闭下拉菜单?
  • @ITACS 我想到的最简单的方法是添加一个虚拟的“背景” div,该 div 绝对定位并采用负 z-index 的整个页面宽度/高度,因此它始终位于背景和onClick,下拉状态被切换。用这种方法更新了 CodeSandbox
【解决方案2】:
import React, { useState } from 'react'
import Link from 'next/link'
import styles from './header.module.css'

const Header = () => {
    const [dropdownToggled, toggleDropdown] = useState(false);

    const handleClick = () => {
        toggleDropdown(!dropdownToggled);
        console.log("boy");
    };

    // Close the dropdown menu if the user clicks outside of it
    if (typeof window !== "undefined") {
        window.onclick = function (event) {
            if (!event.target.matches('#dropbtn')) {
                var dropdowns = document.getElementsByClassName(styles.dropdownContent);
                var i;
                for (i = 0; i < dropdowns.length; i++) {
                    var openDropdown = dropdowns[i];
                    if (openDropdown.classList.contains('show')) {
                        openDropdown.classList.remove('show');
                    }
                }
            }
        }
    }

    return (
        <div className={styles.header}>
            <div className={styles.logoLink}>
                <img src="images/itacs.png" alt="" className={styles.logo} />
            </div>
            <div className={styles.services}>
                <ul>
                    <li><Link href="/page">Docs</Link></li>
                    <li><Link href="/page">Learn</Link></li>
                    <li><Link href="/page">Projects</Link></li>
                    <li><Link href="/page">Blog</Link></li>
                    <div className={styles.dropdown}>
                        <button onClick={handleClick} id="dropbtn" className={styles.dropbtn}>Dropdown</button>
                        <div
                            className={`${styles.dropdownContent} ${dropdownToggled ? styles.show : ""}`}
                        >
                            <a href="/">Link 1</a>
                            <a href="/">Link 2</a>
                            <a href="/">Link 3</a>
                        </div>
                    </div>
                </ul>
            </div>
            <form action="" className={styles.headerForm}>
                <a href="/" className={styles.logIn}>Log In</a>
                <a href="/" className={styles.getStarted}>Get Started</a>
            </form>
        </div>
    )
}

export default Header

是的,终于配置好了。感谢whygeeIngo Steinkie

【讨论】:

    【解决方案3】:

    如果您使用变量在标记中设置 id 和 className,您可能应该在脚本中使用相同的变量,例如

    document.getElementById(`${styles.myDropdown}`).classList.toggle("show");
    

    [编辑]或没有不必要的冗余模板字符串:

    document.getElementById(styles.myDropdown).classList.toggle("show");
    

    假设styles.myDropdown 是一个字符串(不是一个对象)。

    否则您的代码无法确保idclassName 相同。

    【讨论】:

    • 我试过了,但它不起作用。它仍然给我同样的错误,下一个 js 在 myFunction 的右括号中指出错误:第 10 行。应该怎么做?
    • 第 10 行是哪一行? document.getElementById 行后的右花括号?
    • 还看到我的(快速输入的)答案使用了不必要的模板字符串,较短的版本应该是document.getElementById(styles.myDropdown),但无论如何这不应该有任何区别。
    • styles.myDropdown 的值和类型是什么?这应该是一个字符串。目前我只能猜测,因为我还没有看到 header.module.css 的内容,但我怀疑这会从 CSS 文件中返回一个字符串?
    • @IngoSteinkie 我也会添加我的错误和 css 文件...
    猜你喜欢
    • 2019-03-25
    • 2021-11-21
    • 2021-11-07
    • 2019-04-10
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2020-04-25
    • 2021-12-04
    相关资源
    最近更新 更多