JavaScript——切换主题色

603 阅读4分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

友情提示:本文并不是单纯的讲解如何切换主题色,而是通过这个例子来给大家阐明写JavaScript的时候要尽量遵守的原则之一。如果单纯的看如何变色这篇文章也许并不是特别好的。

闲话就到这里,现在进入正题。 现在你可以看到一个简单的文字和图片我们希望通过点击小太阳来将其变成夜晚模式

image.png

点击后应该变成这样

image.png

这两个页面的结构以及样式都很简单,相信大家都可以轻而易举的写出来,你会怎么去达到变色效果? html代码在这里。

// 以下为html代码
<header>
        <button id="modeBtn"></button>
        <h4>深夜食堂</h4>
    </header>
    <main>
        <div class="pic">
            <img src="这里随便一个图片">
        </div>
        <div class="description">
            <p>...</p>
        </div>
    </main>
    

版本一(通过JavaScript来直接修改相关样式属性)

const btn = document.getElementById('modeBtn');
        btn.addEventListener('click', (event) => {
            const body = document.body;
            if(event.target.innerHTML == '☀') {
                body.style.backgroundColor = 'black';
                body.style.color = 'white';
                event.target.innerHTML = '☾';
            } else {
                body.style.backgroundColor = 'white';
                body.style.color = 'black';
                event.target.innerHTML = '☀';
            }
        })

我想这个js代码大多数人都写得出来,但要是在面试中或者说工作中写出这种代码就是不合格的。这种代码在没有上下文、注释或者文档的提示下阅读代码的人是很难这段代码的意图的。

版本二(通过JavaScript来修改类名从而改变样式)

btn.addEventListener('click', (event) => {
            const body = document.body;
            if(body.className !== 'night') {
                body.className = 'night';
            } else {
                body.className = '';
            }
        })
//以下为css代码
body.night{
    background-color: black;
    color: white;
    transition: all 1s;
}
#modeBtn::after{
    content: '☀';
}
body.night #modeBtn::after{
    content: '☾';
}
body{
    transition: all 1s;
}

这里我们通过js来修改元素的类名来改变样式,代码可读性直接就上升了很多,阅读代码的人可以容易且清晰的知道这段代码的意图在于改变主题颜色。

版本三(不用JavaScript直接通过css来改变样式)

这里我们要稍微更改一下html

<input id="modeCheckBox" type="checkbox">!!!
    <div class="content">
        <header>
            <label id="modeBtn" for="modeCheckBox"></label>!!!
            <h4>深夜食堂</h4>
        </header>
        <main>
            <div class="pic">
                <img src="图片">
            </div>
            <div class="description">
                <p>...</p>
            </div>
        </main>
    </div>
//以下为css代码
.content {
    transition: all 1s;
}

#modeCheckBox {
    display: none;
}

#modeCheckBox:checked + .content{
    background-color: black;
    color: white;
    transition: all 1s;
}

#modeBtn::after {
    content: '☀';
}

#modeCheckBox:checked + .content #modeBtn::after{
    content: '☾';
}

这里我们只更改了css和html,通过兄弟节点选择器checkbox的伪类来定位整体的内容从而改变样式。

三个版本的比较和最终核心要点

上述三个版本都可以去更改页面的主题样式,但为什么又有优劣之分呢?

书写JavaScript代码有三个我们应该尽量去遵守的设计原则,

  • 各司其职,组件封装,过程抽象

遵循这三个设计原则,我们才可以写出高效、优美、可读性高的代码。而这个文章就旨在讲明各司其职这个原则

各司其职,正如它的名字一样就是自己做尽到所需要的职责,在web开发中html负责页面的结构css负责样式js负责行为,无数的大佬为我们创造了这样的三层模型,让我们可以将结构、样式、行为分离后去关注,在阅读代码的时候也是如此,我们只需要关注自己想要关注的点就可以了。

所以在设计JavaScript代码的时候,如果只是单纯的样式改变我们不应该过多的通过js去操作样式,如果只是改变结构我们不应该过多的通过js去操作结构,若是我们反其道而行之那么在维护代码或者它人阅读代码的时候事情会变得很麻烦。

所以回到这三个版本

  • 第一个版本之所以不合格是因为它通过js来修改了大量的样式属性,既没有做到职责分离也没有做到封装抽象。如果有人去review这一段代码一定会觉得不知所云。
  • 第二个版本是合格的,因为我们只是修改了元素的类名将css样式应用到了元素上,做到了各司其职,但是这样仍然不够完美,因为我们仍然写了js代码
  • 第三个版本是最好的,我们只通过css与html就完成了主题的转换

当然我们要考虑到保存页面的主题颜色,以确保用户下一次进入页面是他曾经保存的主题颜色,所以是不可避免的会有js代码的。

总结(各司其职)

  • html、css、js各司其职
  • 应该避免不必要的由js直接操作样式
  • 可以用class来表示状态
  • 纯展示类交互寻求零js解决方案