我在此处使用示例
https://github.com/zeit/next.js#custom-document
,我想更改身体标签上的custom_class
我曾尝试通过调用组件的道具,但无效。我想根据某种条件添加一个"黑暗"类,但我不知道如何更改。
编辑:
我不确定这是可能的。从NextJS Slack频道获得帮助后,我被告知
"Pages get rendered client side with next/link
And body is not touched after server side rendering"
我将尝试将内容包裹在我生成的另一个标签中,并尝试改变它。
我发现的最干净的解决方案不是声明性的,但效果很好:
import Head from "next/head"
class HeadElement extends React.Component {
componentDidMount() {
const {bodyClass} = this.props
document.querySelector("body").classList.add(bodyClass || "light")
}
render() {
return <Head>
{/* Whatever other stuff you're using in Head */}
</Head>
}
}
export default HeadElement
使用此头部组件,您将进入"黑暗"或" Light"(遵循问题的示例光/黑暗主题(,作为页面中的BodyClass Prop。
截至当前下一个(10(和react(17(版本,如果您想从页面上更改身体类,则可以这样做:
// only example: maybe you'll want some logic before,
// and maybe pass a variable to classList.add()
useEffect( () => { document.querySelector("body").classList.add("home") } );
请注意,使用效果是钩子,因此仅在现代功能组件而不是类的钩子中使用。
可以使用使用效果挂钩代替"旧" componentdidmount生命周期。
https://reactjs.org/docs/hooks-effect.htmlhttps://reactjs.org/docs/hooks-overview.htmlhttps://reactjs.org/docs/components-and-props.html
直接访问下一个js上body
标签的唯一方法是通过_document.js
文件,但是该文件是文档中所述的服务器端。
我建议的工作是直接从组件访问body
标签。示例:
const handleClick = (e) => {
document.querySelector('body').classList.toggle('dark')
}
<div onClick={handleClick}>Toggle</div>
不幸的是,next/head
不允许像React头盔那样指定身体类:
<Helmet>
<body className="foo"/>
</Helmet>
幸运的是,您可以在_document.js
内使用this.props.__NEXT_DATA__.props.pageProps
来访问页面道具,并使用它们在<body>
元素上设置类:
import Document, { Html, Head, Main, NextScript } from 'next/document';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
const pageProps = this.props?.__NEXT_DATA__?.props?.pageProps;
console.log('pageProps => ', pageProps);
return (
<Html>
<Head />
<body className={pageProps.bodyClassName}>
<Main />
<NextScript />
</body>
</Html>
);
}
}
更多信息。
我为我的情况提出了解决方案,而我不需要很多独特的身体类是创建一个称为bodyclass.js的组件,并将该组件导入我的layout.js。组件。
BodyClass.js
import { Component } from 'react';
class BodyClass extends Component {
componentDidMount() {
if (window.location.pathname == '/') {
this.setBodyClass('home');
} else if (window.location.pathname == '/locations') {
this.setBodyClass('locations');
}
}
setBodyClass(className) {
// remove other classes
document.body.className ='';
// assign new class
document.body.classList.add(className);
}
render() {
return null;
}
}
export default BodyClass;
layout.js
import Header from './Header';
import Footer from './Footer';
import BodyClass from '../BodyClass';
const Layout = ({ children }) => {
return (
<React.Fragment>
<BodyClass />
<Header />
{children}
<Footer />
</React.Fragment>
)
}
export default Layout;
直接,这是不可能的。但是,通过另一种方式,您可以使用诸如tailwind之类的框架,然后将类直接插入CSS。
在这里使用tailwind的示例:
.dark {
background-color: black;
color: white;
}
body {
@apply dark
}
这并不是您要寻找的答案,但是我能够通过通过组件传递道具来在功能上完成相同的事情,然后在顶级元素上更新一类包裹我的应用程序中的所有内容,并坐在下面。这样,每个页面都可以拥有自己的唯一类,并且操作与我使用身体类的方式相同。
这是我通过道具的地方
<Layout page_title={meta_title} page_desc={meta_desc} main_class={'contact_page'}>
这是我在布局组件中使用它的地方:
<main className={props.main_class}>
<Header page_title={props.page_title} page_desc={props.page_desc} />
{props.children}
<Footer />
</main>
这是我的 CSS仅解决方案:
(我首先查看https://stackoverflow.com/a/66358460/729221,但这感觉太复杂了,无法更改一些样式。(
(这使用了尾风CSS,但不需要。(
index.css:
body:has(#__next .set-bg-indigo-50-on-body) {
@apply bg-indigo-50;
}
layout.tsx:
//…
return (
<div className="set-bg-indigo-50-on-body">{children}</div>
)
只要div
是<div id="__next">
的直接父,这将起作用。否则,您需要更新CSS :has
-RULE。
已经提到的答案是不必要的复杂,就像以下
一样简单在下面创建一个CSS文件
src/styles/global.css
body {
/* your styles here */
}
在src/pages/_app.tsx
中导入创建的CSS文件。
import '../styles/global.css'