You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js的page.jsx中集成指定JavaScript代码(适配Next Auth)

问题

需要将实现导航栏下拉切换的静态JavaScript代码集成到Next.js的page.jsx中,但因为Clerk Auth的服务端状态特性,直接使用<script>标签无法正常工作,需确保两段代码无错误协同运行。

原静态JS代码:

const { exportTraceState } = require("next/dist/trace");

const toggleBtn = document.querySelector('.toggle_btn')
const toggleBtnIcon = document.querySelector('.toggle_btn')
const dropDownMenu = document.querySelector('.dropdown_menu')

toggleBtn.onclick = function(){
    dropDownMenu.classList.toggle('open')
    const isOpen = dropDownMenu.classList.contains('open')

    toggleBtnIcon.classList = isOpen
    ? 'fa-solid fa-xmark'
    : 'fa-solid fa-bars'
}

目标page.jsx代码(已集成Clerk Auth):

import Image from "next/image";
import Head from "next/head";
import Script from "next/script";
import { UserButton, auth } from "@clerk/nextjs";
import Link from "next/link";

export default function Home() {
 const {userId } = auth();
 console.log(userId);
 
 return (
     <>
     <meta charSet="UTF-8" />
     <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <link rel="stylesheet" href="styles.css" />
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
     <title>Responsive Navbar</title>
     <div className="body">
          <nav>
               <div className="navbar">
                    <div className="logo"><a href="#">TradeProject</a></div>
               
               <ul className="links">
                    <li><a href="#hero">Home</a></li>
                    <li><a href="#about">About </a></li>
                    <li><a href="#features">Features</a></li>
                    <li><a href="#pricing">Pricing</a></li>
               </ul>
               <a href="/sign-up" className="action_btn">Get Started</a>
               <div className="toggle_btn">
               <i class="fa-solid fa-bars"></i>
               </div>
               </div>
               <div className="dropdown_menu">
               <li><a href="#hero">Home</a></li>
                    <li><a href="#about">About </a></li>
                    <li><a href="#features">Features</a></li>
                    <li><a href="#pricing">Pricing</a></li>
                    <li><a href="/sign-up" className="action_btn">Get Started</a></li>
               </div>
          </nav>
     </div>

   </>
 );
}
解决方案

在Next.js(尤其是App Router)中,直接操作DOM的原生JS逻辑需要适配React的组件生命周期和客户端渲染特性,同时兼容Clerk的服务端状态。以下是具体实现步骤:

1. 标记组件为客户端组件

Next.js 13+ App Router中,包含客户端交互逻辑的组件需要添加'use client'指令,确保代码在客户端执行,避免服务端渲染时的DOM不存在问题。

2. 用React状态与引用替代原生DOM操作

放弃document.querySelector和classList操作,改用React的useState管理下拉菜单的展开状态,useRef获取图标元素,用React的事件绑定处理点击逻辑。

3. 修正原静态JS的错误

原代码中toggleBtnIcon错误地选中了.toggle_btn容器,实际应该选中容器内的<i>图标元素,这会导致样式替换失效,需修正。

完整修改后的page.jsx代码
'use client' // 标记为客户端组件
import Image from "next/image";
import Head from "next/head";
import { auth } from "@clerk/nextjs";
import Link from "next/link";
import { useState, useRef } from "react"; // 导入React状态与引用API

export default function Home() {
 const { userId } = auth();
 console.log(userId);

 // 管理下拉菜单的展开状态
 const [isDropdownOpen, setIsDropdownOpen] = useState(false);
 // 获取图标元素的引用
 const toggleIconRef = useRef(null);

 // 切换下拉菜单的逻辑
 const handleToggleDropdown = () => {
   setIsDropdownOpen(prev => !prev);
   // 更新图标样式
   if (toggleIconRef.current) {
     toggleIconRef.current.className = isDropdownOpen
       ? 'fa-solid fa-bars'
       : 'fa-solid fa-xmark';
   }
 };

 return (
     <>
     <Head>
       <meta charSet="UTF-8" />
       <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
       <meta name="viewport" content="width=device-width, initial-scale=1.0" />
       <link rel="stylesheet" href="styles.css" />
       <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
       <title>Responsive Navbar</title>
     </Head>
     <div className="body">
          <nav>
               <div className="navbar">
                    <div className="logo"><Link href="#">TradeProject</Link></div>
               
               <ul className="links">
                    <li><Link href="#hero">Home</Link></li>
                    <li><Link href="#about">About </Link></li>
                    <li><Link href="#features">Features</Link></li>
                    <li><Link href="#pricing">Pricing</Link></li>
               </ul>
               <Link href="/sign-up" className="action_btn">Get Started</Link>
               {/* 绑定点击事件到toggle按钮 */}
               <div className="toggle_btn" onClick={handleToggleDropdown}>
                 {/* 用ref绑定图标元素 */}
                 <i ref={toggleIconRef} className="fa-solid fa-bars"></i>
               </div>
               </div>
               {/* 根据状态添加/移除open类 */}
               <div className={`dropdown_menu ${isDropdownOpen ? 'open' : ''}`}>
               <li><Link href="#hero">Home</Link></li>
                    <li><Link href="#about">About </Link></li>
                    <li><Link href="#features">Features</Link></li>
                    <li><Link href="#pricing">Pricing</Link></li>
                    <li><Link href="/sign-up" className="action_btn">Get Started</Link></li>
               </div>
          </nav>
     </div>
   </>
 );
}
关键说明
  • 'use client':确保组件在客户端渲染,避免服务端执行时找不到DOM元素的错误,同时兼容Clerk的客户端Auth逻辑。
  • useState:通过React状态管理下拉菜单的展开/收起状态,替代原生DOM的classList.toggle,符合React的数据流模式。
  • useRef:安全获取图标元素的引用,避免直接操作DOM带来的不确定性。
  • 替换<a>为Link:Next.js中推荐使用Link组件进行路由跳转,优化性能。

内容的提问来源于stack exchange,提问作者Suhaas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 01:19:52