JS入门 | 青训营

88 阅读4分钟

什么是好JS:

l 代码简洁,可以令其他人更清晰明了的理解相关内容

l 各种功能分离,显示、运算、数据的相关代码分开,HTML/CSS/JS各司其职

l 避免不必要的由JS直接操作的样式、纯展示类尽量寻求零JS方案

从多种角度思考网页的功能实现

代码耦合度:

--结构(html)、表现(CSS)、行为(JS)是否分开?现有的JS代码是否绕过了CSS代码直接改变了网页的表现?尽量使代码各司其职,让各个部分的代码功能清晰明了。

--如果对行为的检测并非必要,则可以不使用JS。e.g.双状态切换的点击事件可以通过在html中设置checkbox来代替JS中的点击listener

image.png

JS基本七种数据类型为:1.String类型,用于表示字符串;2.Number类型,用于表示数字;3.Boolean类型,用于表示真假取值;4.Symbol类型,代表唯一的特征值;5.Undefined类型;6.Null类型;7.Object类型,用于存储数据块。

表达式和语句:表达式指一个为了得到返回值的计算式,而语句是为了完成某种任务而进行的操作。比如 var a = 7 + "2" 是一行赋值语句,其中 7 + "2" 是表达式。

编写过程中遇到的问题

JS放在head中不生效

解决方法:

1.     script代码无法执行是因为DOM元素还未生成,当浏览器下载完JS时会发现item为空,而html页面是在执行了<body>之后才会显示。JavaScript本身就是单线程的,在没有使用两个属性(async和defer)的情况下,只要把script代码块放到<body>下就可以正常执行。

2.     在JS中用window.onload=function(){//JS代码},window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。该方法可以避免因为引用过多的<script>标签而令<body>的结构变得复杂化

e.g.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="./style.css"/>
        <script src="function.js"></script>
    </head>
    <body>
        <div id="my-slider" class="slider-list">
            <ul>
              <li class="slider-list__item">
                <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--selected">
                <img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg"/>
              </li>
            </ul>
        </div>
    </body>
</html>
#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;
  }
class Slider{
   constructor(id){
     this.container = document.getElementById(id);//获取页面元素
     this.items = this.container//将页面元素按id转换为items
     .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);  
   }
 }

window.onload=function(){
  const slider = new Slider('my-slider');
  slider.slideTo(0);
  setInterval(()=>{
    slider.slideNext();
  }, 1000);//每隔一秒执行一次
}

以上代码实现了幻灯片的功能,即每秒切换一次图片,可以看到JS代码中用了window.onload()的方法,在等待html文档执行完毕后再运行,而html中只负责引入外部文件,以降低JS及html的耦合性

监听事件(addEventListener): 对控件的事件进行监听,e.g.定义一个controller控件,当鼠标触碰到控件时会触发JS中的controller.addEventListener('mouseover', evt=>{})功能

插件化:功能解耦

l 将控制元素抽取成插件

l 插件和组件之间通过依赖注入的方式建立联系

当使用JS构建复杂的UI时,可能会令构造函数变得十分复杂,这时可以用注入依赖的方法以降低复杂度

image.png

比如上述图片中的轮播图效果,可以用插件化的方式将导航栏小圆点、前后按钮的功能通过依赖来注入轮播图中,以降低控件和组件的耦合度,让附加的控件脱离class主体而成为独立的功能

function pluginNext(slider){
  const next = slider.container.querySelector('.slide-list__next');
  if(next){
    next.addEventListener('click', evt => {
      slider.stop();
      slider.slideNext();
      slider.start();
      evt.preventDefault();
    });
  }  
}
class Slider{
  registerPlugins(...plugins){
    plugins.forEach(plugin => plugin(this));
  }
  start(){}
  stop(){}
  .
  .
  .
}
const slider = new Slider('my-slider');
slider.registerPlugins(pluginNext);

如果想让该插件功能失效的话在registerPlugins中删除掉pluginNext即可

模板化:改进插件/组件解耦

如果仅仅是插件化,插件及组件的模板仍然需要从html中创建。这样会导致即使删除掉JS中的插件,html中渲染的插件组件仍然存在,模板化的目标为让插件及主体的创建彻底脱离html,让JS负责所有组件的创建,这样子在删除JS中的插件时,不仅能令插件的功能失效,同时可以从页面中删除插件的组件

class Slider{
  constructor(id, opts = {images:[], cycle: 3000}){
  .
  .
  .
  }}
  
const slider = new Slider('my-slider', {images: ['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});

抽象化:写一个抽象类作为组件的基类,初始化组件。它有注入插件的方法及抽象的render方法