📜  在 ElectronJS 中管理主题

📅  最后修改于: 2021-11-03 10:47:48             🧑  作者: Mango

ElectronJS是一个开源框架,用于使用 HTML、CSS 和 JavaScript 等 Web 技术构建跨平台原生桌面应用程序,这些技术能够在WindowsmacOSLinux操作系统上运行。它将 Chromium 引擎和NodeJS 组合成一个单一的运行时。

为了使桌面应用程序对用户更具吸引力和吸引力,开发人员除了使用CSS 外,还应开发应用程序以使其与本机系统主题兼容。应用程序应提供一项功能,用户可以在其中控制应用程序的外观和感觉,并在运行时动态更改主题。这增强了应用程序的UI并使其与系统环境融为一体。 Electron 提供了一种方法,我们可以使用内置的nativeTheme模块的 Instance 属性和事件来实现这一点。本教程将演示如何使用nativeTheme模块。任何额外的 CSS 应该只应用于本机系统主题,以便为应用程序设计样式。

我们假设您熟悉上述链接中介绍的先决条件。为了让 Electron 正常工作,需要在系统中预装nodenpm

  • 项目结构:

示例:按照ElectronJS中的动态样式中给出的步骤设置基本的 Electron 应用程序。复制文章中提供的main.js文件和index.html文件的样板代码。还要执行package.json文件中提到的必要更改以启动电子应用程序。我们将继续使用相同的代码库构建我们的应用程序。

包.json:

{
  "name": "electron-theme",
  "version": "1.0.0",
  "description": "Themes in Electron",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [
    "electron"
  ],
  "author": "Radhesh Khanna",
  "license": "ISC",
  "dependencies": {
    "electron": "^8.3.0"
  }
}

根据项目结构文件夹中创建的资产,分别创建light.css文件和dark.css文件。我们将在执行期间动态地将这些CSS文件注入到应用程序中。

输出:此时,我们的基本电子应用程序已设置。启动应用程序后,我们应该会看到以下结果。

图形用户界面输出

Electron 中的原生主题: nativeTheme模块用于读取、响应和应用对 Chromium 原生颜色主题的更改。原生系统主题也适用于 Chromium 的原生颜色主题。该模块是Main Process 的一部分。为了在Renderer Process 中导入和使用nativeTheme模块,我们将使用 Electron远程模块。

注意: nativeTheme模块仅支持实例事件和实例属性。它确实有任何与之关联的 Instance 方法。

index.html:启用深色主题和启用浅色主题按钮还没有任何与之相关的功能。要更改此设置,请在index.js文件中添加以下代码。

HTML


       


Javascript
const electron = require("electron");
 
// Importing the nativeTheme module
// using Electron remote
const nativeTheme = electron.remote.nativeTheme;
const path = require("path");
 
console.log("By Default, Dark Theme Enabled - ",
            nativeTheme.shouldUseDarkColors);
console.log("High Contrast Colors - ",
            nativeTheme.shouldUseHighContrastColors);
console.log("Inverted Colors - ",
            nativeTheme.shouldUseInvertedColorScheme);
 
nativeTheme.on("updated", () => {
    console.log("Updated Event has been Emitted");
 
    if (nativeTheme.shouldUseDarkColors) {
        console.log("Dark Theme Chosen by User");
    } else {
        console.log("Light Theme Chosen by User");
    }
});
 
var dark = document.getElementById("dark");
dark.addEventListener("click", () => {
    nativeTheme.themeSource = "dark";
});
 
var light = document.getElementById("light");
light.addEventListener("click", () => {
    nativeTheme.themeSource = "light";
});


Javascript
const electron = require("electron");
 
// Importing the nativeTheme module
// using Electron remote
const nativeTheme = electron.remote.nativeTheme;
const path = require("path");
 
console.log("By Default, Dark Theme Enabled - ",
            nativeTheme.shouldUseDarkColors);
console.log("High Contrast Colors - ",
            nativeTheme.shouldUseHighContrastColors);
console.log("Inverted Colors - ",
            nativeTheme.shouldUseInvertedColorScheme);
 
function loadCSS(load) {
    var head = document.getElementsByTagName("head")[0];
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = path.join(__dirname, "../assets/"
                          + load + ".css");
    head.appendChild(link);
}
 
