环境
makefile
node: v20.12.2,
"nuxt": "^3.11.2",
"vue": "^3.4.27",
所有案例均基于 nuxt3
随机数
html
<template>
<div>
<h3>nuxt3 渲染上的不一致</h3>
<div>
<div v-for="item in colors">{{ item }}</div>
</div>
</div>
</template>
<script setup>
const colors = ref([]);
function generateRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
for (let i = 0; i < 5; i++) {
colors.value.push(generateRandomColor());
}
</script>
看代码上没问题,放 SPA
里面 也不会有任何问题,但是放nuxt3/SSR框架
里面,就会出现 服务端渲染和客户端渲染不一致问题
scss
Hydration text content mismatch on (水合不匹配)
... 某一个组件
- rendered on server: #047FC3 服务端渲染,得到的第一项的值是 #047FC3
- expected on client: #1E87BA 客户端的时候,重新运行,变成了 #1E87BA
造成了,服务端和客户端渲染内容不一致, nuxt3 会以 客户端渲染
为主, 所以我们看到的结果是: #1E87BA
。

解决办法:
- 将数据定死,就N个, 不管页面如何刷新
colors
始终是那些数据
js
const colors = ref([
"xxxx",
"1111"
])
- 从
server
中取数据
html
<template>
<div>
<h3>nuxt3 渲染上的不一致</h3>
<div>
<div v-for="item in colors">{{ item }}</div>
</div>
</div>
</template>
<script setup>
const colors = ref([]);
const res = await useFetch('/api/getColors')
colors.value = res.data.value
</script>
server/api/getColors.ts
js
function generateRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
export default defineEventHandler(() => {
let list = []
for (let i = 0; i < 5; i++) {
list.push(generateRandomColor());
}
return list
})

从 network
中看这个页面的字符串内容,从 api 接口
中取值,是都拼接好了结果的。

- 将取数的逻辑放在
onMounted
里面 从 客户端去取数据,填充数据,这样就不会造成服务端与客户端生成的结果不一致的警告
html
<template>
<div>
<h3>nuxt3 渲染上的不一致</h3>
<div>
<div v-for="item in colors">{{ item }}</div>
</div>
</div>
</template>
<script setup>
const colors = ref([]);
function generateRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
onMounted(() => {
for (let i = 0; i < 5; i++) {
colors.value.push(generateRandomColor());
}
});
</script>