暗模式复选框输入仅在第二次单击时被选中



在浏览器上运行时,下面的开关从第一次点击开始激活/取消激活暗模式,只能从第二次点击开始检查/取消检查。

**最初我只使用checked属性,后来添加了checked属性来尝试解决这个问题(正如您所看到的,它没有帮助(。在JavaScript仅处理checked属性的情况下,它的作用也是一样的。

目的是让它在多页网站中工作(因此localStorage调用(。

我不明白为什么会发生这种事。

有什么建议吗?

所有页面.js:

const htmlTag = document.querySelector('html');
const switchBtn = document.querySelector('.slider');
const darkCheckbox = document.querySelector('.dark-cb');
function darkMode() {
if (localStorage.getItem('dark') == 'true') {
darkCheckbox.checked = true;
darkCheckbox.setAttribute('checked', 'checked');
htmlTag.classList.add('dark');
switchBtn.classList.add('dark');
} else {
darkCheckbox.checked = false;
darkCheckbox.removeAttribute('checked');
htmlTag.classList.remove('dark');
switchBtn.classList.remove('dark');
}
}
switchBtn.addEventListener('click', function() {
localStorage.setItem('dark', htmlTag.className.indexOf('dark') == -1);
darkMode();
});

window.onload = darkMode();

style.css:

html {
min-height: 100%;
}
.switch {
position: absolute;
top: 10px;
left: 20px;
width: 60px;
height: 34px;
}

/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}

/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: skyblue;
-webkit-transition: .4s;
transition: .4s;
}
.slider::before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: #FFFF66;
-webkit-transition: .4s;
transition: .4s;
}
input:checked+.slider {
background-color: darkblue;
}
input:focus+.slider {
box-shadow: 0 0 1000px darkblue;
}
input:checked+.slider::before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round::before {
border-radius: 50%;
}
.dark {
filter: invert(1);
}

index.html:

<html lang="en">
<head>
<link href="./style.css" rel="stylesheet" />
</head>
<body>
<nav id="nav-bar">
<label class="switch">
<input type="checkbox" class='dark-cb'>
<span class="slider round" title="light/dark mode"></span>
</label>
</nav>
<script src="all-pages.js"></script>
</body>
</html>

好的。我明白你的意思了。请试试这个:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dark/Light Mode Switch</title>
<style>
:root {
--primary-color: #302AE6;
--secondary-color: #536390;
--font-color: #424242;
--bg-color: #fff;
--heading-color: #292922;
}
[data-theme="dark"] {
--primary-color: #9A97F3;
--secondary-color: #818cab;
--font-color: #e1e1ff;
--bg-color: #161625;
--heading-color: #818cab;
}
html {
min-height: 100%;
}
body {
background-color: var(--bg-color);
color: var(--font-color);
max-width: 90%;
margin: 0 auto;
font-size: calc(1rem + 0.25vh);
}

.switch {
position: absolute;
top: 10px;
left: 20px;
width: 60px;
height: 34px;
}

/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}

/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #044660;
-webkit-transition: .4s;
transition: .5s;
}
.slider::before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: #FFFF66;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: darkblue;
}
input:focus + .slider {
box-shadow: 0 0 1000px darkblue;
}
input:checked + .slider::before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
border-radius: 24px;
}
.slider.round::before {
border-radius: 50%;
}
.dark {
filter: invert(1);
}
</style>
</head>
<body>
<nav id='nav-bar'>
<label class='switch' for="checkbox">
<input type='checkbox' name='checkbox' id="checkbox" class='dark-cb'>
<span class='slider round' title='Enable Dark Mode!'></span>
</label>
</nav>
<div style="margin: 100px">
Testing Dark/Light Mode Switch
</div>

<script>
const toggleSwitch = document.querySelector('.switch input[type="checkbox"]');
function switchTheme(e) {
if (e.target.checked) {
document.documentElement.setAttribute('data-theme', 'dark');
localStorage.setItem('theme', 'dark'); //add this
} else {
document.documentElement.setAttribute('data-theme', 'light');
localStorage.setItem('theme', 'light'); //add this
}
}
const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;
if (currentTheme) {
document.documentElement.setAttribute('data-theme', currentTheme);
if (currentTheme === 'dark') {
toggleSwitch.checked = true;
}
}
toggleSwitch.addEventListener('change', switchTheme, false);
</script>
</body>
</html>

如果我理解正确的话,你会发现第一次点击时出现的花哨复选框有问题,但将类切换到HTML元素等操作很好。为此,我希望以下内容能够证明是有用的。

由于Snippets无法访问localStorage的限制,我无法创建一个snippet来演示,但也许这个jsFiddle将有助于演示

<html lang="en">
<head>
<style>
/* variables */
:root{
--w:2rem;
--h:2rem;
--l:0rem;
--t:0rem;
--r:10rem;

--sw:5rem;
--sh:2rem;

--pt:1rem;
--pl:2rem;
}

