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

Next.js页面中外部JavaScript脚本无法正常执行问题求助

解决Next.js中原生DOM脚本无法正常运行的问题

看起来你遇到的核心问题是原生DOM操作的时机不对,以及Next.js(React框架)与原生JS脚本的适配问题,下面我会一步步帮你分析并解决:

问题根源

  1. 脚本执行时机过早:你使用了strategy="beforeInteractive",这个策略会在页面DOM还未完全渲染时就执行脚本。此时document.getElementById('result')和document.getElementById('filter')根本找不到对应的元素,后续的addEventListener、result.innerHTML操作都会报错,导致页面卡在加载状态。
  2. 原生DOM操作与React的冲突:Next.js基于React,React通过虚拟DOM管理UI,直接用原生JS操作DOM容易出现UI不同步的问题。
  3. 小语法错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 21:12:39