深入理解JavaScript(上)| 青训营

写好JavaScript的原则

image.png
各司其责

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

组件封装

  • 组件设计的原则:封装性、正确性、扩展性、复用性
  • 实现组件的步骤:结构设计、展现效果、行为设计
  • 三次重构
    • 插件化
    • 模板化
    • 抽象化(组件框架)

满足其上面要求的轮播图代码:

class Component{
  constructor(id, opts = {name, data:[]}){
    this.container = document.getElementById(id);
    this.options = opts;
    this.container.innerHTML = this.render(opts.data);
  }
  registerPlugins(...plugins){
    plugins.forEach(plugin => {
      const pluginContainer = document.createElement('div');
      pluginContainer.className = `.${name}__plugin`;
      pluginContainer.innerHTML = plugin.render(this.options.data);
      this.container.appendChild(pluginContainer);
      
      plugin.action(this);
    });
  }
  render(data) {
    /* abstract */
    return ''
  }
}

class Slider extends Component{
  constructor(id, opts = {name: 'slider-list', data:[], cycle: 3000}){
    super(id, opts);
    this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
    this.cycle = opts.cycle || 3000;
    this.slideTo(0);
  }
  render(data){
    const content = data.map(image => `
      
  • ${image}"/>
  • `
    .trim()); return `
      ${content.join('')}
    `
    ; } 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'; } const detail = {index: idx} const event = new CustomEvent('slide', {bubbles:true, detail}) this.container.dispatchEvent(event) } 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); } addEventListener(type, handler){ this.container.addEventListener(type, handler); } start(){ this.stop(); this._timer = setInterval(()=>this.slideNext(), this.cycle); } stop(){ clearInterval(this._timer); } } const pluginController = { render(images){ return `
    ${images.map((image, i) => ` ${i===0?'--selected':''}"> `).join('')}
    `
    .trim(); }, action(slider){ let controller = slider.container.querySelector('.slide-list__control'); if(controller){ let buttons = controller.querySelectorAll('.slide-list__control-buttons, .slide-list__control-buttons--selected'); controller.addEventListener('mouseover', evt=>{ var idx = Array.from(buttons).indexOf(evt.target); if(idx >= 0){ slider.slideTo(idx); slider.stop(); } }); controller.addEventListener('mouseout', evt=>{ slider.start(); }); slider.addEventListener('slide', evt => { const idx = evt.detail.index; let selected = controller.querySelector('.slide-list__control-buttons--selected'); if(selected) selected.className = 'slide-list__control-buttons'; buttons[idx].className = 'slide-list__control-buttons--selected'; }); } } }; const pluginPrevious = { render(){ return ``; }, action(slider){ let previous = slider.container.querySelector('.slide-list__previous'); if(previous){ previous.addEventListener('click', evt => { slider.stop(); slider.slidePrevious(); slider.start(); evt.preventDefault(); }); } } }; const pluginNext = { render(){ return ``; }, action(slider){ let previous = slider.container.querySelector('.slide-list__next'); if(previous){ previous.addEventListener('click', evt => { slider.stop(); slider.slideNext(); slider.start(); evt.preventDefault(); }); } } }; const slider = new Slider('my-slider', {name: 'slide-list', data: ['https://p5.ssl.qhimg.com/t0119c74624763dd070.png', 'https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg', 'https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg', 'https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg'], cycle:3000}); slider.registerPlugins(pluginController, pluginPrevious, pluginNext); slider.start();
    <div id="my-slider" class="slider-list">div>
    
    #my-slider{
      position: relative;
      width: 790px;
      height: 340px;
    }
    
    .slider-list ul{
      list-style-type:none;
      position: relative;
      width: 100%;
      height: 100%;
      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;
    }
    
    .slide-list__control{
      position: relative;
      display: table;
      background-color: rgba(255, 255, 255, 0.5);
      padding: 5px;
      border-radius: 12px;
      bottom: 30px;
      margin: auto;
    }
    
    .slide-list__next,
    .slide-list__previous{
      display: inline-block;
      position: absolute;
      top: 50%;
      margin-top: -25px;
      width: 30px;
      height:50px;
      text-align: center;
      font-size: 24px;
      line-height: 50px;
      overflow: hidden;
      border: none;
      background: transparent;
      color: white;
      background: rgba(0,0,0,0.2);
      cursor: pointer;
      opacity: 0;
      transition: opacity .5s;
    }
    
    .slide-list__previous {
      left: 0;
    }
    
    .slide-list__next {
      right: 0;
    }
    
    #my-slider:hover .slide-list__previous {
      opacity: 1;
    }
    
    
    #my-slider:hover .slide-list__next {
      opacity: 1;
    }
    
    .slide-list__previous:after {
      content: '<';
    }
    
    .slide-list__next:after {
      content: '>';
    }
    
    .slide-list__control-buttons,
    .slide-list__control-buttons--selected{
      display: inline-block;
      width: 15px;
      height: 15px;
      border-radius: 50%;
      margin: 0 5px;
      background-color: white;
      cursor: pointer;
    }
    
    .slide-list__control-buttons--selected {
      background-color: red;
    }
    
    

    过程抽象

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

    深入理解JavaScript(上)| 青训营_第1张图片
    深入理解JavaScript(上)| 青训营_第2张图片

    高阶函数

    • 以函数作为参数
    • 以函数作为返回值
    • 常用于作为函数装饰器

    深入理解JavaScript(上)| 青训营_第3张图片

    常用的高阶函数

    once(一次)

    上面已有例子

    Throttle(节流)

    防止重复调用,设置0.5s的定时器
    https://code.h5jun.com/gale/1/edit?html,css,js,output
    深入理解JavaScript(上)| 青训营_第4张图片

    function throttle(fn, time = 500){
      let timer;
      return function(...args){
        if(timer == null){
          fn.apply(this,  args);
          timer = setTimeout(() => {
            timer = null;
          }, time)
        }
      }
    }
    
    btn.onclick = throttle(function(e){
      circle.innerHTML = parseInt(circle.innerHTML) + 1;
      circle.className = 'fade';
      setTimeout(() => circle.className = '', 250);
    });
    

    Debounce(防抖)

    防止过度调用函数,过大占用性能
    https://code.h5jun.com/wik/edit?html,js,output
    深入理解JavaScript(上)| 青训营_第5张图片

    var i = 0;
    setInterval(function(){
      bird.className = "sprite " + 'bird' + ((i++) % 3);
    }, 1000/10);
    
    function debounce(fn, dur){
      dur = dur || 100;
      var timer;
      return function(){
        clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(this, arguments);
        }, dur);
      }
    }
    
    document.addEventListener('mousemove', debounce(function(evt){
      var x = evt.clientX,
          y = evt.clientY,
          x0 = bird.offsetLeft,
          y0 = bird.offsetTop;
      
      console.log(x, y);
      
      var a1 = new Animator(1000, function(ep){
        bird.style.top = y0 + ep * (y - y0) + 'px';
        bird.style.left = x0 + ep * (x - x0) + 'px';
      }, p => p * p);
      
      a1.animate();
    }, 100));
    

    Consumer

    https://code.h5jun.com/roka/7/edit?js,output

    Iterative(迭代)

    https://code.h5jun.com/kapef/edit?js,output

    编程范式

    • 过程抽象/HOF/装饰器
    • 命令式/声明式

    命令式与声明式

    深入理解JavaScript(上)| 青训营_第6张图片
    例子:
    深入理解JavaScript(上)| 青训营_第7张图片
    https://code.h5jun.com/tuda/2/edit?js,output
    https://code.h5jun.com/nal/3/edit?js,output
    https://code.h5jun.com/foqo/2/edit?js,output

    你可能感兴趣的:(js高级,javascript)