nativeTheme.on("updated", () => {
    console.log("Updated Event has been Emitted");
 
    if (nativeTheme.shouldUseDarkColors) {
        console.log("Dark Theme Chosen by User");
        console.log("Dark Theme Enabled - ",
                    nativeTheme.shouldUseDarkColors);
 
        loadCSS("dark");
    } else {
        console.log("Light Theme Chosen by User");
        console.log("Dark Theme Enabled - ",
                    nativeTheme.shouldUseDarkColors);
 
        loadCSS("light");
    }
});
 
var dark = document.getElementById("dark");
dark.addEventListener("click", () => {
    nativeTheme.themeSource = "dark";
});
 
var light = document.getElementById("light");
light.addEventListener("click", () => {
    nativeTheme.themeSource = "light";
});


index.js :在该文件中添加以下代码段。

Javascript

const electron = require("electron");
 
// Importing the nativeTheme module
// using Electron remote
const nativeTheme = electron.remote.nativeTheme;
const path = require("path");
 
console.log("By Default, Dark Theme Enabled - ",
            nativeTheme.shouldUseDarkColors);
console.log("High Contrast Colors - ",
            nativeTheme.shouldUseHighContrastColors);
console.log("Inverted Colors - ",
            nativeTheme.shouldUseInvertedColorScheme);
 
nativeTheme.on("updated", () => {
    console.log("Updated Event has been Emitted");
 
    if (nativeTheme.shouldUseDarkColors) {
        console.log("Dark Theme Chosen by User");
    } else {
        console.log("Light Theme Chosen by User");
    }
});
 
var dark = document.getElementById("dark");
dark.addEventListener("click", () => {
    nativeTheme.themeSource = "dark";
});
 
var light = document.getElementById("light");
light.addEventListener("click", () => {
    nativeTheme.themeSource = "light";
});

代码中用到的nativeTheme模块的所有Instance Properties的详细解释如下:

  • nativeTheme.shouldUseDarkColors此实例属性是只读属性。此属性返回一个布尔值,说明系统操作系统或 Chromium 当前是否启用了模式,或者指示它显示主题UI 。要修改此属性(更改应用程序的主题),我们需要使用nativeTheme.themeSource Instance 属性。
  • nativeTheme.shouldUseHighContrastColors此实例属性是只读属性。此实例属性仅在WindowsmacOS上受支持。此属性返回一个布尔值,说明系统操作系统或 Chromium 当前是否启用了高对比度模式,或者被指示显示高对比度主题UI 。不能使用nativeTheme模块直接从代码修改此属性。要修改此属性,用户需要从系统设置中启用高对比度UI
  • nativeTheme.shouldUseInvertedColorScheme此实例属性是只读属性。此实例属性仅在WindowsmacOS上受支持。此属性返回一个布尔值,说明系统操作系统或 Chromium 当前是否启用了反转配色方案,或者指示它在UI 中使用反转配色方案。不能使用nativeTheme模块直接从代码修改此属性。要修改此属性,用户需要从系统设置中启用反转配色方案。
  • nativeTheme.themeSource此实例属性用于更改应用程序的主题。此属性可以在执行期间动态更改。此字符串属性用于覆盖和取代 Chromium 根据系统主题选择在内部使用的值(指定主题)。此属性可以采用以下字符串值之一:
    • system将此实例属性设置为system将删除覆盖值并将所有内容重置为操作系统默认值。这意味着如果 System 主题启用了模式,则 Chromium 将自动将此作为其默认主题并将其应用于 Electron 应用程序。当系统主题启用了灯光模式时,同样的情况也适用。默认情况下, themeSource属性的值为system 。该值与系统的默认操作系统模式一致。
    • 将此实例属性设置为将对应用程序产生以下影响。该值与系统的模式一致。
      • nativeTheme.shouldUseDarkColors Instance 属性将设置为true
      • LinuxWindows上由 Electron 应用程序呈现的任何UI ,包括上下文菜单、开发工具等,都将使用深色主题UI 。输出中也证明了这一点。系统在macOS上呈现的任何UI ,包括菜单、窗口框架等,都将使用深色主题UI
      • 首选颜色方案CSS 查询将匹配模式。
      • Updated Instance 事件将被发出,如代码所示。输出中也演示了相同的内容。
    • light将此 Instance 属性设置为light将对应用程序产生以下影响。该值与系统的Light模式一致。
      • nativeTheme.shouldUseDarkColors Instance 属性将设置为false
      • LinuxWindows上由 Electron 应用程序呈现的任何UI ,包括上下文菜单、开发工具等,都将使用浅色主题UI 。输出中也证明了这一点。系统在macOS上呈现的任何UI ,包括菜单、窗口框架等,都将使用浅色主题UI
      • 首选颜色方案CSS 查询将匹配灯光模式。
      • Updated Instance 事件将被发出,如代码所示。输出中也演示了相同的内容。

