500窗口未定义nuxt3和composition api

问题描述 投票:0回答:3

我想检测用户

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 加载后发生变化

重要注意事项如下:

  • 此页面应在服务器端呈现
  • 我应该在 dom 加载之前检测
    prefers-color-scheme

我知道服务器无法访问该窗口,但是我可以根据系统的模式向服务器发送一些内容并在获取 HTML 文档之前设置

data-mode
属性吗?

javascript node.js vue.js vuejs3 nuxt3.js
3个回答
2
投票

正如写在这里,你不能将多个东西作为根节点(所以将它们包装成

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 配合使用


1
投票

解决方案是在

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')
  }
}

0
投票

使用 import.meta.client。指定模式。

<script setup>

if(import.meta.client){
  window...
}

</script>
© www.soinside.com 2019 - 2024. All rights reserved.