2

在浏览器上运行时,下面的开关会在第一次单击时激活/禁用暗模式,但仅在第二次单击时才会选中/取消选中。

**最初我checked只使用了该属性,后来添加了该checked属性来尝试解决问题(如您所见 - 它没有帮助)。checked在 JavaScript仅处理属性的情况下,它的行为也相同。

目的是让它在多页站点中工作(因此参与localStorage)。

我不明白为什么会这样。

有什么建议么?

all-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();

样式.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);
}

索引.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>
4

4 回答 4

1

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

    <!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>
于 2021-04-07T21:41:48.010 回答
1

如果我理解正确,您在第一次单击时似乎检查了花哨的复选框,但将类切换到 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>

修改了功能,现在仅在没有 MouseEvent/Click 时才darkMode以编程方式进行检查/取消检查。checkbox还调整了 CSS 以使用变量,以便可以在需要时以编程方式快速修改布局。

于 2021-04-07T13:42:15.460 回答
0

将您的 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');
    }
}
于 2021-04-07T10:25:00.697 回答
0

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

稍微修改的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, not触发的switchBtn(这就是我z-index: 100在 CSS 上使用的原因,将输入带到前面)。
于 2021-04-08T16:08:33.673 回答