如何写好JavaScript | 青训营笔记

78 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天。

这一篇笔记记录了如何遵循工业化、规范化的编程原则写出更好的JS代码。

一、本堂课重点内容

  • JavaScript 编码原则之各司其责
  • JavaScript 编码原则之组件封装
  • JavaScript 编码原则之过程抽象

二、详细知识点介绍

1、JavaScript 编码原则之各司其责

  • 在编写项目的时候,HTML、CSS、JavaScript尽量各做各该做的事情,HTML就负责页面结构,CSS就负责样式渲染,JavaScript就负责交互行为。
  • 在课程中,月影老师从一个切换日间与夜间风格的需求入手,逐步讲解如何一步一步地优化代码,直到达到“各司其责”的目的。
  • 借用YK菌的一句话:“最好的JS就是不写JS”,秉承着这样的理念,我尝试使用纯CSS写了一个包含焦点的轮播图

轮播图设计

  • 页面结构
    • 三个radio按钮和对应的label作为轮播图焦点
<div id="carousel">
      <ul>
        <input type="radio" name="control" checked />
        <input type="radio" name="control" />
        <input type="radio" name="control" />
        <li class="image"><img src="..." alt="" /></li>
        <li class="image"><img src="..." alt="" /></li>
        <li class="image"><img src="..." alt="" /></li>
        <div class="bottom-button">
          <label for="control-1"></label>
          <label for="control-2"></label>
          <label for="control-3"></label>
        </div>
      </ul>
    </div>
  • 基础样式
    • 隐藏radio单选框
    • 焦点框使用绝对定位,固定到轮播图的底端位置,内部元素居中对齐。
    • 焦点设置长宽、背景颜色,通过设置border-radius使其变为圆形。
    • 设置焦点的悬停样式,通过:checked伪类选择器和~兄弟选择器找到被选中的焦点对应的label并修改其样式。
#carousel input[type="radio"] {
    display: none;
}
#carousel .bottom-button {
    position: absolute;
    top: calc(100% - 50px);
    left: 0;
    width: 100%;
    height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
}
.bottom-button label {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: rgba(255, 255, 255, 0.575);
    margin: 0 5px;
    cursor: pointer;
    transition: all 0.3s;
}
.bottom-button label:hover {
    box-shadow: #fff 0 0 5px;
    background-color: #fff;
}
#carousel input[type="radio"]:nth-of-type(1):checked ~ .bottom-button label:nth-child(1),
#carousel input[type="radio"]:nth-of-type(2):checked ~ .bottom-button label:nth-child(2),
#carousel input[type="radio"]:nth-of-type(3):checked ~ .bottom-button label:nth-child(3) {
    background-color: #fff;
}
  • 轮播变换
    • 通过:checked伪类选择器和~兄弟选择器找到被选中的焦点对应的图片并修改其opacity透明度样式,达到轮播的效果。
    • 当然这里只实现了手动轮播的效果,没有实现自动轮播的效果。
#carousel input[type="radio"]:checked ~ li.image {
    opacity: 0;
}
#carousel input[type="radio"]:nth-of-type(1):checked ~ li.image:nth-of-type(1),
#carousel input[type="radio"]:nth-of-type(2):checked ~ li.image:nth-of-type(2),
#carousel input[type="radio"]:nth-of-type(3):checked ~ li.image:nth-of-type(3) {
    opacity: 1;
}
  • 进一步思考
    • 一般的轮播图除了焦点之外通常还会有左右两个按钮,有一个实现的方案是添加多个左右切换的按钮,并设置不同的label对应不同的焦点,然后随着切换改变display值。但是这个方法随着轮播图片的增加而变得繁琐。我还没有想到什么很好的纯CSS实现方法,因此使用js实现。
    • 设置一个当前播放的图片的序号值cur,获取图片数量,然后给左右按钮各绑定一个事件,当点击时当前图片的前/后一张图片所对应的radio设置为checked
    • 在实现了左右切换后,该轮播图还未实现自动轮播的效果。个人认为如果要实现自动轮播的效果,则需要添加更多的js代码以及修改页面html和css样式。
/* 省略页面结构和CSS样式 */
const leftArrow = document.querySelector(".left-arrow");
const rightArrow = document.querySelector(".right-arrow");
const control = document.querySelectorAll('input[name="control"]');
const image = document.querySelectorAll(".image");
let cur = 0;
let imageNum = image.length;
leftArrow.addEventListener("click", () => {
  cur = (cur + imageNum - 1) % imageNum;
  control[cur].checked = true;
});
rightArrow.addEventListener("click", () => {
  cur = (cur + 1) % imageNum;
  control[cur].checked = true;
});

2、JavaScript 编码原则之组件封装

组件是指Web页面上抽出来的一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。

  • 组件封装的基本方法
    • 结构设计
    • 展现效果
    • 行为设计
      • API(功能)
      • Event(控制流)
    • 三次重构
      • 插件化
      • 模板化
      • 抽象化
  • 本节老师所使用的例子也是轮播图,后期可以参考老师的代码,在前一节的基础上进行改进。

3、JavaScript 编码原则之过程抽象

  • 过程抽象能够体现出一定的函数式编程的思想,它能够用来处理一些局部细节的控制
  • 高阶函数
    • 以函数作为参数
    • 返回值为函数
    • 常用于作为函数装饰器
  • 编程范式(声明式更简洁、更具有表现力,因此推荐使用声明式编程)
    • 命令式
    function addOne(arr) {
        const result = [];
        for(let i = 0; i < arr.length; i++) {
            result.push(arr[i] + 1)
        }
        return result;
    }
    
    • 声明式
    const addOne = arr => arr.map(item => item + 1);
    

三、实践练习例子

  • 代码已在详细内容介绍中给出

四、课后个人总结

  • 本章内容偏高阶,需要有很扎实的JavaScript基础,课后需要加强巩固JavaScript基础。

五、引用参考