如何在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
相关产品推荐
相关产品推荐

