暗模式复选框输入仅在第二次单击时被选中
Darkmode checkbox input get checked only from the second click
当 运行 在浏览器上时,activates/disactivates 暗模式下的开关从第一次点击开始,但 仅从 秒点击
** 最初我只使用了 checked
属性,后来添加了 checked
属性来尝试解决问题(如您所见-它没有帮助)。
如果 JavaScript 仅处理 checked
属性,它的作用也相同。
目的是让它在多页面站点中工作(因此 localStorage
参与)。
我不明白为什么会这样。
有什么建议吗?
全部-pages.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>
将您的 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');
}
}
如果我理解正确,您遇到的问题是花哨的复选框在第一次单击时似乎已被选中,但将 类 切换到 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
函数,现在只有在没有 MouseEvent/Click 时才会以编程方式选中/取消选中 checkbox
。还调整了 CSS 以使用变量,以便在需要时可以通过编程方式快速修改布局。
好的。我明白你的意思了。请试试这个:
<!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>
一些修改解决了这个问题。
稍作修改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;
- 我更改了
localStorage.getItem('dark')
值以供 isDark
变量接受
- 我使用
.defaultChecked
而不是 .checked
作为输入。
- 我让
.addEventListnter()
由 darkCheckbox
而不是 switchBtn
触发(这就是为什么我在 CSS 上使用 z-index: 100
来带来输入到前面)。
当 运行 在浏览器上时,activates/disactivates 暗模式下的开关从第一次点击开始,但 仅从 秒点击
** 最初我只使用了 checked
属性,后来添加了 checked
属性来尝试解决问题(如您所见-它没有帮助)。
如果 JavaScript 仅处理 checked
属性,它的作用也相同。
目的是让它在多页面站点中工作(因此 localStorage
参与)。
我不明白为什么会这样。
有什么建议吗?
全部-pages.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>
将您的 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');
}
}
如果我理解正确,您遇到的问题是花哨的复选框在第一次单击时似乎已被选中,但将 类 切换到 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
函数,现在只有在没有 MouseEvent/Click 时才会以编程方式选中/取消选中 checkbox
。还调整了 CSS 以使用变量,以便在需要时可以通过编程方式快速修改布局。
好的。我明白你的意思了。请试试这个:
<!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>
一些修改解决了这个问题。
稍作修改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;
- 我更改了
localStorage.getItem('dark')
值以供isDark
变量接受 - 我使用
.defaultChecked
而不是.checked
作为输入。 - 我让
.addEventListnter()
由darkCheckbox
而不是switchBtn
触发(这就是为什么我在 CSS 上使用z-index: 100
来带来输入到前面)。