如何写好JavaScript | 青训营笔记

89 阅读4分钟

这是我参加「第四届青训营 」笔记创作活动的第三天。

今天跟着月影大佬学习了一些有关JavaScript的内容,那么接下来看看有哪些需要注意的点吧。

1. 写好JS的一些原则

  • 各司其职:让HTML、CSS和JavaScript职能分离
  • 组件封装:好的UI组件具备正确性扩展性、复用性
  • 过程抽象:用函数式编程思想

2. 具体应用

2.1 各司其职:深色/浅色模式

当一个页面需要深色和浅色浏览模式,用JS应当如何实现?

2.1.1 my idea

在css代码中写好浅色和深色的样式,类名分别为white、black,在JS中当鼠标点击切换模式的按钮时,获取当前浏览模式的类名,如果当前为white,且切换为black,反之。

 const btn = document.getElementById('modeBtn');
  btn.addEventListener('click', (e) => {
    const body = document.body;
    if(body.className !== 'black') {
      body.className = 'black';
    } else {
      body.className = 'white';
    }
  });

PS :还可直接在js代码中直接修改body.style.color等属性,但在上面所提到的原则中,这样没有各司其职,JS代码直接操作了CSS,应切换状态即可。

2.1.2 大佬优化方案

纯用CSS和HTML,无JS,用 运用CSS的高级功能,使用伪类选择器匹配元素状态。给checkbox设置checked状态,然后设置样式。在lable上用for属性,for的值为checkbox的id,此时点击lable和点击checkbox的作用一样,则切换状态。

  <input id="modeCheckBox" type="checkbox">
  <div class="content">
    <header>
      <label id="modeBtn" for="modeCheckBox"></label>
      <h1>深夜食堂</h1>
    </header>
    <main>
      <div class="pic">
        <img src="https://p2.ssl.qhimg.com/t0120cc20854dc91c1e.jpg">
      </div>
      <div class="description">
        <p>
            这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈
        </p>
      </div>
    </main>
  </div>
 #modeCheckBox {
    display: none;
  }

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

2.1.3 小结

  • HTML/CS/JS各司其职
  • 避免不必要的由JS直接操作样式
  • 可以用class来表示状态
  • 纯展示类交互寻求零JS方案

2.2 组件封装:原生JS写一个轮播图网站

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

2.2.1 my idea

html使用img标签,css使用@keyframes动画,让图片逐渐移动, js代码中使用定时器让图片到时间就切换,修改img中的src。

2.2.2 大佬优化方案1

  1. HTML 轮播图是典型的列表结构,可以使用无序列表ul元素来实现。
<div id="my-slider" class="slider-list">
      <ul>
        <li class="slider-list__item--selected">
          <img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png">
        </li>
        <li class="slider-list__item">
          <img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg">
        </li>
        <li class="slider-list__item">
          <img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg">
        </li>
        <li class="slider-list__item">
          <img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg">
        </li>
      </ul>
    </div>
  1. CSS
  • 使用CSS绝对定位将图片重叠放在同一个位置
  • 轮播图切换的使用状态使用修饰符
  • 轮播与的切换动画使用CSS transition
 #my-slider{
    position: relative;
    width: 790px;
  }

  .slider-list ul{
    list-style-type:none;
    position: relative;
    padding: 0;
    margin: 0;
  }

  .slider-list__item,
  .slider-list__item--selected{
    position: absolute;
    transition: opacity 1s;
    opacity: 0;
    text-align: center;
  }

  .slider-list__item--selected{
    transition: opacity 1s;
    opacity: 1;
  }
  1. JS

使用API

  • getSelectedltem( )得到当前选中的图片元素
  • getSelectedltemIndex( )得到当前选中的图片元素在列表中的下标
  • slideTo( )到特定元素上
  • slideNext( )向下轮播
  • slidePrevious( )向上轮播 定义Slider类,定义以上API
 class Slider{
    constructor(id){
      this.container = document.getElementById(id);
      this.items = this.container
      .querySelectorAll('.slider-list__item, .slider-list__item--selected');
    }
    getSelectedItem(){
      const selected = this.container
        .querySelector('.slider-list__item--selected');
      return selected
    }
    getSelectedItemIndex(){
      return Array.from(this.items).indexOf(this.getSelectedItem());
    }
    slideTo(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';
      }
    }
    slideNext(){
      const currentIdx = this.getSelectedItemIndex();
      const nextIdx = (currentIdx + 1) % this.items.length;
      this.slideTo(nextIdx);
    }
    slidePrevious(){
      const currentIdx = this.getSelectedItemIndex();
      const previousIdx = (this.items.length + currentIdx - 1)
        % this.items.length;
      this.slideTo(previousIdx);  
    }
  }

  const slider = new Slider('my-slider');
  slider.slideTo(3);
控制流
 <a class="slide-list__next"></a>
  <a class="slide-list__previous"></a>
  <div class="slide-list__control">
    <span class="slide-list__control-buttons--selected"></span>
    <span class="slide-list__control-buttons"></span>
    <span class="slide-list__control-buttons"></span>
    <span class="slide-list__control-buttons"></span>
  </div>
  const detail = {index: idx}
  const event = new CustomEvent('slide', {bubbles:true, detail})
  this.container.dispatchEvent(event)

2.2.3 小结

  • 组件设计原则:封装性、正确性、扩展性、复用性
  • 实现组件步骤:结构设计,展现效果,行为设计(API功能、Event控制流)
  • 三次重构:插件化、模板化、抽象化 (可将控制元素抽取成插件,插件与组件之间通过依赖注入方式建立连接,将HTML模块化)

2.3 过程抽象:操作次数限制

用来处理局部细节控制的一些方法,函数式编程思想的基础应用

2.3.1 my idea

用变量值count,初始值为0,每操作一次,count加一,并进行判断是否超过限定值。

2.3.2 大佬优化

使用高阶函数来实现过程抽象,高阶函数是以函数作为返回值和参数,常用作于函数装饰器。

function HOF0(fn) {
    return function(...args) {
      return fn.apply(this, args);
    }
  }

常用高阶函数:Once、Throttle、Debounce、Consumer/2、Iterative 操作次数限制则可使用Once

2.3.3 为什么使用高阶函数

可以提高可维护性

总结

今天讲了很多案例,在实际开发中能够运用,但我基础稍微薄弱,还应多加了解,并掌握一些基本算法。