html {
min-height: 100%;
}
.switch {
position:absolute;

top:var(--pt);
left:var(--pl);
width:var(--sw);
height:var(--sh);
}

/* Hide default HTML checkbox */
.switch input {
opacity:1;
width:2rem;
height:10rem;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position:absolute;
cursor:pointer;

top:0;
left:0;
right:0;
bottom:0;

background-color:skyblue;
transition:0.4s;
}
.slider::before {
position:absolute;
content:'';

height:var(--h);
width:var(--w);
left:var(--l);
bottom:var(--t);

background-color:#FFFF66;
transition:0.4s;
}
input:checked + .slider {
background-color:darkblue;
}
input:focus + .slider {
box-shadow:0 0 1000px darkblue;
}
input:checked + .slider::before {
transform:translateX( calc( var(--sw) - var(--w) ) );
}

/* Rounded sliders */
.slider.round {
border-radius:var(--r);
}
.slider.round::before {
border-radius:var(--r);
}
.dark {
filter:invert(1);
}

/* debug */
html.dark{
background:gray;
color:white;
}
</style>
</head>
<body>
<nav id='nav-bar'>
<label class='switch'>
<input type='checkbox' name='dark-cb' class='dark-cb'>
<span class='slider round' title='light/dark mode'></span>
</label>
</nav>
<script>

document.addEventListener('DOMContentLoaded',()=>{
const store='darkmode_toggle';
const cn='dark';

const html=document.querySelector('html');
const bttn=document.querySelector('.slider');
const chk=document.querySelector('input[type="checkbox"][name="dark-cb"]');


function darkMode() {
// get the stored value. This will be null if it does not exist.
let i=localStorage.getItem(store);

// set the initial value if null.
if( i==null ){
localStorage.setItem(store,0);
i=Number(localStorage.getItem(store));
}else i=Number(i);


// if `darkMode` was invoked by a `click` event - toggle the saved value
if( typeof( arguments[0] )!='undefined' && arguments[0].type=='click' ){
localStorage.setItem( store, 1 - i );
i=Number(localStorage.getItem(store));
}


// set attributes and classes as appropriate to current state
switch(i){
case 1:
html.classList.add(cn)
bttn.classList.add(cn);

// force the checkbox state on page load only
if( typeof( arguments[0] )=='undefined' )chk.checked=1;
break;
case 0:
html.classList.remove(cn)
bttn.classList.remove(cn);
if( html.classList.length==0 )html.removeAttribute('class');
if( bttn.classList.length==0 )bttn.removeAttribute('class');

// force the checkbox state on page load only
if( typeof( arguments[0] )=='undefined' )chk.checked=0;
break;
}
}

bttn.addEventListener('click', darkMode );
darkMode();

});
</script>
</body>
</html>

修改了darkMode函数,使checkbox的检查/取消检查现在只在没有鼠标事件/单击时发生。还调整了CSS,使其使用变量,以便在需要时可以通过编程快速修改布局。

将darkMode函数更改为以下函数。那么你的问题就解决了!

function darkMode() {
if (localStorage.getItem('dark') === 'false' ) {
darkCheckbox.checked = false;
darkCheckbox.removeAttribute('checked');
htmlTag.classList.remove('dark');
switchBtn.classList.remove('dark');
} else {
darkCheckbox.checked = true;
darkCheckbox.setAttribute('checked', 'checked');
htmlTag.classList.add('dark');
switchBtn.classList.add('dark');
}
}

一些修改解决了这个问题。

稍作修改的CSS:

.switch input {
opacity: 0;
z-index: 100;
cursor: pointer;
width: 52px;
height: 30px;
}

修改JS:

const htmlTag = document.querySelector('html');
const switchBtn = document.querySelector('.slider');
const darkCheckbox = document.querySelector('.dark-cb');
function darkMode() {
if (localStorage.getItem('dark') == 'true') {
darkCheckbox.defaultChecked = true;
htmlTag.classList.add('dark');
switchBtn.classList.add('dark');
} else {
darkCheckbox.defaultChecked = false;
htmlTag.classList.remove('dark');
switchBtn.classList.remove('dark');
}
}
darkCheckbox.addEventListener('click', function() {
let isDark = (localStorage.getItem('dark') == 'true') ? 'false' : 'true';
if (localStorage.getItem('dark') == null) {isDark = 'true';}
localStorage.setItem('dark',isDark);
darkMode();
});
window.onload = darkMode;
  1. 我更改了localStorage.getItem('dark')值以供isDark变量接受
  2. 我使用.defaultChecked而不是.checked作为输入
  3. 我让.addEventListnter()darkCheckbox触发,而不是由switchBtn触发(这就是为什么我在CSS上使用z-index: 100,将输入放在前面(

最新更新