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

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;
  1. 我更改了 localStorage.getItem('dark') 值以供 isDark 变量接受
  2. 我使用 .defaultChecked 而不是 .checked 作为输入。
  3. 我让 .addEventListnter()darkCheckbox 而不是 switchBtn 触发(这就是为什么我在 CSS 上使用 z-index: 100 来带来输入到前面)。