zoukankan      html  css  js  c++  java
  • web-api

    1 - WEB API介绍

    1.1 API的概念

    API(Application Programming Interface,应⽤程序编程接⼝)是⼀些预先定义的函数,⽬的是提

    供应⽤程序与开发⼈员基于某软件或硬件得以访问⼀组例程的能⼒,⽽⼜⽆需访问源码,⽆需理解其内

    部⼯作机制细节,只需直接调⽤使⽤即可。

    举例解释什么是API。
    例如,
    C语⾔中有⼀个函数 fopen()可以打开硬盘上的⽂件,这个函数对于我们来说,就是⼀个C语⾔提
    供的打开⽂件的⼯具。
    javascript中有⼀个函数alert()可以在⻚⾯弹⼀个提示框,这个函数就是js提供的⼀个弹框⼯具。
    这些⼯具(函数)由编程语⾔提供,内部的实现已经封装好了,我们只要学会灵活的使⽤这些⼯具
    即可。
    

    1.2 Web API的概念

    Web API 是浏览器提供的⼀套操作浏览器功能和⻚⾯元素的 API ( BOM 和 DOM )。

    现阶段我们主要针对于浏览器讲解常⽤的 API , 主要针对浏览器做交互效果。⽐如我们想要浏览器弹出

    ⼀个警示框, 直接使⽤ alert(‘弹出’)

    MDN 详细 API : https://developer.mozilla.org/zh-CN/docs/Web/API

    因为 Web API 很多,所以我们将这个阶段称为 Web APIs。

    此处的 Web API 特指浏览器提供的⼀系列API(很多函数或对象⽅法),即操作⽹⻚的⼀系列⼯具。例

    如:操作html标签、操作⻚⾯地址的⽅法。

    1.3 API 和 Web API 总结

    1. API 是为我们程序员提供的⼀个接⼝,帮助我们实现某种功能,我们会使⽤就可以了,不必纠结内部如何实现

    2. Web API 主要是针对于浏览器提供的接⼝,主要针对于浏览器做交互效果。

    3. Web API ⼀般都有输⼊和输出(函数的传参和返回值),Web API 很多都是⽅法(函数)

    4. 学习 Web API 可以结合前⾯学习内置对象⽅法的思路学习

    2 - DOM

    DOM 就是把⻚⾯看成是⼀个⽂档,学习DOM就是学习操作⽂档⾥的元素。DOM⼜称为⽂档树模型

    DOM树:把html⻚⾯或者是xml⽂件看成是⼀个⽂档,⽂档就是⼀个对象,这个⽂档中所有的标签都是

    元素,元素也可以看成是对象,标签(元素、对象)有很多,还有嵌套关系组成的这种层次结构,可以

    模拟成树形结构图,简称:树状图,就是dom树

    DOM对象:通过DOM⽅式获取的元素得到的对象

    ⽂档 ⼀个⽹⻚可以称为⽂档

    节点(node):⻚⾯中所有的内容都是节点(包括标签、属性、⽂本(⽂字、换⾏、空格、回⻋)、注释

    等)

    元素(elementt):⻚⾯中所有的标签都是元素,元素可以看成是对象。

    根元素:html标签

    ⻚⾯中的顶级对象:document

    属性 标签的属性

    HTML⽂件是⽤来展示信息,展示数据的 XML:侧重于存储数据

    HTML ⽂件看成是⼀个⽂档(document),把这个⽂档也可以看成是⼀个对象,⽂档中所有的标签都

    可以看成是⼀个对象

    DOM结构树(继承关系)

    image-20210802144503056

    DOM结构树上相关联的有这个继承的关系,例如在 HTMLElement.abc=123 ,那么在它的分⽀下的任何

    ⼀个拥有继承关系的分⽀上,都会有这个属性。⽐如在⻚⾯中选中⼀个元素,那么这个元素身上也有

    abc=123这个属性。

    document.__proto__ ==> HTMLDocument
    HTMLDocument.__proto__ ==> Document
    Document.__proto__ ==> Node
    Node.__proto__ ==> EventTarget
    EventTarget.__proto__ ==> Object
    

    2.1 DOM 常⻅的操作简介

    • 获取元素
    • 动态创建元素
    • 对元素进⾏操作(设置其属性或调⽤其⽅法)
    • 事件(什么时机做相应的操作)

    1、 getElementByid ⽅法定义在 Document.prototype 上,即 Element 节点上不能使⽤。

    2、 getElementsByName ⽅法定义在 HTMLDocument.prototype 上,即⾮ html 中的 document 不能使⽤

    ( xml documentElement )

    3、 getElementsByTagName ⽅法定义在 Document.prototype 和 Element.prototype 上,换句话说就

    是获取到的元素可以继续调⽤ getElementsByTagName 这个⽅法。

    4、 HTMLDocument.prototype 定义了⼀些常⽤的属性, body.head 分别指代 HTML ⽂档中的

    标签

    5、 Document.prototype 上定义了 documentElement 属性,指代⽂档的根元素,在 HTML ⽂档中,他总

    是指代 元素。

    6 、 getELementsByClassName 、 querySelectorAll 、 querySelector

    在 Docuement.prototype , Element.prototype 类中均有定义。

    2.2 获取⻚⾯元素的⽅法

    除了id,其他的选择器取出来的都是⼀组的,基本上全部是类数组
    1、根据id属性获取元素 返回的是⼀个元素对象 getElementById("id")
    2、根据标签名获取元素 返回的是元素对象组成的伪数组 getElementsByTagName("标签的名⼦")
    下⾯的⼏个,有的浏览器不⽀持
    3 、根据表单的 name 属性获取元素,返回的是元素对象组成的⼀个伪数组
    getElementsByName("name属性")
    
    <body> <input type="button" value="更改value值" id="btn"> <input type="text" name="name1" value="我很好"> <br/>
    <input type="text" name="name2" value="我很好"> <br/>
    <input type="text" name="name1" value="我很好"> <br/>
    <input type="text" name="name3" value="我很好"> <br/>
    <input type="text" name="name3" value="我很好"> <br/>
    <script >
    // 根据表单的name属性获取元素 把name是1的获取出来
    document.getElementById("btn").onclick = function () {
    // document.getElementsByName("name属性值")是根据表单的name属性获取元
    素,返回的也是⼀个伪数组
    var nameList = document.getElementsByName("name1");
    for (var i=0; nameList.length; i++) {
    nameList[i].value = "你好呀";
     }
     };
    </script>
    </body>
    

    4、根据类样式的名⼦来获取元素,返回的是元素对象组成的伪数组 getElementsByClassName("类名⼦")

    <head><meta charset="UTF-8"> <title>Title</title>
    <style>
    div {
     100px;
    height: 100px;
    background-color: #f40;
     }
    span {
    display: block;
     100px;
    height: 100px;
    background-color: yellow;
     }
    </style>
    </head>
    <body> <div class="cls">这是第⼀个div</div>
    <div class="cls">这是第⼆个div</div>
    <span class="cls">span</span>
    <input type="button" value="变颜⾊" id="btn"> <script src="./common.js"></script>
    <script >
    // 根据类样式获取元素 注意ie8及以下都不⽀持
    my$("btn").onclick = function () {
    // document.getElementsByClassName("类样式名⼦") 根据类样式获取元素,返
    回的也是⼀个伪数组
    var classList = document.getElementsByClassName("cls");
    for (var i=0; i<classList.length; i++) {
    classList[i].style.backgroundColor="pink";
     }
     };
    </script>
    </body>
    

    5、根据css选择器获取元素,返回来的是⼀个元素对象 querySelector("选择器名字"),并不常⽤,选择

    出来的东⻄不是时事的zz(H5新增的)

    6、根据css选择器获取元素,返回的是元素对象组成的伪数组 querySelectorAll("选择器的名字") 注意

    ⾥⾯的选择器要加符号。⽐如 document.queryselector(".class/#id")

    7、获取特殊的元素(body, html)

    获取 body 元素 : document.body

    获取 html 元素 : document.documentElement

    3 - 事件 基础

    3.1. 事件概述

    JavaScript 使我们有能⼒创建动态⻚⾯,⽽事件是可以被 JavaScript 侦测到的⾏为。

    简单理解: 触发--- 响应机制。

    ⽹⻚中的每个元素都可以产⽣某些可以触发 JavaScript 的事件,例如,我们可以在⽤户点击某按钮时

    产⽣⼀个 事件,然后去执⾏某些操作。

    3.2 事件的三要素

    • 事件源(谁):触发事件的元素
    • 事件类型(什么事件): 例如 click 点击事件
    • 事件处理程序(做啥):事件触发后要执⾏的代码(函数形式),事件处理函数
    <body><button id="btn">唐伯⻁</button>
    <script>
    // 点击⼀个按钮,弹出对话框
    // 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称
    为事件三要素
    //(1) 事件源 事件被触发的对象 谁 按钮
    var btn = document.getElementById('btn');
    //(2) 事件类型 如何触发 什么事件 ⽐如⿏标点击(onclick) 还是⿏标经过
    还是键盘按下
    //(3) 事件处理程序 通过⼀个函数赋值的⽅式 完成
    btn.onclick = function() {
    alert('点秋⾹');
     }
    </script>
    </body>
    

    3.3 事件执⾏的步骤

    1. 获取事件源

    2. 注册事件

    3. 添加事件处理程序

    案例代码

    <body><div>123</div>
    <script>
    // 执⾏事件步骤
    // 点击div 控制台输出 我被选中了
    // 1. 获取事件源
    var div = document.querySelector('div');
    // 2.绑定事件 注册事件
    // div.onclick
    // 3.添加事件处理程序
    div.onclick = function() {
    console.log('我被选中了');
     }
    </script>
    </body>
    

    3.4 常⻅的⿏标事件

    image-20210802144852148

    3.5 分析事件三要素

    • 下拉菜单三要素

    • 关闭⼴告三要素

    4 - 操作属性

    JavaScript的 DOM 操作可以改变⽹⻚内容、结构和样式,我们可以利⽤ DOM 操作元素来改变元素⾥

    ⾯的内容、属性等。(注意:这些操作都是通过元素对象的属性实现的)

    4.1. 改变元素内容(获取或设置)

    image-20210802144945944

    innerText改变元素内容

    <body><button>显示当前系统时间</button>
    <div>某个时间</div>
    <p>1123</p>
    <script>
    // 当我们点击了按钮, div⾥⾯的⽂字会发⽣变化
    // 1. 获取元素
    var btn = document.querySelector('button');
    var div = document.querySelector('div');
    // 2.注册事件
    btn.onclick = function() {
    // div.innerText = '2019-6-6';
    div.innerHTML = getDate();
     }
    function getDate() {
    var date = new Date();
    // 我们写⼀个 2019年 5⽉ 1⽇ 星期三
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var dates = date.getDate();
    var arr = ['星期⽇', '星期⼀', '星期⼆', '星期三', '星期四', '星期
    五', '星期六'];
    var day = date.getDay();
        return '今天是:' + year + '年' + month + '⽉' + dates + '⽇ ' +
    arr[day];
     }
    </script>
    </body>
    

    innerTextinnerHTML的区别

    • innerText主要是设置⽂本的,设置标签内容,是没有标签的效果的,同时会把标签内的所有内容(包括包含的标签)都替换为新的内容 ⽂本的形式
    • innerHTML 可以设置⽂本内容,主要作⽤是在标签中设置新的html标签内容,是有标签的效果的,同时把标签内的所有内容(包括包含的标签)都替换成
    • 新的内容 解析成html代码的形式
    • innerText 获取的时候,会把标签内的所有的⽂本内容到取到。包括嵌套的标签⾥的内容,⽂本的形式
    • innerHTML 获取的时候,会把标签内的所有内容,原样获取到,html代码的形式

    案例代码

    <body><div></div>
    <p>
      我是⽂字
      <span>123</span>
    </p>
    <script>
      // innerText 和 innerHTML的区别
      // 1. innerText 不识别html标签 ⾮标准 去除空格和换⾏
      var div = document.querySelector('div');
      // div.innerText = '<strong>今天是:</strong> 2019';
      // 2. innerHTML 识别html标签 W3C标准 保留空格和换⾏的
      div.innerHTML = '<strong>今天是:</strong> 2019';
      // 这两个属性是可读写的 可以获取元素⾥⾯的内容
      var p = document.querySelector('p');
      console.log(p.innerText);
      console.log(p.innerHTML);
    </script>
    </body>
    

    innerText改变元素内容

    <body><button>显示当前系统时间</button>
    <div>某个时间</div>
    <p>1123</p>
    <script>
      // 当我们点击了按钮, div⾥⾯的⽂字会发⽣变化
      // 1. 获取元素
      var btn = document.querySelector('button');
      var div = document.querySelector('div');
      // 2.注册事件
      btn.onclick = function() {
    // div.innerText = '2019-6-6';
        div.innerHTML = getDate();
      }
      function getDate() {
        var date = new Date();
    // 我们写⼀个 2019年 5⽉ 1⽇ 星期三
        var year = date.getFullYear();
        var month = date.getMonth() + 1;
        var dates = date.getDate();
        var arr = ['星期⽇', '星期⼀', '星期⼆', '星期三', '星期四', '星期
          五', '星期六'];
        var day = date.getDay();
        return '今天是:' + year + '年' + month + '⽉' + dates + '⽇ ' +
          arr[day];
      }
    </script>
    </body>
    

    innerText和innerHTML的区别

    • 获取内容时的区别:

    innerText会去除空格和换⾏,⽽innerHTML会保留空格和换⾏

    • 设置内容时的区别:

    innerText不会识别html,⽽innerHTML会识别

    案例代码

    <body><div></div>
    <p>
      我是⽂字
      <span>123</span>
    </p>
    <script>
      // innerText 和 innerHTML的区别
      // 1. innerText 不识别html标签 ⾮标准 去除空格和换⾏
      var div = document.querySelector('div');
      // div.innerText = '<strong>今天是:</strong> 2019';
      // 2. innerHTML 识别html标签 W3C标准 保留空格和换⾏的
      div.innerHTML = '<strong>今天是:</strong> 2019';
      // 这两个属性是可读写的 可以获取元素⾥⾯的内容
      var p = document.querySelector('p');
      console.log(p.innerText);
      console.log(p.innerHTML);
    </script>
    </body>
    

    innerText和textContent兼容性

    • 设置标签中的⽂本内容,应该使⽤textContent属性,⾕歌、⽕狐⽀持,ie8不⽀持
    • 设置标签中的⽂本内容,应该使⽤innerText属性,⾕歌、ie8⽀持,⾼版本的⽕狐⽀持,低版本的不⽀持
    • 如果这个属性在浏览器中不⽀持,那么这个属性的类型是undefined,判断这个属性的类型是不是undefined,就知道浏览器⽀不⽀持。
    <body><input type="button" value="设置" id="btn"> <input type="button" value="获取" id="btn1">
    <div id="dv">螺蛳粉就算了</div>
    <script src="./common.js"></script>
    <script>// 设置标签中的⽂本内容,应该使⽤textContent属性,⾕歌、⽕狐⽀持,ie8不⽀持// 设置标签中的⽂本内容,应该使⽤innerText属性,⾕歌、ie8⽀持,⾼版本的⽕狐⽀持,低版本的不⽀持// 如果这个属性在浏览器中不⽀持,那么这个属性的类型是undefined,判断这个属性的类型是不是undefined,就知道浏览器⽀不⽀持。// ** 写解决兼容性的函数// 1、设置标签中的⽂本内容function setInnerText (element, text) {if (typeof element.textContent=="undefined") {//说明不⽀持element.innerText = text; }else {element.textContent = text; } }// 2、获取标签中的⽂本内容function getInnerText (element) {if (typeof element.textContent == "undefined") {return element.innerText; } else {return element.textContent; } }// 测试设置my$("btn").onclick = function () {// 设置div中的⽂本内容setInnerText(my$("dv"), "⽼司机服务"); };// 测试获取my$("btn1").onclick = function () {// 获取div中的内容var out = getInnerText(my$("dv"));console.log(out); };</script>
    </body>
    
    

    4.2 常⽤元素的属性操作

    1. src、href

    2. id、 alt、title

    获取属性的值

    ​ 元素对象.属性名

    设置属性的值

    ​ 元素对象.属性名 = 值

    案例代码

    <body><button id="ldh">刘德华</button>
    <button id="zxy">张学友</button> <br>
    <img src="images/ldh.jpg" alt="" title="刘德华"> <script>
      // 修改元素属性 src
      // 1. 获取元素
      var ldh = document.getElementById('ldh');
      var zxy = document.getElementById('zxy');
      var img = document.querySelector('img');
      // 2. 注册事件 处理程序
      zxy.onclick = function() {
        img.src = 'images/zxy.jpg';
        img.title = '张学友思密达';
      }
      ldh.onclick = function() {
        img.src = 'images/ldh.jpg';
        img.title = '刘德华';
      }
    </script>
    </body>
    

    4.2.1. 案例:分时问候

    image-20210802145255687

    4.3 表单元素的属性操作

    image-20210802145311553

    获取属性的值

    元素对象.属性名

    设置属性的值

    元素对象.属性名 = 值

    表单元素中有⼀些属性如:disabled、checked、selected,元素对象的这些属性的值是布尔

    型。

    案例代码

    <body><button>按钮</button>
    <input type="text" value="输⼊内容"> <script>
      // 1. 获取元素
      var btn = document.querySelector('button');
      var input = document.querySelector('input');
      // 2. 注册事件 处理程序
      btn.onclick = function() {
    // 表单⾥⾯的值 ⽂字内容是通过 value 来修改的
        input.value = '被点击了';
    // 如果想要某个表单被禁⽤ 不能再点击 disabled 我们想要这个按钮
        button禁⽤
    // btn.disabled = true;
        this.disabled = true;
    // this 指向的是事件函数的调⽤者 btn
      }
    </script>
    </body>
    

    4.3.1. 案例:仿京东显示密码

    image-20210802145350380

    4.4 样式属性操作

    我们可以通过 JS 修改元素的⼤⼩、颜⾊、位置等样式。

    常⽤⽅式

    image-20210802145411488

    4.4.1. ⽅式1:通过操作style属性

    元素对象的style属性也是⼀个对象!

    元素对象.style.样式属性 = 值;

    image-20210802145427921

    案例代码

    <body><div></div>
    <script>
      // 1. 获取元素
      var div = document.querySelector('div');
      // 2. 注册事件 处理程序
      div.onclick = function() {
    // div.style⾥⾯的属性 采取驼峰命名法
        this.style.backgroundColor = 'purple';
        this.style.width = '250px';
      }
    </script>
    </body>
    

    案例:淘宝点击关闭⼆维码

    image-20210802145506899

    image-20210802145519930

    案例:显示隐藏⽂本框内容

    image-20210802145537161

    4.4.2. ⽅式2:通过操作className属性

    元素对象.className = 值;

    因为class是关键字,所有使⽤className。

    image-20210802145556937

    案例代码

    <body><div class="first">⽂本</div>
    <script>
      // 1. 使⽤ element.style 获得修改元素样式 如果样式⽐较少 或者 功能简单的
      情况下使⽤
    var test = document.querySelector('div');
      test.onclick = function() {
    // this.style.backgroundColor = 'purple';
    // this.style.color = '#fff';
    // this.style.fontSize = '25px';
    // this.style.marginTop = '100px';
    // 2. 我们可以通过 修改元素的className更改元素的样式 适合于样式较多或
        者功能复杂的情况
    // 3. 如果想要保留原先的类名,我们可以这么做 多类名选择器
    // this.className = 'change';
        this.className = 'first change';
      }
    </script>
    </body>
    

    image-20210802145623145

    4.5 ⼩结

    image-20210802145655726

    4.6. 排他操作

    4.6.1. 排他思想

    image-20210802145713496

    如果有同⼀组元素,我们想要某⼀个元素实现某种样式, 需要⽤到循环的排他思想算法:

    1. 所有元素全部清除样式(⼲掉其他⼈)

    2. 给当前元素设置样式 (留下我⾃⼰)

    3. 注意顺序不能颠倒,⾸先⼲掉其他⼈,再设置⾃⼰

    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <button>按钮5</button>
    <script>
    // 1. 获取所有按钮元素
    var btns = document.getElementsByTagName('button');
    // btns得到的是伪数组 ⾥⾯的每⼀个元素 btns[i]
    for (var i = 0; i < btns.length; i++) {
      btns[i].onclick = function() {
    // (1) 我们先把所有的按钮背景颜⾊去掉 ⼲掉所有⼈
        for (var i = 0; i < btns.length; i++) {
          btns[i].style.backgroundColor = '';
        }
    // (2) 然后才让当前的元素背景颜⾊为pink 留下我⾃⼰
        this.style.backgroundColor = 'pink';
      }
    }
    </script>
    

    image-20210802145741115

    image-20210802145748683

    <body><ul class="baidu"> <li><img src="images/1.jpg"></li>
      <li><img src="images/2.jpg"></li>
      <li><img src="images/3.jpg"></li>
      <li><img src="images/4.jpg"></li>
    </ul>
    <script>
      // 1. 获取元素
      var imgs = document.querySelector('.baidu').querySelectorAll('img');
      // console.log(imgs);
      // 2. 循环注册事件
      for (var i = 0; i < imgs.length; i++) {
        imgs[i].onclick = function() {
    // this.src 就是我们点击图⽚的路径 images/2.jpg
    // console.log(this.src);
    // 把这个路径 this.src 给body 就可以了
          document.body.style.backgroundImage = 'url(' + this.src +
            ')';
        }
      }
    </script>
    </body>
    

    image-20210802145809724

    image-20210802145817330

    <script>
    // 1. 全选和取消全选做法: 让下⾯所有复选框的checked属性(选中状态) 跟随
    全选按钮即可
    // 获取元素
    var j_cbAll = document.getElementById('j_cbAll');
    var j_tbs =
      document.getElementById('j_tb').getElementsByTagName('input');
    // 全选按钮注册事件
    j_cbAll.onclick = function() {
    // this.checked 当前复选框的选中状态
      console.log(this.checked);
      for (var i = 0; i < j_tbs.length; i++) {
        j_tbs[i].checked = this.checked;
      }
    }
    // 给所有的⼦复选框注册单击事件
    for (var i = 0; i < j_tbs.length; i++) {
      j_tbs[i].onclick = function() {
    // flag 控制全选按钮是否选中
        var flag = true;
    // 每次点击下⾯的复选框都要循环检查者4个⼩按钮是否全被选中
        for (var i = 0; i < j_tbs.length; i++) {
          if (!j_tbs[i].checked) {
            flag = false;
            break;
          }
        }
    // 设置全选按钮的状态
        j_cbAll.checked = flag;
      }
    }
    </script>
    

    案例:表格隔⾏变⾊

    image-20210802145838321

    <script>
    // 1.获取元素 获取的是 tbody ⾥⾯所有的⾏
    var trs = document.querySelector('tbody').querySelectorAll('tr');
    // 2. 利⽤循环绑定注册事件
    for (var i = 0; i < trs.length; i++) {
    // 3. ⿏标经过事件 onmouseover
      trs[i].onmouseover = function() {
    // console.log(11);
        this.className = 'bg';
      }
    // 4. ⿏标离开事件 onmouseout
      trs[i].onmouseout = function() {
        this.className = '';
      }
    }</script>
    

    4.7. ⾃定义属性操作

    4.7.1. 获取属性值

    image-20210802145922099

    <div id="demo" index="1" class="nav"></div>
    <script>
    var div = document.querySelector('div');
    // 1. 获取元素的属性值
    // (1) element.属性
    console.log(div.id);
    //(2) element.getAttribute('属性') get得到获取 attribute 属性的意思 我
    们程序员⾃⼰添加的属性我们称为⾃定义属性 index
    console.log(div.getAttribute('id'));
    console.log(div.getAttribute('index'));
    </script>
    

    4.7.2. 设置属性值

    image-20210802145942613

    // 2. 设置元素属性值
    // (1) element.属性= '值'
    div.id = 'test';
    div.className = 'navs';
    // (2) element.setAttribute('属性', '值'); 主要针对于⾃定义属性
    div.setAttribute('index', 2);
    div.setAttribute('class', 'footer'); // class 特殊 这⾥⾯写的就是
    

    4.7.3. 移出属性

    image-20210802150010951

    // class 不是className
    // 3 移除属性 removeAttribute(属性)
    div.removeAttribute('index');
    

    案例:tab栏

    image-20210802150047619

    <script>
    // 获取元素
    var tab_list = document.querySelector('.tab_list');
    var lis = tab_list.querySelectorAll('li');
    var items = document.querySelectorAll('.item');
    // for循环,给选项卡绑定点击事件
    for (var i = 0; i < lis.length; i++) {
    // 开始给5个⼩li 设置索引号
      lis[i].setAttribute('index', i);
      lis[i].onclick = function() {
    // 1. 上的模块选项卡,当前这⼀个底⾊会是红⾊,其余不变(排他思想)
    // ⼲掉所有⼈ 其余的li清除 class 这个类
        for (var i = 0; i < lis.length; i++) {
          lis[i].className = '';
        }
    // 留下我⾃⼰
        this.className = 'current';
    // 2. 下⾯的显示内容模块
        var index = this.getAttribute('index');
        console.log(index);
    // ⼲掉所有⼈ 让其余的item 这些div 隐藏
        for (var i = 0; i < items.length; i++) {
          items[i].style.display = 'none';
        }
    // 留下我⾃⼰ 让对应的item 显示出来
        items[index].style.display = 'block';
      }
    }
    </script>
    

    4.8. H5⾃定义属性

    ⾃定义属性⽬的:是为了保存并使⽤数据。有些数据可以保存到⻚⾯中⽽不⽤保存到数据库中。

    ⾃定义属性获取是通过getAttribute(‘属性’) 获取。

    但是有些⾃定义属性很容易引起歧义,不容易判断是元素的内置属性还是⾃定义属性。

    H5给我们新增了⾃定义属性:

    image-20210802150121307

    <div getTime="20" data-index="2" data-list-name="andy"></div>
    <script>
    var div = document.querySelector('div');
    // console.log(div.getTime);
    console.log(div.getAttribute('getTime'));
    div.setAttribute('data-time', 20);
    console.log(div.getAttribute('data-index'));
    console.log(div.getAttribute('data-list-name'));
    // h5新增的获取⾃定义属性的⽅法 它只能获取data-开头的
    // dataset 是⼀个集合⾥⾯存放了所有以data开头的⾃定义属性
    console.log(div.dataset);
    console.log(div.dataset.index);
    console.log(div.dataset['index']);
    // 如果⾃定义属性⾥⾯有多个-链接的单词,我们获取的时候采取 驼峰命名法
    console.log(div.dataset.listName);
    console.log(div.dataset['listName']);
    </script>
    

    5 - 节点操作

    5.1. 节点概述

    ⽹⻚中的所有内容都是节点(标签、属性、⽂本、注释等),在DOM 中,节点使⽤ node 来表示。

    HTML DOM 树中的所有节点均可通过 JavaScript 进⾏访问,所有 HTML 元素(节点)均可被修改,也

    可以创建或删除。

    image-20210802150200349

    ⼀般地,节点⾄少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)

    这三个基本属性。

    image-20210802150214314

    5.2. 节点层级

    利⽤ DOM 树可以把节点划分为不同的层级关系,常⻅的是⽗⼦兄层级关系

    image-20210802150230918

    5.3. ⽗级节点

    image-20210802150257054

    <div class="demo"> <div class="box"> <span class="erweima">×</span>
    </div>
    </div>
    <script>
    // 1. ⽗节点 parentNode
    var erweima = document.querySelector('.erweima');
    // var box = document.querySelector('.box');
    // 得到的是离元素最近的⽗级节点(亲爸爸) 如果找不到⽗节点就返回为 null
    console.log(erweima.parentNode);
    </script>
    

    5.4. ⼦节点

    所有⼦节点

    image-20210802150317091

    ⼦元素节点

    image-20210802150327906

    <ul><li>我是li</li>
    <li>我是li</li>
    <li>我是li</li>
    <li>我是li</li>
    </ul>
    <script>
    // DOM 提供的⽅法(API)获取
    var ul = document.querySelector('ul');
    var lis = ul.querySelectorAll('li');
    // 1. ⼦节点 childNodes 所有的⼦节点 包含 元素节点 ⽂本节点等等
    console.log(ul.childNodes);
    console.log(ul.childNodes[0].nodeType);
    console.log(ul.childNodes[1].nodeType);
    // 2. children 获取所有的⼦元素节点 也是我们实际开发常⽤的
    console.log(ul.children);
    </script>
    

    1个⼦节点

    image-20210802150441016

    最后1个⼦节点

    image-20210802150449785

    1个⼦元素节点

    image-20210802150459257

    最后1个⼦元素节点

    image-20210802150516039

    实际开发中, firstChild 和 lastChild 包含其他节点,操作不⽅便,⽽ firstElementChild 和

    lastElementChild ⼜有兼容性问题,那么我们如何获取第⼀个⼦元素节点或最后⼀个⼦元素节点呢?

    image-20210802150531281

    <ol> <li>我是li1</li>
    <li>我是li2</li>
    <li>我是li3</li>
    <li>我是li4</li>
    <li>我是li5</li>
    </ol>
    <script>
    var ol = document.querySelector('ol');
    // 1. firstChild 第⼀个⼦节点 不管是⽂本节点还是元素节点
    console.log(ol.firstChild);
    console.log(ol.lastChild);
    // 2. firstElementChild 返回第⼀个⼦元素节点 ie9才⽀持
    console.log(ol.firstElementChild);
    console.log(ol.lastElementChild);
    // 3. 实际开发的写法 既没有兼容性问题⼜返回第⼀个⼦元素
    console.log(ol.children[0]);
    console.log(ol.children[ol.children.length - 1]);
    </script>
    
    案例:新浪下拉菜单

    image-20210802150555152

    image-20210802150612483

    <script>
    // 1. 获取元素
    var nav = document.querySelector('.nav');
    var lis = nav.children; // 得到4个⼩li
    // 2.循环注册事件
    for (var i = 0; i < lis.length; i++) {
      lis[i].onmouseover = function() {
        this.children[1].style.display = 'block';
      }
      lis[i].onmouseout = function() {
        this.children[1].style.display = 'none';
      }
    }
    </script>
    

    5.5. 兄弟节点

    下⼀个兄弟节点

    image-20210802150636045

    上⼀个兄弟节点

    image-20210802150644185

    <div>我是div</div>
    <span>我是span</span>
    <script>
    var div = document.querySelector('div');
    // 1.nextSibling 下⼀个兄弟节点 包含元素节点或者 ⽂本节点等等
    console.log(div.nextSibling);
    console.log(div.previousSibling);
    // 2. nextElementSibling 得到下⼀个兄弟元素节点
    console.log(div.nextElementSibling);
    console.log(div.previousElementSibling);
    </script>
    

    下⼀个兄弟元素节点(有兼容性问题)

    image-20210802150709271

    上⼀个兄弟元素节点(有兼容性问题)

    image-20210802150730866

    function getNextElementSibling(element) {
    var el = element;
    while (el = el.nextSibling) {
    if (el.nodeType === 1) {
    return el;
    }
    }
    return null;
    }
    

    5.6. 创建节点

    image-20210802150754614

    5.7. 添加节点

    image-20210802150806407

    <ul><li>123</li>
    </ul>
    <script>
    // 1. 创建节点元素节点
    var li = document.createElement('li');
    // 2. 添加节点 node.appendChild(child) node ⽗级 child 是⼦级 后⾯追加
    元素
    var ul = document.querySelector('ul');
    ul.appendChild(li);
    // 3. 添加节点 node.insertBefore(child, 指定元素);
    var lili = document.createElement('li');
    ul.insertBefore(lili, ul.children[0]);
    // 4. 我们想要⻚⾯添加⼀个新的元素 : 1. 创建元素 2. 添加元素
    </script>
    

    案例:简单版发布留⾔

    image-20210802150832453

    image-20210802150838123

    <body><textarea name="" id=""></textarea>
    <button>发布</button>
    <ul> </ul>
    <script>
      // 1. 获取元素
      var btn = document.querySelector('button');
      var text = document.querySelector('textarea');
      var ul = document.querySelector('ul');
      // 2. 注册事件
      btn.onclick = function() {
        if (text.value == '') {
          alert('您没有输⼊内容');
          return false;
        } else {
    // console.log(text.value);
    // (1) 创建元素
          var li = document.createElement('li');
    // 先有li 才能赋值
          li.innerHTML = text.value;
    // (2) 添加元素
    // ul.appendChild(li);
          ul.insertBefore(li, ul.children[0]);
        }
      }
    </script>
    </body>
    

    5.8. 删除节点

    image-20210802150859801

    <button>删除</button>
    <ul><li>熊⼤</li>
    <li>熊⼆</li>
    <li>光头强</li>
    </ul>
    <script>
    // 1.获取元素
    var ul = document.querySelector('ul');
    var btn = document.querySelector('button');
    // 2. 删除元素 node.removeChild(child)
    // ul.removeChild(ul.children[0]);
    // 3. 点击按钮依次删除⾥⾯的孩⼦
    btn.onclick = function() {
      if (ul.children.length == 0) {
        this.disabled = true;
      } else {
        ul.removeChild(ul.children[0]);
      }
    }
    </script>
    

    案例:删除留⾔

    image-20210802150949733

    image-20210802151004105

    <textarea name="" id=""></textarea>
    <button>发布</button>
    <ul> </ul>
    <script>
    // 1. 获取元素
    var btn = document.querySelector('button');
    var text = document.querySelector('textarea');
    var ul = document.querySelector('ul');
    // 2. 注册事件
    btn.onclick = function() {
      if (text.value == '') {
        alert('您没有输⼊内容');
        return false;
      } else {
    // console.log(text.value);
    // (1) 创建元素
        var li = document.createElement('li');
    // 先有li 才能赋值
        li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
    // (2) 添加元素
    // ul.appendChild(li);
        ul.insertBefore(li, ul.children[0]);
    // (3) 删除元素 删除的是当前链接的li 它的⽗亲
        var as = document.querySelectorAll('a');
        for (var i = 0; i < as.length; i++) {
          as[i].onclick = function() {
    // 删除的是 li 当前a所在的li this.parentNode;
            ul.removeChild(this.parentNode);
          }
        }
      }
    }
    </script>
    

    5.9. 复制(克隆)节点

    image-20210802151042298

    <ul><li>1111</li>
    <li>2</li>
    <li>3</li>
    </ul>
    <script>
    var ul = document.querySelector('ul');
    // 1. node.cloneNode(); 括号为空或者⾥⾯是false 浅拷⻉ 只复制标签不复制⾥
    ⾯的内容
    // 2. node.cloneNode(true); 括号为true 深拷⻉ 复制标签复制⾥⾯的内容
    var lili = ul.children[0].cloneNode(true);
    ul.appendChild(lili);
    </script>
    

    案例:动态⽣成表格

    image-20210802151111032

    <script>
    // 1.先去准备好学⽣的数据
    var datas = [{
      name: '魏璎珞',
      subject: 'JavaScript',
      score: 100
    }, {
      name: '弘历',
      subject: 'JavaScript',
      score: 98
    }, {
      name: '傅恒',
      subject: 'JavaScript',
      score: 99
    }, {
      name: '明⽟',
      subject: 'JavaScript',
      score: 88
    }, {
      name: '⼤猪蹄⼦',
      subject: 'JavaScript',
      score: 0
    }];
    // 2. 往tbody ⾥⾯创建⾏: 有⼏个⼈(通过数组的⻓度)我们就创建⼏⾏
    var tbody = document.querySelector('tbody');
    // 遍历数组
    for (var i = 0; i < datas.length; i++) {
    // 1. 创建 tr⾏
      var tr = document.createElement('tr');
      tbody.appendChild(tr);
    // 2. ⾏⾥⾯创建单元格td 单元格的数量取决于每个对象⾥⾯的属性个数
    // 使⽤for in遍历学⽣对象
      for (var k in datas[i]) {
    // 创建单元格
        var td = document.createElement('td');
    // 把对象⾥⾯的属性值 datas[i][k] 给 td 
        td.innerHTML = datas[i][k];
        tr.appendChild(td);
      }
    // 3. 创建有删除2个字的单元格
      var td = document.createElement('td');
      td.innerHTML = '<a href="javascript:;">删除 </a>';
      tr.appendChild(td);
    }
    // 4. 删除操作 开始
    var as = document.querySelectorAll('a');
    for (var i = 0; i < as.length; i++) {
      as[i].onclick = function() {
    // 点击a 删除 当前a 所在的⾏(链接的爸爸的爸爸)
        node.removeChild(child)
        tbody.removeChild(this.parentNode.parentNode)
      }
    }
    </script>
    

    5.10. 创建元素的三种⽅式

    image-20210802151142676

    <script>
    // 三种创建元素⽅式区别
    // 1. document.write() 创建元素 如果⻚⾯⽂档流加载完毕,再调⽤这句话会导
    致⻚⾯重绘
    var btn = document.querySelector('button');
    btn.onclick = function() {
      document.write('<div>123</div>');
    }
    // 2. innerHTML 创建元素
    var inner = document.querySelector('.inner');
    for (var i = 0; i <= 100; i++) {
      inner.innerHTML += '<a href="#">百度</a>'
    }
    var arr = [];
    for (var i = 0; i <= 100; i++) {
      arr.push('<a href="#">百度</a>');
    }
    inner.innerHTML = arr.join('');
    // 3. document.createElement() 创建元素
    var create = document.querySelector('.create');
    for (var i = 0; i <= 100; i++) {
      var a = document.createElement('a');
      create.appendChild(a);
    }
    </script>
    

    5.11. innerTHML和createElement效率对⽐

    innerHTML字符串拼接⽅式(效率低)

    <script>
    function fn() {
      var d1 = +new Date();
      var str = '';
      for (var i = 0; i < 1000; i++) {
        document.body.innerHTML += '<div style="100px; height:2px;
        border:1px solid blue;"></div>';
      }
      var d2 = +new Date();
      console.log(d2 - d1);
    }
    fn();
    </script>
    

    createElement⽅式(效率⼀般)

    <script>
    function fn() {
      var d1 = +new Date();
      for (var i = 0; i < 1000; i++) {
        var div = document.createElement('div');
        div.style.width = '100px';
        div.style.height = '2px';
        div.style.border = '1px solid red';
        document.body.appendChild(div);
      }
      var d2 = +new Date();
      console.log(d2 - d1);
    }
    fn();
    </script>
    

    innerHTML数组⽅式(效率⾼)

    <script>
    function fn() {
      var d1 = +new Date();
      var array = [];
      for (var i = 0; i < 1000; i++) {
        array.push('<div style="100px; height:2px; border:1px solid
        blue;"></div>');
      }
      document.body.innerHTML = array.join('');
      var d2 = +new Date();
      console.log(d2 - d1);
    }
    fn();
    </script>
    

    6 - DOM的核⼼总结

    image-20210802151245414

    6.1. 创建

    image-20210802151325257

    6.2. 增加

    image-20210802151334592

    6.3. 删

    image-20210802151342273

    6.4. 改

    image-20210802151350050

    6.5. 查

    image-20210802151419414

    6.6. 属性操作

    image-20210802151429249

    7 - 事件⾼级

    7.1. 注册事件(2种⽅式)

    image-20210802151508827

    7.2 事件监听

    addEventListener()事件监听(IE9以后⽀持)

    image-20210802151527863

    eventTarget.addEventListener()⽅法将指定的监听器注册到 eventTarget(⽬标对象)上,当该对象

    触发指定的事件时,就会执⾏事件处理函数。

    image-20210802151539018

    attacheEvent()事件监听(IE678⽀持)

    image-20210802151550023

    eventTarget.attachEvent()⽅法将指定的监听器注册到 eventTarget(⽬标对象) 上,当该对象触发

    指定的事件时,指定的回调函数就会被执⾏。

    image-20210802151605939

    <button>传统注册事件</button>
    <button>⽅法监听注册事件</button>
    <button>ie9 attachEvent</button>
    <script>
    var btns = document.querySelectorAll('button');
    // 1. 传统⽅式注册事件
    btns[0].onclick = function() {
      alert('hi');
    }
    btns[0].onclick = function() {
      alert('hao a u');
    }
    // 2. 事件侦听注册事件 addEventListener
    // (1) ⾥⾯的事件类型是字符串 必定加引号 ⽽且不带on
    // (2) 同⼀个元素 同⼀个事件可以添加多个侦听器(事件处理程序)
    btns[1].addEventListener('click', function() {
      alert(22);
    })
    btns[1].addEventListener('click', function() {
      alert(33);
    })
    // 3. attachEvent ie9以前的版本⽀持
    btns[2].attachEvent('onclick', function() {
      alert(11);
    })
    </script>
    

    事件监听兼容性解决⽅案

    封装⼀个函数,函数中判断浏览器的类型:

    image-20210802151629776

    7.3. 删除事件(解绑事件)

    image-20210802151645218

    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script>
    var divs = document.querySelectorAll('div');
    divs[0].onclick = function() {
      alert(11);
    // 1. 传统⽅式删除事件
      divs[0].onclick = null;
    }
    // 2. removeEventListener 删除事件
    divs[1].addEventListener('click', fn) // ⾥⾯的fn 不需要调⽤加⼩括号
    function fn() {
      alert(22);
      divs[1].removeEventListener('click', fn);
    }
    // 3. detachEvent
    divs[2].attachEvent('onclick', fn1);
    function fn1() {
      alert(33);
      divs[2].detachEvent('onclick', fn1);
    }
    </script>
    

    删除事件兼容性解决⽅案

    image-20210802151709899

    7.4. DOM事件流

    html中的标签都是相互嵌套的,我们可以将元素想象成⼀个盒⼦装⼀个盒⼦,document是
    最外⾯的⼤盒⼦。
    当你单击⼀个div时,同时你也单击了div的⽗元素,甚⾄整个⻚⾯。
    那么是先执⾏⽗元素的单击事件,还是先执⾏div的单击事件 ???
    

    image-20210802151735004

    ⽐如:我们给⻚⾯中的⼀个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。
    

    image-20210802151747331

    image-20210802151756560

    当时的2⼤浏览器霸主谁也不服谁!
    IE 提出从⽬标元素开始,然后⼀层⼀层向外接收事件并响应,也就是冒泡型事件流。
    Netscape(⽹景公司)提出从最外层开始,然后⼀层⼀层向内接收事件并响应,也就是捕获
    型事件流。
    江湖纷争,武林盟主也脑壳疼!!!
    最终,w3c 采⽤折中的⽅式,平息了战⽕,制定了统⼀的标准 —--— 先捕获再冒泡。
    现代浏览器都遵循了此标准,所以当事件发⽣时,会经历3个阶段。
    

    DOM 事件流会经历3个阶段:

    1. 捕获阶段

    2. 当前⽬标阶段

    3. 冒泡阶段

    我们向⽔⾥⾯扔⼀块⽯头,⾸先它会有⼀个下降的过程,这个过程就可以理解为从最顶层向事件发⽣的

    最具体元素(⽬标点)的捕获过程;之后会产⽣泡泡,会在最低点( 最具体元素)之后漂浮到⽔⾯上,

    这个过程相当于事件冒泡。

    image-20210802151844717

    image-20210802151853131

    事件冒泡

    <div class="father"> <div class="son">son盒⼦</div>
    </div>
    <script>
    // onclick 和 attachEvent(ie) 在冒泡阶段触发
    // 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略
    // son -> father ->body -> html -> document
    var son = document.querySelector('.son');
    // 给son注册单击事件
    son.addEventListener('click', function() {
      alert('son');
    }, false);
    // 给father注册单击事件
    var father = document.querySelector('.father');
    father.addEventListener('click', function() {
      alert('father');
    }, false);
    // 给document注册单击事件,省略第3个参数
    document.addEventListener('click', function() {
      alert('document');
    })
    </script>
    

    事件捕获

    <div class="father"> <div class="son">son盒⼦</div>
    </div>
    <script>
    // 如果addEventListener() 第三个参数是 true 那么在捕获阶段触发
    // document -> html -> body -> father -> son
    var son = document.querySelector('.son');
    // 给son注册单击事件,第3个参数为true
    son.addEventListener('click', function() {
      alert('son');
    }, true);
    var father = document.querySelector('.father');
    // 给father注册单击事件,第3个参数为true
    father.addEventListener('click', function() {
      alert('father');
    }, true);
    // 给document注册单击事件,第3个参数为true
    document.addEventListener('click', function() {
      alert('document');
    }, true) </script>
    

    7.5. 事件对象

    什么是事件对象

    事件发⽣后,跟事件相关的⼀系列信息数据的集合都放到这个对象⾥⾯,这个对象就是事件对象。

    ⽐如:

    1. 谁绑定了这个事件。

    2. ⿏标触发事件的话,会得到⿏标的相关信息,如⿏标位置。

    3. 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。

    事件对象的使⽤

    事件触发发⽣时就会产⽣事件对象,并且系统会以实参的形式传给事件处理函数。所以,在事件处理函数中声明1个形参⽤来接收事件对象。

    image-20210802151949863

    事件对象的兼容性处理

    事件对象本身的获取存在兼容问题:

    1. 标准浏览器中是浏览器给⽅法传递的参数,只需要定义形参 e 就可以获取到。

    2. 在 IE6~8 中,浏览器不会给⽅法传递参数,如果需要的话,需要到 window.event 中获取查找。

    image-20210802152009485

    只要“||”前⾯为false, 不管“||”后⾯是true 还是 false,都返回 “||” 后⾯的值。
    只要“||”前⾯为true, 不管“||”后⾯是true 还是 false,都返回 “||” 前⾯的值。
    
    <div>123</div>
    <script>
    var div = document.querySelector('div');
    div.onclick = function(e) {
    // 事件对象
      e = e || window.event;
      console.log(e);
    }
    </script>
    

    事件对象的属性和⽅法

    image-20210802152034147

    e.target 和 this 的区别

    • this 是事件绑定的元素(绑定这个事件处理函数的元素) 。

    • e.target 是事件触发的元素。

      常情况下terget 和 this是⼀致的, 但有⼀种情况不同,那就是在事件冒泡时(⽗⼦元素有相同事
      件,单击⼦元素,⽗元素的事件处理函数也会被触发执⾏), 这时候this指向的是⽗元素,因为它
      是绑定事件的元素对象, ⽽target指向的是⼦元素,因为他是触发事件的那个具体元素对象。
      
    <div>123</div>
    <script>
    var div = document.querySelector('div');
    div.addEventListener('click', function(e) {
    // e.target 和 this指向的都是div
      console.log(e.target);
      console.log(this);
    });
    </script>
    

    事件冒泡下的e.target和this

    <ul><li>abc</li>
    <li>abc</li>
    <li>abc</li>
    </ul>
    <script>
    var ul = document.querySelector('ul');
    ul.addEventListener('click', function(e) {
    // 我们给ul 绑定了事件 那么this 就指向ul 
      console.log(this); // ul
    // e.target 触发了事件的对象 我们点击的是li e.target 指向的就是li
      console.log(e.target); // li
    });
    </script>
    

    7.6 阻⽌默认⾏为

    html中⼀些标签有默认⾏为,例如a标签被单击后,默认会进⾏⻚⾯跳转。

    href="javacript:void(0);"

    <a href="http://www.baidu.com">百度</a>
    <script>
    // 2. 阻⽌默认⾏为 让链接不跳转
    var a = document.querySelector('a');
    a.addEventListener('click', function(e) {
      e.preventDefault(); // dom 标准写法
    });
    // 3. 传统的注册⽅式
    a.onclick = function(e) {
    // 普通浏览器 e.preventDefault(); ⽅法
      e.preventDefault();
    // 低版本浏览器 ie678 returnValue 属性
      e.returnValue = false;
    // 我们可以利⽤return false 也能阻⽌默认⾏为 没有兼容性问题
      return false;
    }
    </script>
    

    7.7 阻⽌事件冒泡

    事件冒泡本身的特性,会带来的坏处,也会带来的好处。

    image-20210802152216247

    <div class="father"> <div class="son">son⼉⼦</div>
    </div>
    <script>
    var son = document.querySelector('.son');
    // 给son注册单击事件
    son.addEventListener('click', function(e) {
      alert('son');
      e.stopPropagation(); // stop 停⽌ Propagation 传播
      window.event.cancelBubble = true; // ⾮标准 cancel 取消 bubble 泡 泡
    }, false);
    var father = document.querySelector('.father');
    // 给father注册单击事件
    father.addEventListener('click', function() {
      alert('father');
    }, false);
    // 给document注册单击事件
    document.addEventListener('click', function() {
      alert('document');
    })
    </script>
    

    阻⽌事件冒泡的兼容性处理

    image-20210802152234017

    7.8 事件委托

    事件冒泡本身的特性,会带来的坏处,也会带来的好处。

    什么是事件委托

    把事情委托给别⼈,代为处理。

    事件委托也称为事件代理,在 jQuery ⾥⾯称为事件委派。

    说⽩了就是,不给⼦元素注册事件,给⽗元素注册事件,把处理代码在⽗元素的事件中执⾏。

    ⽣活中的代理:

    image-20210802152251578

    js事件中的代理:

    image-20210802152317580

    事件委托的原理

    给⽗元素注册事件,利⽤事件冒泡,当⼦元素的事件触发,会冒泡到⽗元素,然后去控制相应的⼦元素。

    事件委托的作⽤

    • 我们只操作了⼀次 DOM ,提⾼了程序的性能。
    • 动态新创建的⼦元素,也拥有事件。
    <ul><li>知否知否,点我应有弹框在⼿!</li>
    <li>知否知否,点我应有弹框在⼿!</li>
    <li>知否知否,点我应有弹框在⼿!</li>
    <li>知否知否,点我应有弹框在⼿!</li>
    <li>知否知否,点我应有弹框在⼿!</li>
    </ul>
    <script>
    // 事件委托的核⼼原理:给⽗节点添加侦听器, 利⽤事件冒泡影响每⼀个⼦节点
    var ul = document.querySelector('ul');
    ul.addEventListener('click', function(e) {
    // e.target 这个可以得到我们点击的对象
      e.target.style.backgroundColor = 'pink';
    })
    </script>
    

    8 - 常⽤⿏标事件

    image-20210802152356059

    8.1 mouseenter 和mouseover的区别

    • 当⿏标移动到元素上时就会触发mouseenter 事件
    • 类似 mouseover,它们两者之间的差别是
    • mouseover ⿏标经过⾃身盒⼦会触发,经过⼦盒⼦还会触发。mouseenter 只会经过⾃身盒⼦触发
    • 之所以这样,就是因为mouseenter不会冒泡
    • 跟mouseenter搭配⿏标离开 mouseleave 同样不会冒泡

    8.2 禁⽌选中⽂字和禁⽌右键菜单

    image-20210802152429547

    <body>
    我是⼀段不愿意分享的⽂字
    <script>
      // 1. contextmenu 我们可以禁⽤右键菜单
      document.addEventListener('contextmenu', function(e) {
        e.preventDefault();
      })
      // 2. 禁⽌选中⽂字 selectstart
      document.addEventListener('selectstart', function(e) {
        e.preventDefault();
      })
    </script>
    </body>
    

    8.3 ⿏标事件对象

    image-20210802152450570

    8.4 获取⿏标在⻚⾯的坐标

    <script>
    // ⿏标事件对象 MouseEvent
    document.addEventListener('click', function(e) {
    // 1. client ⿏标在可视区的x和y坐标
      console.log(e.clientX);
      console.log(e.clientY);
      console.log('---------------------');
    // 2. page ⿏标在⻚⾯⽂档的x和y坐标
      console.log(e.pageX);
      console.log(e.pageY);
      console.log('---------------------');
    // 3. screen ⿏标在电脑屏幕的x和y坐标
      console.log(e.screenX);
      console.log(e.screenY);
    })
    </script>
    

    image-20210802152520056

    <img src="images/angel.gif" alt=""> <script>
    var pic = document.querySelector('img');
    document.addEventListener('mousemove', function(e) {
    // 1. mousemove只要我们⿏标移动1px 就会触发这个事件
    // 2.核⼼原理: 每次⿏标移动,我们都会获得最新的⿏标坐标,
    // 把这个x和y坐标做为图⽚的top和left 值就可以移动图⽚
      var x = e.pageX;
      var y = e.pageY;
      console.log('x坐标是' + x, 'y坐标是' + y);
    //3 . 千万不要忘记给left 和top 添加px 单位
      pic.style.left = x - 50 + 'px';
      pic.style.top = y - 40 + 'px';
    });
    </script>
    

    9 - 常⽤的键盘事件

    9.1 键盘事件

    image-20210802152549636

    <script>
    // 常⽤的键盘事件
    //1. keyup 按键弹起的时候触发
    document.addEventListener('keyup', function() {
      console.log('我弹起了');
    })
    //3. keypress 按键按下的时候触发 不能识别功能键 ⽐如 ctrl shift 左右箭头
    啊
    document.addEventListener('keypress', function() {
      console.log('我按下了press');
    })
    //2. keydown 按键按下的时候触发 能识别功能键 ⽐如 ctrl shift 左右箭头啊
    document.addEventListener('keydown', function() {
      console.log('我按下了down');
    })
    // 4. 三个事件的执⾏顺序 keydown -- keypress -- keyup
    </script>
    

    9.2 键盘事件对象

    image-20210802152613504

    image-20210802152622234

    使⽤keyCode属性判断⽤户按下哪个键

    <script>
    // 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
    document.addEventListener('keyup', function(e) {
      console.log('up:' + e.keyCode);
    // 我们可以利⽤keycode返回的ASCII码值来判断⽤户按下了那个键
      if (e.keyCode === 65) {
        alert('您按下的a键');
      } else {
        alert('您没有按下a键')
      }
    })
    document.addEventListener('keypress', function(e) {
    // console.log(e);
      console.log('press:' + e.keyCode);
    })
    </script>
    

    案例:模拟京东按键输⼊内容

    当我们按下 s 键, 光标就定位到搜索框(⽂本框获得焦点)。

    image-20210802152647186

    <input type="text"> <script>
    // 获取输⼊框
    var search = document.querySelector('input');
    // 给document注册keyup事件
    document.addEventListener('keyup', function(e) {
    // 判断keyCode的值
      if (e.keyCode === 83) {
    // 触发输⼊框的获得焦点事件
        search.focus();
      }
    })
    </script>
    

    案例:模拟京东快递单号查询

    要求:当我们在⽂本框中输⼊内容时,⽂本框上⾯⾃动显示⼤字号的内容。

    image-20210802152720117

    <div class="search"> <div class="con">123</div>
    <input type="text" placeholder="请输⼊您的快递单号" class="jd"> </div>
    <script>
    // 获取要操作的元素
    var con = document.querySelector('.con');
    var jd_input = document.querySelector('.jd');
    // 给输⼊框注册keyup事件
    jd_input.addEventListener('keyup', function() {
    // 判断输⼊框内容是否为空
      if (this.value == '') {
    // 为空,隐藏放⼤提示盒⼦
        con.style.display = 'none';
      } else {
    // 不为空,显示放⼤提示盒⼦,设置盒⼦的内容
        con.style.display = 'block';
        con.innerText = this.value;
      }
    })
    // 给输⼊框注册失去焦点事件,隐藏放⼤提示盒⼦
    jd_input.addEventListener('blur', function() {
      con.style.display = 'none';
    })
    // 给输⼊框注册获得焦点事件
    jd_input.addEventListener('focus', function() {
    // 判断输⼊框内容是否为空
      if (this.value !== '') {
    // 不为空则显示提示盒⼦
        con.style.display = 'block';
      }
    })
    </script>
    

    10 - BOM

    10.1. 什么是BOM

    BOM(Browser Object Model)即浏览器对象模型,它提供了独⽴于内容⽽与浏览器窗⼝进⾏交互的对象,其核⼼对象是 window。

    BOM 由⼀系列相关的对象构成,并且每个对象都提供了很多⽅法与属性。

    BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的⼀部分。

    image-20210802152802581

    10.2. BOM的构成

    BOM ⽐ DOM 更⼤,它包含 DOM。

    image-20210802152815977

    10.3. 顶级对象window

    image-20210802152830705

    10.4. window对象的常⻅事件

    ⻚⾯(窗⼝)加载事件(3种)

    1

    image-20210802152842554

    window.onload 是窗⼝ (⻚⾯)加载事件,当⽂档内容完全加载完成会触发该事件(包括图像、脚本⽂

    件、CSS ⽂件等), 就调⽤的处理函数。

    image-20210802152853522

    2

    image-20210802152907416

    DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图⽚,flash等等。

    IE9以上才⽀持!!!

    如果⻚⾯的图⽚很多的话, 从⽤户访问到onload触发可能需要较⻓的时间, 交互效果就不能实现,必然影响⽤户的体验,此时⽤ DOMContentLoaded 事件⽐较合适。

    <script>
    window.addEventListener('load', function() {
      var btn = document.querySelector('button');
      btn.addEventListener('click', function() {
        alert('点击我');
      })
    })
    window.addEventListener('load', function() {
      alert(22);
    })
    document.addEventListener('DOMContentLoaded', function() {
      alert(33);
    })
    </script>
    

    3

    pageshow 事件,事件在⽤户浏览⽹⻚时触发。onpageshow 事件类似于 onload 事件,onload 事件在⻚⾯第⼀次加载时触发, onpageshow 事件在每次加载⻚⾯时触发,即 onload 事件在⻚⾯从浏览器缓存中读取时不触发。

    调整窗⼝⼤⼩事件

    image-20210802152951728

    window.onresize 是调整窗⼝⼤⼩加载事件, 当触发时就调⽤的处理函数。

    注意:

    1. 只要窗⼝⼤⼩发⽣像素变化,就会触发这个事件。

    2. 我们经常利⽤这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度

    <script>
    // 注册⻚⾯加载事件
    window.addEventListener('load', function() {
      var div = document.querySelector('div');
    // 注册调整窗⼝⼤⼩事件
      window.addEventListener('resize', function() {
    // window.innerWidth 获取窗⼝⼤⼩
        console.log('变化了');
        if (window.innerWidth <= 800) {
          div.style.display = 'none';
        } else {
          div.style.display = 'block';
        }
      })
    })
    </script>
    <div></div>
    

    10.5. 定时器(两种)

    window 对象给我们提供了 2 个⾮常好⽤的⽅法-定时器。

    • setTimeout()
    • setInterval()

    setTimeout() 炸弹定时器

    开启定时器

    image-20210802153056318

    image-20210802153106725

    普通函数是按照代码顺序直接调⽤。
    简单理解: 回调,就是回头调⽤的意思。上⼀件事⼲完,再回头再调⽤这个函数。
    例如:定时器中的调⽤函数,事件处理函数,也是回调函数。
    以前我们讲的 element.onclick = function(){} 或者
    element.addEventListener(“click”, fn); ⾥⾯的 函数也是回调函数。
    
    <script>
    // 回调函数是⼀个匿名函数
    setTimeout(function() {
      console.log('时间到了');
    }, 2000);
    function callback() {
      console.log('爆炸了');
    }
    // 回调函数是⼀个有名函数
    var timer1 = setTimeout(callback, 3000);
    var timer2 = setTimeout(callback, 5000);
    </script>
    

    案例:5秒后关闭⼴告

    image-20210802153132576

    image-20210802153139556

    <body><img src="images/ad.jpg" alt="" class="ad"> <script>
      // 获取要操作的元素
      var ad = document.querySelector('.ad');
      // 开启定时器
      setTimeout(function() {
        ad.style.display = 'none';
      }, 5000);
    </script>
    </body>
    

    停⽌定时器

    image-20210802153155628

    <button>点击停⽌定时器</button>
    <script>
    var btn = document.querySelector('button');
    // 开启定时器
    var timer = setTimeout(function() {
      console.log('爆炸了');
    }, 5000);
    // 给按钮注册单击事件
    btn.addEventListener('click', function() {
    // 停⽌定时器
      clearTimeout(timer);
    })
    </script>
    

    setInterval() 闹钟定时器

    开启定时器

    image-20210802153218592

    <script>
    // 1. setInterval
    setInterval(function() {
      console.log('继续输出');
    }, 1000);
    </script>
    

    案例:倒计时

    image-20210802153242580

    image-20210802153250581

    <div><span class="hour">1</span>
    <span class="minute">2</span>
    <span class="second">3</span>
    </div>
    <script>
    // 1. 获取元素(时分秒盒⼦)
    var hour = document.querySelector('.hour'); // ⼩时的⿊⾊盒⼦
    var minute = document.querySelector('.minute'); // 分钟的⿊⾊盒⼦
    var second = document.querySelector('.second'); // 秒数的⿊⾊盒⼦
    var inputTime = +new Date('2019-5-1 18:00:00'); // 返回的是⽤户输⼊时间
    总的毫秒数
    countDown(); // 我们先调⽤⼀次这个函数,防⽌第⼀次刷新⻚⾯有空⽩
    // 2. 开启定时器
    setInterval(countDown, 1000);
    function countDown() {
      var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
      var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒
      数
      var h = parseInt(times / 60 / 60 % 24); //时 h = h < 10 ? '0' + h : h;
      hour.innerHTML = h; // 把剩余的⼩时给 ⼩时⿊⾊盒⼦
      var m = parseInt(times / 60 % 60); // 分 m = m < 10 ? '0' + m : m;
      minute.innerHTML = m;
      var s = parseInt(times % 60); // 当前的秒
      s = s < 10 ? '0' + s : s;
      second.innerHTML = s;
    }
    </script>
    

    停⽌定时器

    image-20210802153312558

    案例:发送短信倒计时

    点击按钮后,该按钮60秒之内不能再次点击,防⽌重复发送短信。

    image-20210802153335113

    ⼿机号码: <input type="number"> <button>发送</button>
    <script>
    var btn = document.querySelector('button');
    // 全局变量,定义剩下的秒数
    var time = 3;
    // 注册单击事件
    btn.addEventListener('click', function() {
    // 禁⽤按钮
      btn.disabled = true;
    // 开启定时器
      var timer = setInterval(function() {
    // 判断剩余秒数
        if (time == 0) {
    // 清除定时器和复原按钮
          clearInterval(timer);
          btn.disabled = false;
          btn.innerHTML = '发送';
        } else {
          btn.innerHTML = '还剩下' + time + '秒';
          time--;
        }
      }, 1000);
    });
    </script>
    

    10.6. this指向问题

    this的指向在函数定义的时候是确定不了的,只有函数执⾏的时候才能确定this到底指向谁,⼀般情况下this的最终指向的是那个调⽤它的对象。

    现阶段,我们先了解⼀下⼏个this指向

    1. 全局作⽤域或者普通函数中this指向全局对象window(注意定时器⾥⾯的this指向window)

    2. ⽅法调⽤中谁调⽤this指向谁

    3. 构造函数中this指向构造函数的实例

    <button>点击</button>
    <script>
    // this 指向问题 ⼀般情况下this的最终指向的是那个调⽤它的对象
    // 1. 全局作⽤域或者普通函数中this指向全局对象window( 注意定时器⾥⾯的
    this指向window)
    console.log(this);
    function fn() {
      console.log(this);
    }
    window.fn();
    window.setTimeout(function() {
      console.log(this);
    }, 1000);
    // 2. ⽅法调⽤中谁调⽤this指向谁
    var o = {
      sayHi: function() {
        console.log(this); // this指向的是 o 这个对象
      }
    }
    o.sayHi();
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
      console.log(this); // 事件处理函数中的this指向的是btn这个按钮对
      象
    })
    // 3. 构造函数中this指向构造函数的实例
    function Fun() {
      console.log(this); // this 指向的是fun 实例对象
    }
    var fun = new Fun();
    </script>
    

    10.7. location对象

    什么是 location 对象

    image-20210802153439178

    URL

    image-20210802153449478

    location 对象的属性

    image-20210802153519728

    案例:5分钟⾃动跳转⻚⾯

    image-20210802153534573

    <button>点击</button>
    <div></div>
    <script>
    var btn = document.querySelector('button');
    var div = document.querySelector('div');
    btn.addEventListener('click', function() {
    // console.log(location.href);
      location.href = 'http://www.itcast.cn';
    })
    var timer = 5;
    setInterval(function() {
      if (timer == 0) {
        location.href = 'http://www.itcast.cn';
      } else {
        div.innerHTML = '您将在' + timer + '秒钟之后跳转到⾸⻚';
        timer--;
      }
    }, 1000);
    </script>
    

    案例:获取URL参数

    image-20210802153602815

    <div></div>
    <script>
    console.log(location.search); // ?uname=andy
    // 1.先去掉? substr('起始的位置',截取⼏个字符);
    var params = location.search.substr(1); // uname=andy
    console.log(params);
    // 2. 利⽤=把字符串分割为数组 split('=');
    var arr = params.split('=');
    console.log(arr); // ["uname", "ANDY"]
    var div = document.querySelector('div');
    // 3.把数据写⼊div中
    div.innerHTML = arr[1] + '欢迎您'; </script>
    

    location对象的常⻅⽅法

    image-20210802153633506

    <button>点击</button>
    <script>
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
    // 记录浏览历史,所以可以实现后退功能
    // location.assign('http://www.itcast.cn');
    // 不记录浏览历史,所以不可以实现后退功能
    // location.replace('http://www.itcast.cn');
      location.reload(true);
    })
    </script>
    

    10.8. navigator对象

    navigator 对象包含有关浏览器的信息,它有很多属性,我们最常⽤的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。

    下⾯前端代码可以判断⽤户那个终端打开⻚⾯,实现跳转

    if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mo
    bile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Sym
    bian|Windows Phone)/i))) {
    window.location.href = ""; //⼿机
    } else {
    window.location.href = ""; //电脑
    }
    

    10.9 history对象

    window对象给我们提供了⼀个 history对象,与浏览器历史记录进⾏交互。该对象包含⽤户(在浏览器

    窗⼝中)访问过的URL。

    image-20210802154807050

    history对象⼀般在实际开发中⽐较少⽤,但是会在⼀些 OA 办公系统中⻅到。

    image-20210802154821218

    11 - JS执⾏机制

    以下代码执⾏的结果是什么?

    console.log(1);
    setTimeout(function () {
    console.log(3);
    }, 1000);
    console.log(2);
    

    以下代码执⾏的结果是什么?

    console.log(1);
    setTimeout(function () {
    console.log(3);
    }, 0);
    console.log(2);
    

    11.1 JS 是单线程

    image-20210802154928122

    单线程就意味着,所有任务需要排队,前⼀个任务结束,才会执⾏后⼀个任务。如果前⼀个任
    务耗时很⻓,后⼀个任务就不得不⼀直等着。
    这样所导致的问题是: 如果 JS 执⾏的时间过⻓,这样就会造成⻚⾯的渲染不连贯,导致⻚
    ⾯渲染加载阻塞的感觉。
    

    11.2 同步任务和异步任务

    单线程导致的问题就是后⾯的任务等待前⾯任务完成,如果前⾯任务很耗时(⽐如读取⽹络数据),后⾯任务不得不⼀直等待!!

    为了解决这个问题,利⽤多核 CPU 的计算能⼒,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是⼦线程完全受主线程控制。于是,JS 中出现了同步任务和异步任务。

    同步

    前⼀个任务结束后再执⾏后⼀个任务,程序的执⾏顺序与任务的排列顺序是⼀致的、同步的。⽐如做饭的同步做法:我们要烧⽔煮饭,等⽔开了(10分钟之后),再去切菜,炒菜。

    异步

    你在做⼀件事情时,因为这件事情会花费很⻓时间,在做这件事的同时,你还可以去处理其他事情。⽐如做饭的异步做法,我们在烧⽔的同时,利⽤这10分钟,去切菜,炒菜。

    image-20210802155012490

    JS中所有任务可以分成两种,⼀种是同步任务(synchronous),另⼀种是异步任务
    (asynchronous)。
    同步任务指的是:
    在主线程上排队执⾏的任务,只有前⼀个任务执⾏完毕,才能执⾏后⼀个任务;
    异步任务指的是:
    不进⼊主线程、⽽进⼊”任务队列”的任务,当主线程中的任务运⾏完了,才会从”任务队
    列”取出异步任务放⼊主线程执⾏。
    

    image-20210802155038495

    11.3 JS执⾏机制(事件循环)

    image-20210802155051295

    image-20210802155058809

    11.4 代码思考题

    console.log(1);
    document.onclick = function() {
    console.log('click');
    }
    setTimeout(function() {
    console.log(3)
    }, 3000)
    console.log(2);
    

    12 - 元素偏移量 OFFSET 系列

    12.1 offset 概述

    offset 翻译过来就是偏移量, 我们使⽤ offset系列相关属性可以动态的得到该元素的位置(偏移)、⼤⼩等。

    1. 获得元素距离带有定位⽗元素的位置

    2. 获得元素⾃身的⼤⼩(宽度⾼度)

    3. 注意:返回的数值都不带单位

    image-20210802155139338

    12.2 offset 与 style 区别

    offset

    • offset 可以得到任意样式表中的样式值
    • offset 系列获得的数值是没有单位的
    • offsetWidth 包含padding+border+width
    • offsetWidth 等属性是只读属性,只能获取不能赋值
    • 所以,我们想要获取元素⼤⼩位置,⽤offset更合适

    style

    • style 只能得到⾏内样式表中的样式值
    • style.width 获得的是带有单位的字符串
    • style.width 获得不包含padding和border 的值
    • style.width 是可读写属性,可以获取也可以赋值
    • 所以,我们想要给元素更改值,则需要⽤style改变
    • 因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

    案例:获取⿏标在盒⼦内的坐标

    1. 我们在盒⼦内点击,想要得到⿏标距离盒⼦左右的距离。

    2. ⾸先得到⿏标在⻚⾯中的坐标(e.pageX, e.pageY)

    3. 其次得到盒⼦在⻚⾯中的距离 ( box.offsetLeft, box.offsetTop)

    4. ⽤⿏标距离⻚⾯的坐标减去盒⼦在⻚⾯中的距离,得到 ⿏标在盒⼦内的坐标

    5. 如果想要移动⼀下⿏标,就要获取最新的坐标,使⽤⿏标移动

    var box = document.querySelector('.box');
    box.addEventListener('mousemove', function(e) {
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
    })
    

    案例:模态框拖拽

    弹出框,我们也称为模态框。

    1.点击弹出层,会弹出模态框, 并且显示灰⾊半透明的遮挡层。

    2.点击关闭按钮,可以关闭模态框,并且同时关闭灰⾊半透明遮挡层。

    3.⿏标放到模态框最上⾯⼀⾏,可以按住⿏标拖拽模态框在⻚⾯中移动。

    4.⿏标松开,可以停⽌拖动模态框移动

    案例分析:

    1. 点击弹出层, 模态框和遮挡层就会显示出来 display:block;

    2. 点击关闭按钮,模态框和遮挡层就会隐藏起来 display:none;

    3. 在⻚⾯中拖拽的原理:⿏标按下并且移动, 之后松开⿏标

    4. 触发事件是⿏标按下mousedown,⿏标移动mousemove ⿏标松开 mouseup

    5. 拖拽过程: ⿏标移动过程中,获得最新的值赋值给模态框的left和top值,这样模态框可以跟着⿏标⾛了

    6. ⿏标按下触发的事件源是最上⾯⼀⾏,就是 id 为 title

    7. ⿏标的坐标减去 ⿏标在盒⼦内的坐标, 才是模态框真正的位置。

    8. ⿏标按下,我们要得到⿏标在盒⼦的坐标。

    9. ⿏标移动,就让模态框的坐标 设置为 :⿏标坐标 减去盒⼦坐标即可,注意移动事件写到按下事件⾥⾯。

    10. ⿏标松开,就停⽌拖拽,就是可以让⿏标移动事件解除

    // 1. 获取元素
    var login = document.querySelector('.login');
    var mask = document.querySelector('.login-bg');
    var link = document.querySelector('#link');
    var closeBtn = document.querySelector('#closeBtn');
    var title = document.querySelector('#title');
    // 2. 点击弹出层这个链接 link 让mask 和login 显示出来
    link.addEventListener('click', function() {
    mask.style.display = 'block';
    login.style.display = 'block';
    })
    // 3. 点击 closeBtn 就隐藏 mask 和 login
    closeBtn.addEventListener('click', function() {
    mask.style.display = 'none';
    login.style.display = 'none';
    })
    // 4. 开始拖拽
    // (1) 当我们⿏标按下, 就获得⿏标在盒⼦内的坐标
    title.addEventListener('mousedown', function(e) {
    var x = e.pageX - login.offsetLeft;
    var y = e.pageY - login.offsetTop;
    // (2) ⿏标移动的时候,把⿏标在⻚⾯中的坐标,减去 ⿏标在盒⼦内的坐标就
    是模态框的left和top值
    document.addEventListener('mousemove', move)
    function move(e) {
    login.style.left = e.pageX - x + 'px';
    login.style.top = e.pageY - y + 'px';
    }
    // (3) ⿏标弹起,就让⿏标移动事件移除
    document.addEventListener('mouseup', function() {
    document.removeEventListener('mousemove', move);
    })
    })
    

    案例:仿京东放⼤镜

    1. 整个案例可以分为三个功能模块

    2. ⿏标经过⼩图⽚盒⼦, ⻩⾊的遮挡层 和 ⼤图⽚盒⼦显示,离开隐藏2个盒⼦功能

    3. ⻩⾊的遮挡层跟随⿏标功能。

    4. 移动⻩⾊遮挡层,⼤图⽚跟随移动功能。

    案例分析:

    1. ⻩⾊的遮挡层跟随⿏标功能。

    2. 把⿏标坐标给遮挡层不合适。因为遮挡层坐标以⽗盒⼦为准。

    3. ⾸先是获得⿏标在盒⼦的坐标。

    4. 之后把数值给遮挡层做为left 和top值。

    5. 此时⽤到⿏标移动事件,但是还是在⼩图⽚盒⼦内移动。

    6. 发现,遮挡层位置不对,需要再减去盒⼦⾃身⾼度和宽度的⼀半。

    7. 遮挡层不能超出⼩图⽚盒⼦范围。

    8. 如果⼩于零,就把坐标设置为0

    9. 如果⼤于遮挡层最⼤的移动距离,就把坐标设置为最⼤的移动距离

    10. 遮挡层的最⼤移动距离:⼩图⽚盒⼦宽度 减去 遮挡层盒⼦宽度

    window.addEventListener('load', function() {
    var preview_img = document.querySelector('.preview_img');
    var mask = document.querySelector('.mask');
    var big = document.querySelector('.big');
    // 1. 当我们⿏标经过 preview_img 就显示和隐藏 mask 遮挡层 和 big ⼤盒⼦
    preview_img.addEventListener('mouseover', function() {
    mask.style.display = 'block';
    big.style.display = 'block';
    })
    preview_img.addEventListener('mouseout', function() {
    mask.style.display = 'none';
    big.style.display = 'none';
    })
    // 2. ⿏标移动的时候,让⻩⾊的盒⼦跟着⿏标来⾛
    preview_img.addEventListener('mousemove', function(e) {
    // (1). 先计算出⿏标在盒⼦内的坐标
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    // console.log(x, y);
    // (2) 减去盒⼦⾼度 300的⼀半 是 150 就是我们mask 的最终 left 和top值了
    // (3) 我们mask 移动的距离
    var maskX = x - mask.offsetWidth / 2;
    var maskY = y - mask.offsetHeight / 2;
    // (4) 如果x 坐标⼩于了0 就让他停在0 的位置
    // 遮挡层的最⼤移动距离
    var maskMax = preview_img.offsetWidth - mask.offsetWidth;
    if (maskX <= 0) {
    maskX = 0;
    } else if (maskX >= maskMax) {
    maskX = maskMax;
    }
    if (maskY <= 0) {
    maskY = 0;
    } else if (maskY >= maskMax) {
    maskY = maskMax;
    }
    mask.style.left = maskX + 'px';
    mask.style.top = maskY + 'px';
    // 3. ⼤图⽚的移动距离 = 遮挡层移动距离 * ⼤图⽚最⼤移动距离 / 遮挡层的最⼤
    移动距离
    // ⼤图
    var bigIMg = document.querySelector('.bigImg');
    // ⼤图⽚最⼤移动距离
    var bigMax = bigIMg.offsetWidth - big.offsetWidth;
    // ⼤图⽚的移动距离 X Y
    var bigX = maskX * bigMax / maskMax;
    var bigY = maskY * bigMax / maskMax;
    bigIMg.style.left = -bigX + 'px';
    bigIMg.style.top = -bigY + 'px';
    })
    })
    

    13 - 元素可视区 CLIENT 系列

    13.1 client概述

    client 翻译过来就是客户端,我们使⽤ client 系列的相关属性来获取元素可视区的相关信息。通过client 系列的相关属性可以动态的得到该元素的边框⼤⼩、元素⼤⼩等。

    image-20210802155502694

    image-20210802155509760

    13.2. 淘宝 flexible.js 源码分析

    ⽴即执⾏函数 (function(){})() 或者 (function(){}())

    主要作⽤: 创建⼀个独⽴的作⽤域。 避免了命名冲突问题

    下⾯三种情况都会刷新⻚⾯都会触发 load 事件。

    1.a标签的超链接

    2.F5或者刷新按钮(强制刷新)

    3.前进后退按钮

    但是 ⽕狐中,有个特点,有个“往返缓存”,这个缓存中不仅保存着⻚⾯数据,还保存了DOM和JavaScript的状态;实际上是将整个⻚⾯都保存在了内存⾥。

    所以此时后退按钮不能刷新⻚⾯。

    此时可以使⽤ pageshow事件来触发。,这个事件在⻚⾯显示时触发,⽆论⻚⾯是否来⾃缓存。在重新加载⻚⾯中,pageshow会在load事件触发后触发;根据事件对象中的persisted来判断是否是缓存中的⻚⾯触发的pageshow事件

    注意这个事件给window添加。

    14 - 元素滚动 SCROLL 系列

    14.1. scroll 概述

    scroll 翻译过来就是滚动的,我们使⽤ scroll 系列的相关属性可以动态的得到该元素的⼤⼩、滚动距离

    等。

    image-20210802155610834

    14.2. ⻚⾯被卷去的头部

    如果浏览器的⾼(或宽)度不⾜以显示整个⻚⾯时,会⾃动出现滚动条。当滚动条向下滚动时,⻚⾯上⾯被隐藏掉的⾼度,我们就称为⻚⾯被卷去的头部。滚动条在滚动时会触发 onscroll事件。

    查看⻚⾯被卷出的部分⽤ window.pageYoffset 和 window.pageXoffset 来 查 看 , 和

    scrollTop 、 scrollLeft 的区别是⼀个是针对⻚⾯ document 的⼀个是针对⻚⾯元素的。

    案例:仿淘宝固定右侧侧边栏

    1. 原先侧边栏是绝对定位

    2. 当⻚⾯滚动到⼀定位置,侧边栏改为固定定位

    3. ⻚⾯继续滚动,会让 返回顶部显示出来

    案例分析:

    1. 需要⽤到⻚⾯滚动事件 scroll 因为是⻚⾯滚动,所以事件源是document

    2. 滚动到某个位置,就是判断⻚⾯被卷去的上部值。

    3. ⻚ ⾯ 被 卷 去 的 头 部 : 可 以 通 过 window.pageYOffset 获 得 如果是被卷去的左侧window.pageXOffset

    4. 注 意 , 元 素 被 卷 去 的 头 部 是 element.scrollTop , 如果是⻚⾯被卷去的头部 则 是window.pageYOffset

    5. 其实这个值 可以通过盒⼦的 offsetTop可以得到,如果⼤于等于这个值,就可以让盒⼦固定定位了

    //1. 获取元素
    var sliderbar = document.querySelector('.slider-bar');
    var banner = document.querySelector('.banner');
    // banner.offestTop 就是被卷去头部的⼤⼩ ⼀定要写到滚动的外⾯
    var bannerTop = banner.offsetTop
    // 当我们侧边栏固定定位之后应该变化的数值
    var sliderbarTop = sliderbar.offsetTop - bannerTop;
    // 获取main 主体元素
    var main = document.querySelector('.main');
    var goBack = document.querySelector('.goBack');
    var mainTop = main.offsetTop;
    // 2. ⻚⾯滚动事件 scroll
    document.addEventListener('scroll', function() {
    // console.log(11);
    // window.pageYOffset ⻚⾯被卷去的头部
    // console.log(window.pageYOffset);
    // 3 .当我们⻚⾯被卷去的头部⼤于等于了 172 此时 侧边栏就要改为固定定位
    if (window.pageYOffset >= bannerTop) {
    sliderbar.style.position = 'fixed';
    sliderbar.style.top = sliderbarTop + 'px';
    } else {
    sliderbar.style.position = 'absolute';
    sliderbar.style.top = '300px';
    }
    // 4. 当我们⻚⾯滚动到main盒⼦,就显示 goback模块
    if (window.pageYOffset >= mainTop) {
    goBack.style.display = 'block';
    } else {
    goBack.style.display = 'none';
    }
    })
    

    14.3. ⻚⾯被卷去的头部兼容性解决⽅案

    需要注意的是,⻚⾯被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下⼏种写法:

    1. 声明了 DTD,使⽤ document.documentElement.scrollTop

    2. 未声明 DTD,使⽤ document.body.scrollTop

    3. 新⽅法 window.pageYOffset和 window.pageXOffset,IE9 开始⽀持

    function getScroll() {
    return {
    left: window.pageXOffset || document.documentElement.scrollLeft ||
    document.body.scrollLeft||0,
    top: window.pageYOffset || document.documentElement.scrollTop ||
    document.body.scrollTop || 0
    };
    }
    使⽤的时候 getScroll().left
    

    15 - 三⼤系列总结

    image-20210802155738366

    他们主要⽤法:

    1.offset系列 经常⽤于获得元素位置 offsetLeft offsetTop

    2.client经常⽤于获取元素⼤⼩ clientWidth clientHeight

    3.scroll 经常⽤于获取滚动距离 scrollTop scrollLeft

    4.注意⻚⾯滚动的距离通过 window.pageXOffset 获得

    16 - 动画函数封装

    动画实现原理

    核⼼原理:通过定时器 setInterval() 不断移动盒⼦位置。

    实现步骤:

    1. 获得盒⼦当前位置

    2. 让盒⼦在当前位置加上1个移动距离

    3. 利⽤定时器不断重复这个操作

    4. 加⼀个结束定时器的条件

    5. 注意此元素需要添加定位,才能使⽤element.style.left

    动画函数给不同元素记录不同定时器

    如果多个元素都使⽤这个动画函数,每次都要var 声明定时器。我们可以给不同的元素使⽤不同的定时器(⾃⼰专⻔⽤⾃⼰的定时器)。

    核⼼原理:利⽤ JS 是⼀⻔动态语⾔,可以很⽅便的给当前对象添加属性。

    function animate(obj, target) {
    // 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时
    器
    // 解决⽅案就是 让我们元素只有⼀个定时器执⾏
    // 先清除以前的定时器,只保留当前的⼀个定时器执⾏
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
    if (obj.offsetLeft >= target) {
    // 停⽌动画 本质是停⽌定时器
    clearInterval(obj.timer);
    }
    obj.style.left = obj.offsetLeft + 1 + 'px';
    }, 30);
    }
    

    缓动效果原理

    缓动动画就是让元素运动速度有所变化,最常⻅的是让速度慢慢停下来

    思路:

    1. 让盒⼦每次移动的距离慢慢变⼩,速度就会慢慢落下来。

    2. 核⼼算法: (⽬标值 - 现在的位置) / 10 做为每次移动的距离步⻓

    3. 停⽌的条件是: 让当前盒⼦位置等于⽬标位置就停⽌定时器

    4. 注意步⻓值需要取整

    动画函数多个⽬标值之间移动

    可以让动画函数从 800 移动到 500。

    当我们点击按钮时候,判断步⻓是正值还是负值

    1.如果是正值,则步⻓往⼤了取整

    2.如果是负值,则步⻓ 向⼩了取整

    动函数添加回调函数

    回调函数原理:函数可以作为⼀个参数。将这个函数作为参数传到另⼀个函数⾥⾯,当那个函数执⾏完之后,再执⾏传进去的这个函数,这个过程就叫做回调。

    回调函数写的位置:定时器结束的位置。

    动画完整版代码

    function animate(obj, target, callback) {
    // console.log(callback); callback = function() {} 调⽤的时候 callback()
    // 先清除以前的定时器,只保留当前的⼀个定时器执⾏
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
    // 步⻓值写到定时器的⾥⾯
    // 把我们步⻓值改为整数 不要出现⼩数的问题
    // var step = Math.ceil((target - obj.offsetLeft) / 10);
    var step = (target - obj.offsetLeft) / 10;
    step = step > 0 ? Math.ceil(step) : Math.floor(step);
    if (obj.offsetLeft == target) {
    // 停⽌动画 本质是停⽌定时器
    clearInterval(obj.timer);
    // 回调函数写到定时器结束⾥⾯
    // if (callback) {
    // // 调⽤函数
    // callback();
    // }
    callback && callback();
    }
    // 把每次加1 这个步⻓值改为⼀个慢慢变⼩的值 步⻓公式:(⽬标值 - 现在的位
    置) / 10
    obj.style.left = obj.offsetLeft + step + 'px';
    }, 15);
    }
    

    17 - 常⻅⽹⻚特效案例

    17.1. ⽹⻚轮播图

    轮播图也称为焦点图,是⽹⻚中⽐较常⻅的⽹⻚特效。功能需求:

    1.⿏标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。

    2.点击右侧按钮⼀次,图⽚往左播放⼀张,以此类推,左侧按钮同理。

    3.图⽚播放的同时,下⾯⼩圆圈模块跟随⼀起变化。

    4.点击⼩圆圈,可以播放相应图⽚。

    5.⿏标不经过轮播图,轮播图也会⾃动播放图⽚。

    6.⿏标经过,轮播图模块, ⾃动播放停⽌。

    window.addEventListener('load', function() {
    // 1. 获取元素
    var arrow_l = document.querySelector('.arrow-l');
    var arrow_r = document.querySelector('.arrow-r');
    var focus = document.querySelector('.focus');
    var focusWidth = focus.offsetWidth;
    // 2. ⿏标经过focus 就显示隐藏左右按钮
    focus.addEventListener('mouseenter', function() {
    arrow_l.style.display = 'block';
    arrow_r.style.display = 'block';
    clearInterval(timer);
    timer = null; // 清除定时器变量
    });
    focus.addEventListener('mouseleave', function() {
    arrow_l.style.display = 'none';
    arrow_r.style.display = 'none';
    timer = setInterval(function() {
    //⼿动调⽤点击事件
    arrow_r.click();
    }, 2000);
    });
    // 3. 动态⽣成⼩圆圈 有⼏张图⽚,我就⽣成⼏个⼩圆圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    // console.log(ul.children.length);
    for (var i = 0; i < ul.children.length; i++) {
    // 创建⼀个⼩li
    var li = document.createElement('li');
    // 记录当前⼩圆圈的索引号 通过⾃定义属性来做
    li.setAttribute('index', i);
    // 把⼩li插⼊到ol ⾥⾯
    ol.appendChild(li);
    // 4. ⼩圆圈的排他思想 我们可以直接在⽣成⼩圆圈的同时直接绑定点击事件
    li.addEventListener('click', function() {
    // ⼲掉所有⼈ 把所有的⼩li 清除 current 类名
    for (var i = 0; i < ol.children.length; i++) {
    ol.children[i].className = '';
    }
    // 留下我⾃⼰ 当前的⼩li 设置current 类名
    this.className = 'current';
    // 5. 点击⼩圆圈,移动图⽚ 当然移动的是 ul
    // ul 的移动距离 ⼩圆圈的索引号 乘以 图⽚的宽度 注意是负值
    // 当我们点击了某个⼩li 就拿到当前⼩li 的索引号
    var index = this.getAttribute('index');
    // 当我们点击了某个⼩li 就要把这个li 的索引号给 num
    num = index;
    // 当我们点击了某个⼩li 就要把这个li 的索引号给 circle
    circle = index;
    // num = circle = index;
    console.log(focusWidth);
    console.log(index);
    animate(ul, -index * focusWidth);
    })
    }
    // 把ol⾥⾯的第⼀个⼩li设置类名为 current
    ol.children[0].className = 'current';
    // 6. 克隆第⼀张图⽚(li)放到ul 最后⾯
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7. 点击右侧按钮, 图⽚滚动⼀张
    var num = 0;
    // circle 控制⼩圆圈的播放
    var circle = 0;
    // flag 节流阀
    var flag = true;
    arrow_r.addEventListener('click', function() {
    if (flag) {
    flag = false; // 关闭节流阀
    // 如果⾛到了最后复制的⼀张图⽚,此时 我们的ul 要快速复原 left 改为 0
    if (num == ul.children.length - 1) {
    ul.style.left = 0;
    num = 0;
    }
    num++;
    animate(ul, -num * focusWidth, function() {
    flag = true; // 打开节流阀
    });
    // 8. 点击右侧按钮,⼩圆圈跟随⼀起变化 可以再声明⼀个变量控制⼩圆圈的播
    放
    circle++;
    // 如果circle == 4 说明⾛到最后我们克隆的这张图⽚了 我们就复原
    if (circle == ol.children.length) {
    circle = 0;
    }
    // 调⽤函数
    circleChange();
    }
    });
    // 9. 左侧按钮做法
    arrow_l.addEventListener('click', function() {
    if (flag) {
    flag = false;
    if (num == 0) {
    num = ul.children.length - 1;
    ul.style.left = -num * focusWidth + 'px';
    }
    num--;
    animate(ul, -num * focusWidth, function() {
    flag = true;
    });
    // 点击左侧按钮,⼩圆圈跟随⼀起变化 可以再声明⼀个变量控制⼩圆圈的播放
    circle--;
    // 如果circle < 0 说明第⼀张图⽚,则⼩圆圈要改为第4个⼩圆圈(3)
    // if (circle < 0) {
    // circle = ol.children.length - 1;
    // }
    circle = circle < 0 ? ol.children.length - 1 : circle;
    // 调⽤函数
    circleChange();
    }
    });
    function circleChange() {
    // 先清除其余⼩圆圈的current类名
    for (var i = 0; i < ol.children.length; i++) {
    ol.children[i].className = '';
    }
    // 留下当前的⼩圆圈的current类名
    ol.children[circle].className = 'current';
    }
    // 10. ⾃动播放轮播图
    var timer = setInterval(function() {
    //⼿动调⽤点击事件
    arrow_r.click();
    }, 2000);
    })
    

    17.2. 节流阀

    防⽌轮播图按钮连续点击造成播放过快。

    节流阀⽬的:当上⼀个函数动画内容执⾏完毕,再去执⾏下⼀个函数动画,让事件⽆法连续触发。

    核⼼实现思路:利⽤回调函数,添加⼀个变量来控制,锁住函数和解锁函数。

    开始设置⼀个变量var flag= true;If(flag){flag = false; do something} 关闭⽔⻰头

    利⽤回调函数动画执⾏完毕, flag = true 打开⽔⻰头

    17.3. 返回顶部

    1. 带有动画的返回顶部

    2. 此时可以继续使⽤我们封装的动画函数

    3. 只需要把所有的left 相关的值改为 跟 ⻚⾯垂直滚动距离相关就可以了

    4. ⻚⾯滚动了多少,可以通过 window.pageYOffset 得到

    5. 最后是⻚⾯滚动,使⽤ window.scroll(x,y)

    //1. 获取元素
    var sliderbar = document.querySelector('.slider-bar');
    var banner = document.querySelector('.banner');
    // banner.offestTop 就是被卷去头部的⼤⼩ ⼀定要写到滚动的外⾯
    var bannerTop = banner.offsetTop
    // 当我们侧边栏固定定位之后应该变化的数值
    var sliderbarTop = sliderbar.offsetTop - bannerTop;
    // 获取main 主体元素
    var main = document.querySelector('.main');
    var goBack = document.querySelector('.goBack');
    var mainTop = main.offsetTop;
    // 2. ⻚⾯滚动事件 scroll
    document.addEventListener('scroll', function() {
    // console.log(11);
    // window.pageYOffset ⻚⾯被卷去的头部
    // console.log(window.pageYOffset);
    // 3 .当我们⻚⾯被卷去的头部⼤于等于了 172 此时 侧边栏就要改为固定
    定位
    if (window.pageYOffset >= bannerTop) {
    sliderbar.style.position = 'fixed';
    sliderbar.style.top = sliderbarTop + 'px';
    } else {
    sliderbar.style.position = 'absolute';
    sliderbar.style.top = '300px';
    }
    // 4. 当我们⻚⾯滚动到main盒⼦,就显示 goback模块
    if (window.pageYOffset >= mainTop) {
    goBack.style.display = 'block';
    } else {
    goBack.style.display = 'none';
    }
    })
    // 3. 当我们点击了返回顶部模块,就让窗⼝滚动的⻚⾯的最上⽅
    goBack.addEventListener('click', function() {
    // ⾥⾯的x和y 不跟单位的 直接写数字即可
    // window.scroll(0, 0);
    // 因为是窗⼝滚动 所以对象是window
    animate(window, 0);
    });
    

    案例:筋头云案例

    1. 利⽤动画函数做动画效果

    2. 原先筋⽃云的起始位置是0

    3. ⿏标经过某个⼩li,把当前⼩li的offsetLeft 位置做为⽬标值即可

    4. ⿏标离开某个⼩li,就把⽬标值设为 0

    5. 如果点击了某个⼩li, 就把li当前的位置存储起来,做为筋⽃云的起始位置

    window.addEventListener('load', function() {
    // 1. 获取元素
    var cloud = document.querySelector('.cloud');
    var c_nav = document.querySelector('.c-nav');
    var lis = c_nav.querySelectorAll('li');
    // 2. 给所有的⼩li绑定事件
    // 这个current 做为筋⽃云的起始位置
    var current = 0;
    for (var i = 0; i < lis.length; i++) {
    // (1) ⿏标经过把当前⼩li 的位置做为⽬标值
    lis[i].addEventListener('mouseenter', function() {
    animate(cloud, this.offsetLeft);
    });
    // (2) ⿏标离开就回到起始的位置
    lis[i].addEventListener('mouseleave', function() {
    animate(cloud, current);
    });
    // (3) 当我们⿏标点击,就把当前位置做为⽬标值
    lis[i].addEventListener('click', function() {
    current = this.offsetLeft;
    });
    }
    })
    

    18 - 触屏事件

    18.1. 触屏事件概述

    移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放⼼的使⽤原⽣ JS 书写效果,但是移动端也有⾃⼰独特的地⽅。⽐如触屏事件 touch(也称触摸事件),Android和 IOS 都有。

    touch 对象代表⼀个触摸点。触摸点可能是⼀根⼿指,也可能是⼀根触摸笔。触屏事件可响应⽤户⼿指(或触控笔)对屏幕或者触控板操作。

    常⻅的触屏事件如下:

    image-20210802160157014

    18.2. 触摸事件对象(TouchEvent)

    TouchEvent 是⼀类描述⼿指在触摸平⾯(触摸屏、触摸板等)的状态变化的事件。这类事件⽤于描述⼀个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等

    touchstart、touchmove、touchend 三个事件都会各⾃有事件对象。

    触摸事件对象重点我们看三个常⻅对象列表:

    image-20210802160226913

    因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

    案例:移动端拖动元素

    1. touchstart、touchmove、touchend可以实现拖动元素

    2. 但是拖动元素需要当前⼿指的坐标值 我们可以使⽤ targetTouches[0] ⾥⾯的pageX 和pageY

    3. 移动端拖动的原理: ⼿指移动中,计算出⼿指移动的距离。然后⽤盒⼦原来的位置 + ⼿指移动的距离

    4. ⼿指移动的距离: ⼿指滑动中的位置 减去 ⼿指刚开始触摸的位置

    拖动元素三步曲:

    (1) 触摸元素 touchstart: 获取⼿指初始坐标,同时获得盒⼦原来的位置

    (2) 移动⼿指 touchmove: 计算⼿指的滑动距离,并且移动盒⼦

    (3) 离开⼿指 touchend:

    注意: ⼿指移动也会触发滚动屏幕所以这⾥要阻⽌默认的屏幕滚动 e.preventDefault();

    19 - 移动端常⻅特效

    19.1 移动轮播图

    移动端轮播图功能和基本PC端⼀致。

    1. 可以⾃动播放图⽚

    2. ⼿指可以拖动播放轮播图

    案例分析:

    1. ⾃动播放功能

    2. 开启定时器

    3. 移动端移动,可以使⽤translate 移动

    4. 想要图⽚优雅的移动,请添加过渡效果

    5. image-20210802160331853

    6. ⾃动播放功能-⽆缝滚动

    7. 注意,我们判断条件是要等到图⽚滚动完毕再去判断,就是过渡完成后判断

    8. 此时需要添加检测过渡完成事件 transitionend

    9. 判断条件:如果索引号等于 3 说明⾛到最后⼀张图⽚,此时 索引号要复原为 0

    10. 此时图⽚,去掉过渡效果,然后移动

    11. 如果索引号⼩于0, 说明是倒着⾛, 索引号等于2

    12. 此时图⽚,去掉过渡效果,然后移动

    image-20210802160354701

    20 - CLASSLIST 属性

    classList属性是HTML5新增的⼀个属性,返回元素的类名。但是ie10以上版本⽀持。

    该属性⽤于在元素中添加,移除及切换 CSS 类。有以下⽅法

    添加类:

    element.classList.add(’类名’);

    focus.classList.add('current');
    

    移除类:

    element.classList.remove(’类名’);

    focus.classList.remove('current');
    

    切换类:

    element.classList.toggle(’类名’);

    focus.classList.toggle('current');
    

    注意:以上⽅法⾥⾯,所有类名都不带点

    案例分析

    1. ⼩圆点跟随变化效果

    2. 把ol⾥⾯li带有current类名的选出来去掉类名 remove

    3. 让当前索引号的⼩li 加上 current add

    4. 但是,是等着过渡结束之后变化,所以这个写到 transitionend 事件⾥⾯

    image-20210802160455518

    1. ⼿指滑动轮播图

    2. 本质就是ul跟随⼿指移动,简单说就是移动端拖动元素

    3. 触摸元素touchstart: 获取⼿指初始坐标

    4. 移动⼿指touchmove: 计算⼿指的滑动距离,并且移动盒⼦

    5. 离开⼿指touchend: 根据滑动的距离分不同的情况

    6. 如果移动距离⼩于某个像素 就回弹原来位置

    7. 如果移动距离⼤于某个像素就上⼀张下⼀张滑动。

    8. 滑动也分为左滑动和右滑动判断的标准是 移动距离正负 如果是负值就是左滑 反之右滑

    9. 如果是左滑就播放下⼀张 (index++)

    10. 如果是右滑就播放上⼀张 (index--)

    image-20210802160521550

    image-20210802160529486

    案例:返回顶部

    当⻚⾯滚动某个地⽅,就显示,否则隐藏

    点击可以返回顶部

    案例分析

    1. 滚动某个地⽅显示

    2. 事件:scroll⻚⾯滚动事件

    3. 如果被卷去的头部(window.pageYOffset )⼤于某个数值

    4. 点击,window.scroll(0,0) 返回顶部

    image-20210802160554829

    21 - CLICK 延时解决⽅案

    移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) ⻚⾯。

    解决⽅案:

    1. 禁⽤缩放。 浏览器禁⽤默认的双击缩放⾏为并且去掉300ms 的点击延迟。
    <meta name="viewport" content="user-scalable=no">
    

    2.利⽤touch事件⾃⼰封装这个事件解决300ms 延迟。

    原理就是:

    1. 当我们⼿指触摸屏幕,记录当前触摸时间

    2. 当我们⼿指离开屏幕, ⽤离开的时间减去触摸的时间

    3. 如果时间⼩于150ms,并且没有滑动过屏幕, 那么我们就定义为点击

    4. 代码如下:

    //封装tap,解决click 300ms 延时
    function tap (obj, callback) {
    var isMove = false;
    var startTime = 0; // 记录触摸时候的时间变量
    obj.addEventListener('touchstart', function (e) {
    startTime = Date.now(); // 记录触摸时间
    });
    obj.addEventListener('touchmove', function (e) {
    isMove = true; // 看看是否有滑动,有滑动算拖拽,不算点击
    });
    obj.addEventListener('touchend', function (e) {
    if (!isMove && (Date.now() - startTime) < 150) { // 如果⼿指触摸
    和离开时间⼩于150ms 算点击
    callback && callback(); // 执⾏回调函数
    }
    isMove = false; // 取反 重置
    startTime = 0;
    });
    }
    //调⽤
    tap(div, function(){ // 执⾏代码 });
    
    1. 使⽤插件。fastclick 插件解决300ms 延迟。

    image-20210802160651737

    22 - 移动端常⽤开发插件

    22.1. 什么是插件

    移动端要求的是快速开发,所以我们经常会借助于⼀些插件来帮我完成操作,那么什么是插件呢?

    JS 插件是 js ⽂件,它遵循⼀定规范编写,⽅便程序展示效果,拥有特定功能且⽅便调⽤。如轮播图和瀑

    布流插件。

    特点:它⼀般是为了解决某个问题⽽专⻔存在,其功能单⼀,并且⽐较⼩。

    我们以前写的animate.js 也算⼀个最简单的插件

    fastclick 插件解决 300ms 延迟。 使⽤延时

    GitHub官⽹地址: https://github.com/ftlabs/fastclick

    22.2. 插件的使⽤

    1. 引⼊ js 插件⽂件。

    2. 按照规定语法使⽤。

    3. fastclick 插件解决 300ms 延迟。 使⽤延时

    4. GitHub官⽹地址: https://github.com/ftlabs/fastclick

    if ('addEventListener' in document) {
    document.addEventListener('DOMContentLoaded', function() {
    FastClick.attach(document.body);
    }, false);
    }
    

    22.3. Swiper 插件的使⽤

    中⽂官⽹地址: https://www.swiper.com.cn/

    1. 引⼊插件相关⽂件。

    2. 按照规定语法使⽤

    22.4. 其他移动端常⻅插件

    lsuperslide: http://www.superslide2.com/

    l iscroll: https://github.com/cubiq/iscroll

    22.5. 插件的使⽤总结

    1.确认插件实现的功能

    2.去官⽹查看使⽤说明

    3.下载插件

    4.打开demo实例⽂件,查看需要引⼊的相关⽂件,并且引⼊

    5.复制demo实例⽂件中的结构html,样式css以及js代码

    22.6. 移动端视频插件 zy.media.js

    H5 给我们提供了 video 标签,但是浏览器的⽀持情况不同。

    不同的视频格式⽂件,我们可以通过source解决。

    但是外观样式,还有暂停,播放,全屏等功能我们只能⾃⼰写代码解决。

    这个时候我们可以使⽤插件⽅式来制作。

    我们可以通过 JS 修改元素的⼤⼩、颜⾊、位置等样式。

    23 - 移动端常⽤开发框架

    23.1. 移动端视频插件 zy.media.js

    框架,顾名思义就是⼀套架构,它会基于⾃身的特点向⽤户提供⼀套较为完整的解决⽅案。框架的控制

    权在框架本身,使⽤者要按照框架所规定的某种规范进⾏开发。插件⼀般是为了解决某个问题⽽专⻔存在,其功能单⼀,并且⽐较⼩。

    前端常⽤的框架有 Bootstrap、Vue、Angular、React 等。既能开发PC端,也能开发移动端

    前端常⽤的移动端插件有 swiper、superslide、iscroll等。

    框架: ⼤⽽全,⼀整套解决⽅案

    插件: ⼩⽽专⼀,某个功能的解决⽅案

    23.2. Bootstrap

    Bootstrap 是⼀个简洁、直观、强悍的前端开发框架,它让 web 开发更迅速、简单。

    它能开发PC端,也能开发移动端

    Bootstrap JS插件使⽤步骤:

    1.引⼊相关js ⽂件

    2.复制HTML 结构

    3.修改对应样式

    4.修改相应JS 参数

    24 - 本地存储

    随着互联⽹的快速发展,基于⽹⻚的应⽤越来越普遍,同时也变的越来越复杂,为了满⾜各种各样的需

    求,会经常性在本地存储⼤量的数据,HTML5规范提出了相关解决⽅案。

    24.1.本地存储特性

    1、数据存储在⽤户浏览器中

    2、设置、读取⽅便、甚⾄⻚⾯刷新不丢失数据

    3、容量较⼤,sessionStorage约5M、localStorage约20M

    4、只能存储字符串,可以将对象JSON.stringify() 编码后存储

    24.2.window.sessionStorage

    1、⽣命周期为关闭浏览器窗⼝

    2、在同⼀个窗⼝(⻚⾯)下数据可以共享

    3、以键值对的形式存储使⽤

    存储数据:

    sessionStorage.setItem(key, value)
    

    获取数据:

    sessionStorage.getItem(key)
    

    删除数据:

    sessionStorage.removeItem(key)
    

    清空数据:(所有都清除掉)

    sessionStorage.clear()
    

    24.3.window.localStorage

    1、声明周期永久⽣效,除⾮⼿动删除 否则关闭⻚⾯也会存在

    2、可以多窗⼝(⻚⾯)共享(同⼀浏览器可以共享)

    3,以键值对的形式存储使⽤

    存储数据:

    localStorage.setItem(key, value)
    

    获取数据:

    localStorage.getItem(key)
    

    删除数据:

    localStorage.removeItem(key)
    

    清空数据:(所有都清除掉)

    localStorage.clear()
    

    案例:记住⽤户名

    如果勾选记住⽤户名, 下次⽤户打开浏览器,就在⽂本框⾥⾯⾃动显示上次登录的⽤户名

    案例分析

    1. 把数据存起来,⽤到本地存储

    2. 关闭⻚⾯,也可以显示⽤户名,所以⽤到localStorage

    3. 打开⻚⾯,先判断是否有这个⽤户名,如果有,就在表单⾥⾯显示⽤户名,并且勾选复选框

    4. 当复选框发⽣改变的时候change事件

    5. 如果勾选,就存储,否则就移除

    image-20210802160953330

  • 相关阅读:
    搞一个先试试
    java map排序
    文件上传
    文件下载
    Filter过滤器
    java编写一个简单的验证码
    centos7安装mysql
    linux安装jdk,tomcat服务器
    DBUtil工具类
    mysql
  • 原文地址:https://www.cnblogs.com/zgboy/p/15090387.html
Copyright © 2011-2022 走看看