我想检测用户
prefers-color-scheme
并将 data-mode
属性设置为文档根(html),但我不能。
我的
app.vue
代码是这样的:
<template>
<div>
<NuxtLayout />
<NuxtLoadingIndicator color="orange" />
<NuxtPage />
</div>
</template>
<script setup lang="ts">
if (
!("theme" in localStorage) &&
window.matchMedia("(prefers-color-scheme: dark)").matches ) {
document.documentElement.setAttribute("data-mode", "dark");
}
</script>
但是此页面使用SSR,因此我得到localStorage或窗口未定义
我无法在
onBeforeMount
或 onMounted
生命周期中执行此操作,因为颜色在 dom 加载后发生变化
重要注意事项如下:
prefers-color-scheme
值我知道服务器无法访问该窗口,但是我可以根据系统的模式向服务器发送一些内容并在获取 HTML 文档之前设置
data-mode
属性吗?
正如写在这里,你不能将多个东西作为根节点(所以将它们包装成
div
)。
然后,
window is undefined
如这里,这意味着您需要仔细检查您的代码是否在带有process.server
的服务器上运行。
<script>
export default {
created() {
if (process.server) {
// run your thing on the server
}
},
}
</script>
最后,您可能应该使用这个 Nuxt 模块:https://github.com/nuxt-modules/color-mode 满足您的目的,几乎是它的全部目的。
这里也提出了类似的问题,也许它会有所帮助:Nuxt 3 中的暗模式切换器无法与官方 @nuxtjs/color-mode 配合使用
解决方案是在
app.vue
中使用 useHead
函数。在 app.vue 中你应该这样写
<script setup>
useHead({
script: {
children: `
(() => {
const localStorageTheme = localStorage.getItem('theme') || ''
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
(!localStorageTheme || localStorageTheme === 'auto' ? prefersDark : localStorageTheme === 'dark') && document.documentElement.classList.add('dark')
})();
`
}
})
</script>
这将阻止页面的渲染,直到脚本完成执行,因为此脚本标记不会延迟。通常您不想这样做,但对于这种关键的渲染情况来说,这很好,而且它是一个超小的脚本,因此您不会遇到任何问题。
如果您想在单击按钮时切换主题,您可以使用这样的功能
function toggleTheme() {
const active_theme = localStorage.getItem('theme')
if (!active_theme) {
localStorage.setItem('theme', window.matchMedia('(prefers-color-scheme: dark)').matches ? 'light' : 'dark')
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.remove('dark')
}
else {
document.documentElement.classList.add('dark')
}
}
if (active_theme === 'light') {
localStorage.setItem('theme', 'dark')
document.documentElement.classList.add('dark')
}
else if (active_theme === 'dark') {
localStorage.setItem('theme', 'light')
document.documentElement.classList.remove('dark')
}
}
使用 import.meta.client。指定模式。
<script setup>
if(import.meta.client){
window...
}
</script>