提问人:nicoiscoding 提问时间:9/13/2023 最后编辑:nicoiscoding 更新时间:9/22/2023 访问量:445
在 astro 中使用 viewtransition 的深色模式
Using viewtransition for dark mode in astro
问:
我正在尝试在我的 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 并非如此
答:
您是否还实现了 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 在转换之间保持状态。
评论
transition:persist
<ViewTransitions />
baseHead.astro
我已经解决了这个问题,这是代码:
// 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
评论
js <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>