我正在寻求帮助。我正在尝试在 Next.js 版本 13 中构建一个组件,该组件在位于窗口底部的 SongPlayer 组件中播放音乐,很像 Spotify 的歌曲播放器,但我的 SongPlayer 组件采用 youtubeVideoId Prop 并使用它来渲染 youtube iframe 嵌入来播放音乐。我已将此 SongPlayer 组件放置在我的应用程序 (app/layout.tsx) 的根布局中,因为我希望歌曲播放器在导航到不同页面之间保持不变,这是可行的,但我也希望它切换播放哪首歌曲当用户按下位于 app/[songSlug]/page.tsx 中的歌曲页面中的按钮时,该按钮会根据用户请求的 url slug 更新 youtubeVideoId。 这就是我陷入困境的地方。我认为歌曲页面上的按钮需要传递有关 SongPlayer 组件应使用的 youtubeVideoId 的数据,但 SongPlayer 组件是组件层次结构中较高的父组件。此外,由于我使用的是 Next.js 版本 13 的应用程序目录,因此服务器端组件会阻止我使用任何 React Hook ,例如 useContext。
这是我的代码: app/layout.tsx(这是根布局,它必须始终是服务器端组件。)
import './theme.scss'
import './page.scss'
import SongPlayer from './components/SongPlayer'
// import Play from './components/Play'
export const metadata = {
title: 'The Second Messenger',
description: 'Home Page',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang='en'>
<body>
{children}
<SongPlayer youTubeVideoId={'O94ESaJtHtM'} />
</body>
</html>
)
}
应用程序/SongPlayer.tsx
import selectors from './SongPlayer.module.scss'
type SongPlayerProps = {
youTubeVideoId: string
}
export default function SongPlayer({ youTubeVideoId }: SongPlayerProps) {
const srcURL = `https://www.youtube.com/embed/${youTubeVideoId}?color=white&rel=0`
return (
<section id={selectors.song_player}>
<div className={selectors.viewport}>
<iframe
id='ytplayer'
data-type='text/html'
src={srcURL}
frameBorder='0'
allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
allowFullScreen
></iframe>
</div>
</section>
)
}
应用程序/[songSlug]/page.tsx
import { getSongBySlug } from '@/lib/firebase'
export default async function SongPage({
params,
}: {
params: { songSlug: string }
}) {
const song: any = await getSongBySlug(params.songSlug)
const youtubeVideoId = song.stream_links.youtube
return (
<main>
<h2>About {song.title}</h2>
{/* This button should somehow pass youtubeVideoId to SongPlayer component when clicked */}
<button onClick={ } >
Play Song
</button>
</main>
)
}
更新以添加有关我的项目的更多上下文:
这是我的音乐/乐队的网站。用户可以导航到多个页面,例如主页、音乐、视频等,以及显示单个歌曲/发行的详细信息的 [songSlug] 页面。我想要来自 YouTube 的流,以便它能够计算 YouTube 上的视频播放次数,所以我没有使用 html <audio>
标签。我已经非常习惯使用 YouTube API,并且在将来的某个时候,我可能想要添加播放器控件以获得更注重音频的 UI,但目前我已经简化了组件,以便仅播放来自YouTube 位于屏幕右下角的绝对定位 div 中。
我有一个 CMS,将数据存储在 firebase 中。这个数据库就是 youtubeVideoId
来自。这个想法是,当用户导航到 [songSlug] 页面时,页面组件根据 slug 参数直接从 firebase 获取该特定歌曲的数据。然后使用该歌曲获取的数据(例如插图、评论、外部链接、相关轨道等)渲染页面。CMS/数据库中的所有歌曲都会渲染到 [songSlug]/page.tsx 组件,并具有相同的布局,包括“播放这首歌曲”按钮应该以某种方式告诉根布局中的 SongPlayer 组件要播放哪首歌曲。 SongPlayer 本身并不位于 [songSlug] 页面内部,因为我希望它在用户导航到网站上的任何其他页面时继续播放。
回顾一下:
- 我放置了每首歌曲的数据,包括它的歌曲和
youtubeVideoId
通过 CMS 导入 Firebase 数据库。 - 用户导航到特定歌曲的页面,例如 mysite.com/music/best-song-ever
- [songSlug]/page.tsx 组件识别 slug 参数(“best-song-ever”)并将其与我在第一步中为该歌曲输入的 slug 进行匹配,并获取数据库中该歌曲的所有数据,包括
youtubeVideoId
- [songSlug]/page.tsx 的 render 方法使用上一步获取的数据填充前端。其中应包含一个按钮,用于播放用户当前正在观看的歌曲(实际上是 YouTube 视频)。
- 用户点击播放按钮,SongPlayer 组件会在右下角弹出,并播放与第 3 步中获取的 youtubeVideoId 关联的 YouTube 视频,用户可以在播放歌曲时收听歌曲(或观看其视频)继续浏览网站。
最佳答案
我想您可以使用模板而不是使用文档中列出的布局,如果我们正在工作取决于 useState 或 useEffect,那么它们是更好的选择。我分享一个链接供您引用: 依赖于 useEffect(例如记录页面 View )和 useState(例如每页反馈表)的功能。 https://nextjs.org/docs/app/api-reference/file-conventions/template
关于javascript - 在 Next.js 版本 13 中,如果根布局必须始终是服务器端组件,如何将 prop 传递给根布局中的组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77098854/