代码中使用的nativeTheme模块的Instance Event的详细解释如下:

  • 更新:事件当底层原生 Chromium 主题中的某些属性发生更改时,会发出此实例事件。这意味着任何只读实例属性的值已更改。如上所述,可以通过更改nativeTheme.themeSource属性的值来更改nativeTheme.shouldUseDarkColors属性的值。发出此事件后,我们需要手动检查哪个Readonly属性已更改,因为此 Instance 事件不返回任何 Promise/Callback。

至此,我们应该可以成功的从上面的代码中确定并更改Electron应用的Native Theme了。

输出:

注意:在上面的输出中,系统操作系统主题默认设置为模式,因此nativeTheme.shouldUseDarkColors实例属性返回true 。此外,在重新加载应用程序时,对主题所做的任何更改都将恢复为默认的系统操作系统主题,因为我们没有在应用程序的本地存储中持久化nativeTheme.themeSource Instance 属性的值。

在我们使应用程序成功适应原生系统主题后,我们需要为应用程序动态应用与该主题兼容的相应CSS 。这很重要,因为样式的某些属性不能同时应用于这两个主题。例如,我们不能对模式和模式使用相同的字体颜色。下面的教程将演示如何根据应用的主题动态注入相应的 CSS。

  • dark.css :在该文件中添加以下代码段。
body {
    background-color: darkgray;
    color: white;
}
  • light.css :在该文件中添加以下代码段。
body {
    background-color: lightgray;
    color: black;
}

index.js :对此文件进行以下更改。函数loadCSS(load)根据传递给它的亮或暗字符串值动态地将 CSS 插入到HTML DOM 结构中。我们只是使用appendChild方法将另一个带有相应 CSS 文件和属性的链接标记附加到index.html文档的 head 标记。

Javascript

const electron = require("electron");
 
// Importing the nativeTheme module
// using Electron remote
const nativeTheme = electron.remote.nativeTheme;
const path = require("path");
 
console.log("By Default, Dark Theme Enabled - ",
            nativeTheme.shouldUseDarkColors);
console.log("High Contrast Colors - ",
            nativeTheme.shouldUseHighContrastColors);
console.log("Inverted Colors - ",
            nativeTheme.shouldUseInvertedColorScheme);
 
function loadCSS(load) {
    var head = document.getElementsByTagName("head")[0];
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = path.join(__dirname, "../assets/"
                          + load + ".css");
    head.appendChild(link);
}
 
nativeTheme.on("updated", () => {
    console.log("Updated Event has been Emitted");
 
    if (nativeTheme.shouldUseDarkColors) {
        console.log("Dark Theme Chosen by User");
        console.log("Dark Theme Enabled - ",
                    nativeTheme.shouldUseDarkColors);
 
        loadCSS("dark");
    } else {
        console.log("Light Theme Chosen by User");
        console.log("Dark Theme Enabled - ",
                    nativeTheme.shouldUseDarkColors);
 
        loadCSS("light");
    }
});
 
var dark = document.getElementById("dark");
dark.addEventListener("click", () => {
    nativeTheme.themeSource = "dark";
});
 
var light = document.getElementById("light");
light.addEventListener("click", () => {
    nativeTheme.themeSource = "light";
});

输出:当动态指定 CSS 文件时,我们不会删除之前的 CSS 文件(如果有),因此应用于应用程序的样式包括这两个 CSS 文件。如果我们在任何一个 CSS 文件中遗漏了一个属性,它仍然会在更改主题时应用于应用程序。因此,我们可以先删除链接标签,然后使用 JS 动态重新附加它,或者通过制作相同的副本并简单地更改值来覆盖先前 CSS 文件的所有属性。