在生命周期中
ngOnInit
我尝试向页面添加一个元素。所以我使用 Renderer2
,创建一个新元素并添加它。问题很简单。该项目被创建两次。请注意,我在 console.log
中有一个 ngOnInit
,并且我在控制台中只收到了一份日志。我必须假设 ngOnInit
并没有真正执行两次。
我尝试在 stackblitz 中重现该问题,但不能...这是代码:https://stackblitz.com/edit/stackblitz-starters-r5psb2?file=src%2Fmain.ts
因此,我尝试使用 IDE(与代码)在空项目中重现该问题,在这种情况下,我遇到了问题。所以我的代码与 stackblitz 中的代码相同,但结果是 2 个
p
元素而不是 1.
请注意,如果我查看页面源代码,我只得到 1 个 p 元素,而在 DOM 中,有 2 个主题。这是页面来源:
<!DOCTYPE html><html lang="en"><head>
<script type="module" src="/@vite/client"></script>
<meta charset="utf-8">
<title>Issue</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.css"></head>
<body><!--nghm-->
<app-root _nghost-ng-c1098833243="" ng-version="17.3.1" ngh="0" ng-server-context="ssr"><p _ngcontent-ng-c1098833243="">some text</p></app-root>
<script src="polyfills.js" type="module"></script><script src="main.js" type="module"></script>
<script id="ng-state" type="application/json">{"__nghData__":[{}]}</script></body></html>
我认为如果问题没有出现在 stackblitz 中,则它来自我的设置。我尝试禁用 ssr,但它不起作用(即使它起作用,它也很糟糕)。
这是启用 SSR 和水合作用的预期行为,因为组件的
ngOnInit
在服务器端调用,生成第一个 <p>
,然后在客户端调用,生成第二个 <p>
。
您可以通过几种方式修复此行为:
export class MyComponent {
constructor(@Inject(PLATFORM_ID) private platform: Object) {}
ngOnInit(): void {
if (!isPlatformServer(this.platform)) { // <-- runs only on the client
/* Code for inserting a node */
}
}
}
从
provideClientHydration()
中删除 app.config.ts
,禁用整个应用程序的水合作用。
使用
ngSkipHydration
属性禁用此特定组件的水合作用
@Component({
/* ... */
host: { ngSkipHydration: 'true' },
/* ... */
})
禁用水合作用后,组件仍然运行 ngOnInit 并在服务器上添加一个
<p>
元素,但在客户端,整个 DOM 在应用程序启动之前被擦除
angular.json
的architect > build > options部分中的以下行来禁用SSR(禁用预渲染是不够的):"prerender": true,
"ssr": {
"entry": "server.ts"
}
在这种情况下,您可能还需要清理一些与 ssr 相关的东西,例如带有
server
后缀的文件。