在 astro 中使用 viewtransition 的深色模式

Using viewtransition for dark mode in astro

提问人:nicoiscoding 提问时间:9/13/2023 最后编辑:nicoiscoding 更新时间:9/22/2023 访问量:445

问:

我正在尝试在我的 astro 项目中实现新的 viewtransition,问题是我已经找到了有关如何在 chaging 路由时修复暗模式问题的文档,但我使用的代码略有不同,因此它不起作用,我的代码:

  // Get the theme toggle input
  const themeToggle: HTMLInputElement = document.querySelector(
    '.theme-switch input[type="checkbox"]'
  );

  // Get the current theme from local storage
  const currentTheme = localStorage.getItem("theme");

  // If the current local storage item can be found
  if (currentTheme) {
    // Set the body data-theme attribute to match the local storage item
    document.documentElement.setAttribute("data-theme", currentTheme);

    // If the current theme is dark, check the theme toggle
    if (currentTheme === "dark") {
      themeToggle.checked = true;
    }
  }

  // Function that will switch the theme based on the if the theme toggle is checked or not
  function switchTheme(e) {
    if (e.target.checked) {
      document.documentElement.setAttribute("data-theme", "dark");
      localStorage.setItem("theme", "dark");
    } else {
      document.documentElement.setAttribute("data-theme", "default");
      localStorage.setItem("theme", "default");
    }
  }

  // Add an event listener to the theme toggle, which will switch the theme
  themeToggle.addEventListener("change", switchTheme, false);
  document.addEventListener("astro:after-swap", switchTheme, false);
  /* TOGGLE  */
  .theme-switch-wrapper {
    margin-inline: 20px;
    display: inline-block;
    /* justify-content: flex-end; */
    /* align-items: center; */
  }

  .theme-switch {
    display: inline-block;
    height: 34px;
    position: relative;
    width: 60px;
  }

  .theme-switch input {
    display: none;
  }

  .slider {
    background-color: #dddddd;
    bottom: 0;
    cursor: pointer;
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
    transition: 0.4s;
    border-radius: 34px;
  }

  .slider:before {
    background-color: #fff;
    bottom: 4px;
    content: "";
    height: 26px;
    left: 4px;
    position: absolute;
    transition: 0.4s;
    width: 26px;
    border-radius: 50%;
  }

  input:checked + .slider {
    background-color: #8758ff;
  }

  input:checked + .slider:before {
    transform: translateX(26px);
  }

  .slider svg {
    color: #222;
    position: absolute;
    transition: opacity 0.2s ease 0s, transform 0.35s ease 0s;
    pointer-events: none;
  }

  .feather-moon {
    opacity: 0;
    left: 9px;
    bottom: 9px;
    transform: translateX(4px);
  }

  .feather-sun {
    opacity: 1;
    right: 10px;
    bottom: 9px;
    transform: translateX(0px);
  }

  input:checked + .slider .feather-moon {
    opacity: 1;
    transform: translateX(0);
  }

  input:checked + .slider .feather-sun {
    opacity: 0;
    transform: translateX(-4px);
  }
<div class="theme-switch-wrapper py-2 mt-1">
  <label class="theme-switch" for="checkbox">
    <input type="checkbox" id="checkbox" />
    <div class="slider">
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="16"
        height="16"
        viewBox="0 0 24 24"
        fill="#FCD53F"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
        class="feather feather-sun"
      >
        <circle cx="12" cy="12" r="5"></circle>
        <line x1="12" y1="1" x2="12" y2="3"></line>
        <line x1="12" y1="21" x2="12" y2="23"></line>
        <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
        <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
        <line x1="1" y1="12" x2="3" y2="12"></line>
        <line x1="21" y1="12" x2="23" y2="12"></line>
        <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
        <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
      </svg>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="16"
        height="16"
        viewBox="0 0 24 24"
        fill="#FCD53F"
        stroke="currentColor"
        stroke-width="2"
        stroke-linecap="round"
        stroke-linejoin="round"
        class="feather feather-moon"
      >
        <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
      </svg>
    </div>
  </label>
</div>

所以问题是我正在为项目使用复选框,我见过的大多数项目都使用带有 viewtransitions 的暗模式,它们使用按钮,但我认为我的问题是,当我使用复选框的更改方法时,以及我正在使用的函数,它是为在复选框更改状态时使用的, 但要使暗模式按钮持久化,我必须使用这个 EventListener:

  document.addEventListener("astro:after-swap", switchTheme, false);

因为它不是由复选框触发的,所以它不起作用,这些是我的想法,但我不知道如何解决它,所以请帮助我。

真正的问题是该按钮有效,但是当我更改路由时,它会转到默认主题,但复选框仍处于打开状态,因此本应持久化的 localstorage 并非如此

javascript html astro astrojs 视图-转换-api

评论

0赞 tjex 9/13/2023
您能否链接您在问题中找到并提到的修复程序的文档?
0赞 nicoiscoding 9/13/2023
@tjex 这是 Astro 文档的代码:Astro 这是 YouTube 上某人的代码:GitHubjs <script> const setDarkMode = () => { if (localStorage.darkMode) { document.documentElement.dataset.dark = ''; } }; // Runs on initial navigation setDarkMode(); // Runs on view transitions navigation document.addEventListener('astro:after-swap', setDarkMode); </script>

答:

0赞 tjex 9/13/2023 #1

您是否还实现了 html 元素本身?transition:persist

概述如下: https://docs.astro.build/en/guides/view-transitions/#maintaining-state

与您发布的 github 存储库相关的视频也谈到了它: https://youtu.be/9T4N0cIlBUE?feature=shared&t=287

transition:persist告诉 Astro 在转换之间保持状态。

评论

0赞 nicoiscoding 9/14/2023
是的,我已经实现了它,但它并没有解决问题,我在包含主题组件的容器中实现了它,导航栏
0赞 tjex 9/14/2023
嗯,是的,我也尝试在我的网站上实现它,但实际上破坏了整个过渡功能(页面像往常一样导航,尽管闪光灯更亮......不过,我的配色方案确实存在。你可以在这里检查它,以防它给你一些线索。我设置了 关于为什么会发生您的问题......我没有想法:(transition:persist<ViewTransitions />baseHead.astro
0赞 nicoiscoding 9/14/2023 #2

我已经解决了这个问题,这是代码:

  // Get the theme toggle input
  const themeToggle: HTMLInputElement = document.querySelector(
    '.theme-switch input[type="checkbox"]'
  );

  // Get the current theme from local storage
  const currentTheme = localStorage.getItem("theme");

  // If the current local storage item can be found
  if (currentTheme) {
    // Set the body data-theme attribute to match the local storage item
    document.documentElement.setAttribute("data-theme", currentTheme);

    // If the current theme is dark, check the theme toggle
    if (currentTheme === "dark") {
      themeToggle.checked = true;
    }
  }

  function switchTheme() {
    if (themeToggle.checked) {
      document.documentElement.setAttribute("data-theme", "dark");
      localStorage.setItem("theme", "dark");
    } else {
      document.documentElement.setAttribute("data-theme", "default");
      localStorage.setItem("theme", "default");
    }
  }

  // Add an event listener to the theme toggle, which will switch the theme
  themeToggle.addEventListener("change", switchTheme, false);
  document.addEventListener("astro:after-swap", switchTheme);

我通过更改 switchTheme 函数来修复它,以便它检查 themeToggle 变量,而不是 eventlistener 触发的事件,这样现在它适用于交换 eventlistener 后的 astro