Astro:使内联脚本与渲染组件交互

huangapple go评论68阅读模式
英文:

Astro: make an inline script interact with rendered components

问题

所以,我有一个用于切换深色模式的脚本。该脚本将主题偏好保存到本地存储,并相应地对DOM进行修改。HTML中的默认主题是深色。当在本地存储中保存了白色主题偏好时,DOM 在渲染时会出现恼人的闪烁。为了解决这个问题,我按照指南进行操作,并尝试在页面加载前执行主题脚本。这是我的当前 Layout.astro 的示例:

<head>
  <script is:inline>
    // 配置的模式存储在本地存储中
    const isDarkMode = localStorage.getItem('darkMode');

    // 如果 darkMode = 'true',则将主题设置为 'dark'
    const theme = isDarkMode === 'true' ? 'dark' : '';

    // 在html标签上添加dark类以启用深色模式
    document.querySelector("html").className = theme;
   
    // 根据情况更改其他元素
    document.querySelectorAll(".my").className = theme;

  </script>
...
</head>

样式在一个单独的 .css 文件中定义。这是 index.astro 的一部分:

<Layout>
  <Navbar navLinks={navLinks} />

  <Hero />

  <Bar />

  <Foo />

  <Contacts />
</Layout>

问题在于我的 .my-element 元素分散在所有组件中(即 NavbarHero 等)。由于内联脚本在 Layout.astro 中定义,它无法访问组件内部的 .my-element 元素。如果我移除 is:inline,它可以工作,但当然会回到起点。

有没有修复的办法?理想情况下,我需要在应用样式表之前修改与元素关联的类。

英文:

So, I have a script that is used to toggle dark mode. The script saves the theme preference to the local storage and applies the modifications to the DOM accordingly. The default theme in the html is dark. When in the local storage the white theme preference has been saved, the DOM is modified upon rendering with an annoying flickering. To fix that, I followed this guide, and I tried to execute the theme script before the loading of the page. Here is a sample of my current Layout.astro:

<head>
  <script is:inline>
    // The configured mode is stored in local storage
    const isDarkMode = localStorage.getItem('darkMode');

    // Set theme to 'dark' if darkMode = 'true'
    const theme = isDarkMode === 'true' ? 'dark' : '';

    // Put dark class on html tag to enable dark mode
    document.querySelector("html").className = theme;
   
    // Change other elements accordingly
    document.querySelectorAll(".my").className = theme;

  </script>
...
</head>

Styles are defined in a single .css file. And here is part of index.astro

<Layout>
  <Navbar navLinks={navLinks} />

  <Hero />

  <Bar />

  <Foo />

  <Contacts />
</Layout>

The problem is that my .my-element elements are scattered in all the components (i.e., Navbar, Hero, etc...). Since the inline script is defined in Layout.astro, it can't access the .my-element elements inside the components. If I remove is:inline, it works, but of course I come back to the starting point.

Is there a way to fix? Ideally, I'd need to modify the classes associated to the elements before the stylesheet is applied.

答案1

得分: 2

在这种情况下,你可能想要更改图标组件的工作方式。你可以使用与 HTML 元素上设置的相同类名来改变它们的样式。

我不确定你当前的样式是什么样子,但如果它们类似于 .icon.light { ... },它们可以变成 .light .icon { ... }(这第二种情况中的空格很重要!)

此外,如果你正在使用 Astro 的范围化 CSS 编写这些样式,你需要明确地说明 light 类是来自图标组件外部的,使用 :global() 包裹 HTML 元素上的类:

---
// Icon.Astro
---
<svg class="icon">...</svg>

<style>
.icon {
  /* dark styles */
}

:global(.light) .icon {
  /* light styles */
}
</style>
英文:

In this case, you probably want to change how your icon components work. You can use the same class name set on the html element to change their styling.

I'm not sure what your styles look like currently but if they're something like .icon.light { ... } they could become .light .icon { ... } (the space in this second one is important!)

Additionally, if you're writing these styles using Astro's scoped CSS, you'll need to explicitly say that the light class comes from outside the icon component by using :global() around the class on the html element:

---
// Icon.Astro
---
<svg class="icon">...</svg>

<style>
.icon {
  /* dark styles */
}

:global(.light) .icon {
  /* light styles */
}
</style>

huangapple
  • 本文由 发表于 2023年4月17日 21:17:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76035593.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定