JavaScript 编码原则 | 青训营

79 阅读2分钟

一、如何写好JavaScript?

推荐书籍:JavaScript(犀牛书)、JavaScript The Good Parts(语言精髓)

写好JS的一些原则

1.各司其职:让HTML、CSS和JavaScript 职能分离

HTML负责结构

CSS负责表现

JavaScript 负责行为

例如:如今有很多页面有深色和浅色模式,可以随机切换。实现这个可以单独使用HTML和CSS来编写,但是不便于阅读。

2.组件封装:好的UI组件具备正确性、扩展性、复用性

3.过程抽象:应用函数式编程思想

二、组件封装

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

例子:用原生JS写一个电商网站的轮播图,该怎么实现?

1.结构

轮播图是一个典型的列表结构,可以使用ul来实现

image.png 2.表现

  • 使用CSS绝对定位将图片重叠在同一个位置
  • 轮播图切换的状态使用修饰符(modifier)
  • 轮播图的切换动画使用CSS transition

image.png 3.行为-控制流

  • 使用自定义事件来解耦
class Slider {
    constructor(id) {
        this.container = document.getElementById(id);
        this.items = this.container.querySelectorAll('.slider-list__item, .slider-lise__item--selected');
        this.cycle = cycle;

        const controller = this.querySelector('.slider-list__control');
        if (controller) {
            const buttons = controller.querySelectorAll('.slider-list__control-buttons, ..slider-list__control-buttons--selected');
            controller.addEventListener('mouseover', evt => {
                const idx = Array.from(buttons).indexOf(evt.target);
                if (idx >= 0) {
                    this.sliderTo(idx);
                    this.stop();
                }
            });

            controller.addEventListener('mouseout', evt => {
                this.start();
            });

            this.container.addEventListener('slide', evt => {
                const idx = evt.detail.index;
                const selected = controller.querySelector('.slider-list__control-buttons--selected');
                if (selected) selected.className = 'slider-list__control-buttons';
                buttons[idx].className = 'slider-list__control-buttons--selected';
            });
        }

        const previous = this.container.querySelector('.slide-list__previous');
        if (previous) {
            previous.addEventListener('click', evt => {
                this.stop();
                this.sliderPrevious();
                this.start();
                evt.preventDefault;
            });
        }

        const previous = this.container.querySelector('.slide-list__next');
        if (previous) {
            previous.addEventListener('click', evt => {
                this.stop();
                this.sliderNext();
                this.start();
                evt.preventDefault;
            });
        }
    }
    getSelectedItem() {
        const selected = this.container
            .querySelector('.slider-list__item--selected');
        return selected;
    }
    getSelectedItemIndex() {
        return Array.from(this.items).indexOf(this.getSelectedItem());
    }
    sliderTo(idx) {
        const selected = this.getSelectedItem();
        if (selected) {
            selected.className = 'slider-list__item';
        }
        const item = this.items[idx];
        if (item) {
            item.className = 'slider-list__item--selected';
        }
        const detail = { index: idx }
        const event = new CustomEvent('slide', { bubbles: true, detail })
        this.container.dispatchEvent(event)
    }
    sliderNext(){
        const currentIdx = this.getSelectedItemIndex();
        const nextIdx = (currentIdx + 1) % this.items.length;
        this.sliderTo(nextIdx);
    }
    sliderPrevious() {
        const currentIdx = this.getSelectedItemIndex();
        const previousIdx = ((this.items.length) + currentIdx - 1)
            % this.items.length;
        this.sliderTo(previousIdx);
    }
    start() {
        this.stop();
        this._timer = setInterval(() => this.sliderNext(), this.cycle);
    }
    stop() {
        clearInterval(this._timer);
    }
}
const slider = new Slider('slider');
slider.start();

基本方法

  • 结构设计
  • 展示效果
  • 行为设计 -API Event

重构:插件化

解耦

  • 将控制元素抽取成插件
  • 插件与组件之间通过依赖注入方式建立联系

二、个人总结

此次课程,我明白了结构、表现、行为的分离是我们练习的时候需要注意的,如果将三者混在一起使用,会影响其他合作者来阅读,各司其职可以让代码更清晰,更专业。轮播图中有动态的行为,有状态绑定的过程,一般使用控制流来实现。三者也可以写在同一个文件里,最后生成的时候是各司其事、单独表现的。