TypeError:无法读取 null 的属性(读取“classList”)

Posted

技术标签:

【中文标题】TypeError:无法读取 null 的属性(读取“classList”)【英文标题】:TypeError: Cannot read properties of null (reading '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"  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.dropdownContentstyles.myDropdown 设置在哪里?如果您使用变量在标记中设置 id 和 className,您可能应该在脚本中使用相同的变量,例如 document.getElementById($styles.myDropdown).classList.toggle("show"); 【参考方案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"  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

是的,终于配置好了。感谢whygee 和Ingo 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 文件...

以上是关于TypeError:无法读取 null 的属性(读取“classList”)的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:无法读取 null 的属性(读取“classList”)

TypeError:无法读取 null 的属性(读取“1”)

TypeError:无法读取 null 的属性“userID”

TypeError:无法读取 null 的属性(读取“classList”)反应

TypeError:无法读取 null 的属性“uid”

× TypeError: 无法读取 null 的属性“名称”