Vuejs单页应用程序动态主题

5
我有一个用Vuejs构建的单页应用程序,我想添加用户可切换的动态主题功能。用户可以在某个地方点击一个“亮色”或“暗色”主题选项,整个应用程序会立即更新。我还希望所有我的“theme”scss文件都是本地的。
这个答案在这里 是目前为止我找到的最接近的答案,但主题不是本地的。
const themes = {
  flatly: "https://bootswatch.com/4/flatly/bootstrap.min.css",
  materia: "https://bootswatch.com/4/materia/bootstrap.min.css",
  solar: "https://bootswatch.com/4/solar/bootstrap.min.css"
};

如果我能想出如何使用本地主题文件使这个答案有效,那就太好了,但是将链接路径替换为本地路径并不能起作用。
const themes = {
  dark: "dark-theme.scss",
  light: "light-theme.scss"
};

我怀疑这不起作用是因为Webpack或其他编译问题,导致scss文件未被包含。

我发现,如果我在index.html中添加以下内容,可以使我的主题文件出现在客户端源代码中: <link rel="stylesheet" type="text/css" href="<%= BASE_URL %>dark-theme.scss"> 但是我不知道如何在应用程序中引用它。也许像 http://localhost:8080/dark-theme.scss 这样的链接?但是我认为这在生产环境中不起作用(在本地也不行)。

我还看过:

  • 这个,它是与上面链接的答案类似的想法,并遇到了类似的问题
  • 这个,它只有scss变量,不能为类添加属性,例如
  • 这个,我认为它不是一个非常干净的解决方案,因为它要求所有组件都知道主题等信息

我还尝试过在我的 main.ts 文件中做类似于 import "@/path/to/theme.scss"; 的事情,它确实可以工作,但是我不知道如何利用它来使主题可切换。它只添加了一个如下所示的元素到我的头部,其中没有id或class,因此我无法有效地查询它以切换它。使用 require 也会产生类似的结果。

<style type="text/css" >
  ...
</style>

2
几周前我和一位客户遇到了类似的问题。在我看来,实现这个最好的方法是像您在 main.ts 中提到的那样导入两个主题,然后使用JavaScript方法来提供媒体查询无法提供的功能:也就是在不支持它们的浏览器上。现在已经是凌晨3点,但我会在明天关注您的问题和可能的答案! - Federico Moretti
1
@FedericoMoretti 谢谢,我很想看到这个问题的答案。如果我的帖子有任何歧义,让我知道我可以澄清。 - Montana
2个回答

2

main.ts:

import "@/path/to/dark-theme.scss"
import "@/path/to/light-theme.scss"

dark-theme.scss:

body.dark {
  /* rest of the theme */
}

light-theme.scss:

body.ligh {
  /* rest of the theme */
}

index.html(或者根据本地存储或操作系统模式从main.ts中注入它):

<body class="light">

您的交换机放在哪里:

methods: {
  toggleTheme() {
    document.body.classList.toggle('dark')
    document.body.classList.toggle('light')
  }
}

1
这似乎运行良好。我仍然希望不需要 body.dark,而是只需在根级别拥有一个包含所有 CSS 的 scss 文件,但这似乎完全可接受。感谢您的回答。 - Montana

2

我想到了一个技巧,您可以使用它来创建两个空组件,如下所示:

这些组件是与您的主题相关的。请按照以下步骤操作:

<template><div></div></template>
<script>export default {name: 'DarkTheme'}</script>
<style>
  @import "~@/path/to/theme.scss"
</style>

现在您的应用程序可以像这样在这两个组件上使用v-if:

<dark-theme v-if="theme == 'dark'"/>
<light-theme v-if="theme == 'light'"/>

PS:此代码未经测试


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接