Next.js页面中外部JavaScript脚本无法正常执行问题求助
解决Next.js中原生DOM脚本无法正常运行的问题
看起来你遇到的核心问题是原生DOM操作的时机不对,以及Next.js(React框架)与原生JS脚本的适配问题,下面我会一步步帮你分析并解决:
问题根源
- 脚本执行时机过早:你使用了
strategy="beforeInteractive",这个策略会在页面DOM还未完全渲染时就执行脚本。此时document.getElementById('result')和document.getElementById('filter')根本找不到对应的元素,后续的addEventListener、result.innerHTML操作都会报错,导致页面卡在加载状态。 - 原生DOM操作与React的冲突:Next.js基于React,React通过虚拟DOM管理UI,直接用原生JS操作DOM容易出现UI不同步的问题。
- 小语法错误:
reportSearch.js里的className={user-info}是错误的,原生HTML应该用class="user-info"。
解决方案一:调整脚本执行时机(快速修复)
如果你想继续使用原生JS脚本,需要确保脚本在DOM完全加载后再执行:
1. 修改reportSearch.js,添加DOM加载监听
// 等待页面DOM完全渲染完成后再执行逻辑 document.addEventListener('DOMContentLoaded', () => { const result = document.getElementById('result') const filter = document.getElementById('filter') const listItems = [] // 提前判断元素是否存在,避免报错 if (!result || !filter) return getData() filter.addEventListener('input', (e) => filterData(e.target.value)) async function getData() { const res = await fetch('https://randomuser.me/api?results=50') const { results } = await res.json() result.innerHTML = '' results.forEach(user => { const li = document.createElement('li') listItems.push(li) // 修正className为class li.innerHTML = ` <img src="${user.picture.large}" alt="${user.name.first}"> <div class="user-info"> <h4>${user.name.first} ${user.name.last}</h4> <p>${user.location.city}, ${user.location.country}</p> <p class="text-dark">${user.gender}</p> </div> ` result.appendChild(li) }) } function filterData(searchTerm) { listItems.forEach(item => { if(item.innerText.toLowerCase().includes(searchTerm.toLowerCase())) { item.classList.remove('hide') } else { item.classList.add('hide') } }) } })
2. 调整Next.js页面中的脚本加载策略
把strategy改成afterInteractive,确保脚本在页面交互就绪后执行:
// 别忘了导入Head组件!你之前的代码漏了这一行 import Head from 'next/head' import ArticleList from '../components/ArticleList' import Script from 'next/script' export default function Home({ articles }) { return ( <div> <Head> <title>MFT Power BI - Next.js</title> <meta name='keywords' content='test,test,test'/> </Head> <Script src="../components/scripts/reportSearch.js" strategy="afterInteractive" /> <div> <ArticleList articles={articles} /> </div> </div> ) } // ... 你的getStaticProps代码不变
解决方案二:重构为React组件(推荐)
在Next.js中,更符合框架设计的方式是用React组件来实现功能,避免原生DOM操作的兼容性问题:
1. 创建UserSearch.js组件
import { useState, useEffect } from 'react' export default function UserSearch() { const [users, setUsers] = useState([]) const [searchTerm, setSearchTerm] = useState('') const [filteredUsers, setFilteredUsers] = useState([]) // 初始化获取用户数据 useEffect(() => { const fetchUsers = async () => { const res = await fetch('https://randomuser.me/api?results=50') const { results } = await res.json() setUsers(results) setFilteredUsers(results) } fetchUsers() }, []) // 根据搜索词过滤用户 useEffect(() => { const filtered = users.filter(user => { const fullName = `${user.name.first} ${user.name.last}`.toLowerCase() const location = `${user.location.city}, ${user.location.country}`.toLowerCase() const gender = user.gender.toLowerCase() return fullName.includes(searchTerm.toLowerCase()) || location.includes(searchTerm.toLowerCase()) || gender.includes(searchTerm.toLowerCase()) }) setFilteredUsers(filtered) }, [searchTerm, users]) return ( <div> <input id="filter" type="text" placeholder="Search users..." value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> <ul id="result"> {filteredUsers.map(user => ( <li key={user.login.uuid}> <img src={user.picture.large} alt={user.name.first} /> <div className="user-info"> <h4>{user.name.first} {user.name.last}</h4> <p>{user.location.city}, {user.location.country}</p> <p className="text-dark">{user.gender}</p> </div> </li> ))} </ul> </div> ) }
2. 在Home页面中使用组件
import Head from 'next/head' import ArticleList from '../components/ArticleList' import UserSearch from '../components/UserSearch' // 导入组件 export default function Home({ articles }) { return ( <div> <Head> <title>MFT Power BI - Next.js</title> <meta name='keywords' content='test,test,test'/> </Head> <UserSearch /> {/* 直接使用组件 */} <div> <ArticleList articles={articles} /> </div> </div> ) } // ... 你的getStaticProps代码不变
这种方式利用React的状态管理来控制UI,完全避免了原生DOM操作的问题,也更符合Next.js的开发规范。
内容的提问来源于stack exchange,提问作者Adam Ross
相关产品推荐
相关产品推荐

