自学js第十三天:JS的基础事件

;王道阮一峰写的DOM的事件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qi3mw41o-1620307183602)(C:\Users\tuyue\AppData\Local\Temp\1617207708116.png)]

EventTarget 接口

事件的本质是程序各个组成部分之间的一种’通信’方式,也是异步编程的一种实现。DOM 支持大量的事件,本章开始介绍 DOM 的事件编程。

目录 [隐藏]

概述

DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequestAudioNodeAudioContext)也部署了这个接口。

该接口主要提供三个实例方法。

  • addEventListener:绑定事件的监听函数
  • removeEventListener:移除事件的监听函数
  • dispatchEvent:触发事件

EventTarget.addEventListener()

EventTarget.addEventListener()用于在当前节点或对象上,定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。该方法没有返回值。

target.addEventListener(type, listener[, useCapture]);

该方法接受三个参数。

  • type:事件名称,大小写敏感。
  • listener:监听函数。事件发生时,会调用该监听函数。
  • useCapture:布尔值,表示监听函数是否在捕获阶段(capture)触发(参见后文《事件的传播》部分),默认为false(监听函数只在冒泡阶段被触发)。该参数可选。

下面是一个例子。

function hello() {
  console.log('Hello world');
}

var button = document.getElementById('btn');
button.addEventListener('click', hello, false);

上面代码中,button节点的addEventListener方法绑定click事件的监听函数hello,该函数只在冒泡阶段触发。

关于参数,有两个地方需要注意。

首先,第二个参数除了监听函数,还可以是一个具有handleEvent方法的对象。

buttonElement.addEventListener('click', {
  handleEvent: function (event) {
    console.log('click');
  }
});

上面代码中,addEventListener方法的第二个参数,就是一个具有handleEvent方法的对象。

其次,第三个参数除了布尔值useCapture,还可以是一个属性配置对象。该对象有以下属性。

  • capture:布尔值,表示该事件是否在捕获阶段触发监听函数。
  • once:布尔值,表示监听函数是否只触发一次,然后就自动移除。
  • passive:布尔值,表示监听函数不会调用事件的preventDefault方法。如果监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行警告。

如果希望事件监听函数只执行一次,可以打开属性配置对象的once属性。

element.addEventListener('click', function (event) {
  // 只执行一次的代码
}, {once: true});

addEventListener方法可以为针对当前对象的同一个事件,添加多个不同的监听函数。这些函数按照添加顺序触发,即先添加先触发。如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除(不必使用removeEventListener方法手动去除)。

function hello() {
  console.log('Hello world');
}

document.addEventListener('click', hello, false);
document.addEventListener('click', hello, false);

执行上面代码,点击文档只会输出一行Hello world

如果希望向监听函数传递参数,可以用匿名函数包装一下监听函数。

function print(x) {
  console.log(x);
}

var el = document.getElementById('div1');
el.addEventListener('click', function () { print('Hello'); }, false);

上面代码通过匿名函数,向监听函数print传递了一个参数。

监听函数内部的this,指向当前事件所在的那个对象。

// HTML 代码如下
// <p id="para">Hello</p>
var para = document.getElementById('para');
para.addEventListener('click', function (e) {
  console.log(this.nodeName); // "P"
}, false);

上面代码中,监听函数内部的this指向事件所在的对象para

EventTarget.removeEventListener()

EventTarget.removeEventListener方法用来移除addEventListener方法添加的事件监听函数。该方法没有返回值。

div.addEventListener('click', listener, false);
div.removeEventListener('click', listener, false);

removeEventListener方法的参数,与addEventListener方法完全一致。它的第一个参数“事件类型”,大小写敏感。

注意,removeEventListener方法移除的监听函数,必须是addEventListener方法添加的那个监听函数,而且必须在同一个元素节点,否则无效。

div.addEventListener('click', function (e) {}, false);
div.removeEventListener('click', function (e) {}, false);

上面代码中,removeEventListener方法无效,因为监听函数不是同一个匿名函数。

element.addEventListener('mousedown', handleMouseDown, true);
element.removeEventListener("mousedown", handleMouseDown, false);

上面代码中,removeEventListener方法也是无效的,因为第三个参数不一样。

EventTarget.dispatchEvent()

EventTarget.dispatchEvent方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true

target.dispatchEvent(event)

dispatchEvent方法的参数是一个Event对象的实例(详见《Event 对象》章节)。

para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);

上面代码在当前节点触发了click事件。

如果dispatchEvent方法的参数为空,或者不是一个有效的事件对象,将报错。

下面代码根据dispatchEvent方法的返回值,判断事件是否被取消了。

var canceled = !cb.dispatchEvent(event);
if (canceled) {
  console.log('事件取消');
} else {
  console.log('事件未取消');
}

W3C的JS事件解释:(用户html网页提出需求,js底层代码来满足响应)

1.HTML 事件概念?

HTML 事件是发生在 HTML 元素上的“事情”。
当在 HTML 页面中使用 JavaScript 时,JavaScript 能够“应对”这些事件。简而言之:HTML 事件是浏览器或用户做的某些事情。

2.HTML 事件

下面是 HTML 事件的一些例子:

  • HTML 网页可以完成加载
  • HTML 输入字段可以被修改
  • HTML 按钮可以被点击

通常,当事件发生时,表明用户希望做某件事。

JavaScript 允许您在事件被侦测到时执行代码。

通过 JavaScript 代码,HTML 允许您向 HTML 元素添加事件处理程序。

使用单引号:

<element event='一些 JavaScript'>

使用双引号:

<element event="一些 JavaScript">

DOM的海牙JS基础事件

一.事件概念:

1.事件是一个很笼统的概念:

’用户’ 与 ‘文档’ 交互基础事件:分为鼠标事件与键盘事件

2.事件从本质来说: 是程序各个组成部分之间的一种’交互通信’方式,也是异步编程的一种实现。DOM 支持大量的事件产生
3.事件严格从程序来说:事件是可以被 JavaScript 侦测到的行为

JavaScript 创建动态页面, 网页中的每个元素都可以产生某些可以触发 JavaScript 函数或程序的事件。

比如说,当用户单击按钮或者提交表单数据时,就发生一个鼠标单击(onclick)事件,需要浏览器做出处理,返回给用户一个结果。

4.总结: 触发事件 + 响应事件(调动函数)

一般情况下,dom事件与js函数方法是连贯使用的,比如登录按钮(button)触发了点击(click)事件,就会调用封装好的登录方法(function login(){}),最终完成操作。

二.触发事情的写法:

<!--
 * @Author: your name
 * @Date: 2021-03-02 15:26:15
 * @LastEditTime: 2021-04-16 01:54:26
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \视频d:\前端资料\js_20200713_224341\js第二十八天 碰撞监测和节流\案例\case00.html
-->
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    div {
      width: 110px;
      height: 100px;
      background-color: #368;
    }
  </style>

</head>

<body>
  <div onclick="tap()">111</div>
  <script>

    //第一种绑定事件写法: 在相应的html标签内 设置事件属性, 绑定函数写法. 
    //等于是把事件行为写到了标签内,没有实现标签和行为分离,类似行内写法没有分离标签和css样式,因此不推荐)
    function tap() {
      console.log(123)
    }
      
   
   //第二种绑定事件: 在js内单独寻找到对应的标签,然后再js内实现事情的绑定,实现了js和html标签分离,因此推荐
    // 节点元素对象.onclick属性  =  事件匿名函数function(event){}    实现事件绑定
    //事件的回调函数 用户触发了 click操作的时候 执行了这个函数   
     var oDiv = document.querySelector('div');
    
      oDiv.onclick = function (event) {
          console.log(event); //eventxx对象包含了当前这一次行为所有的事件信息
          //比如这里onclick属于鼠标事件,那么event就是鼠标mouseEvent事件对象集合,集合里面有各种鼠标信息
          console.log(event.target); //触发事件的目标 target 目标
          console.log(event.type); //事件类型
          console.log(event.target.innerText); //111
          console.log(this.innerText); //111
        
        }   

  </script>
</body>

</html>

三.触发产生事件的例子?

1.HTML DOM 允许 JavaScript 对 HTML 事件作出反应:
2.js中事件分为三大类:鼠标事件、键盘事件、其他html事件. (统称html事件)。
如:鼠标事件click,当元素容器被点击时,则JS函数响应 回去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2wmOWd3r-1620307183608)(C:\Users\tuyue\AppData\Local\Temp\1617210308907.png)]

4.JavaScript 能够在事件发生时执行,比如当用户点击某个 HTML 元素比如按钮时。为了在用户点击元素时执行代码,请向 HTML 事件属性添加 JavaScript 代码:触发事件主体.οnclick=JavaScript
HTML 事件的例子:

- 当用户点击鼠标时
- 当网页加载后
- 当图像加载后
- 当鼠标移至元素上时
- 当输入字段被改变时
- 当 HTML 表单被提交时
- 当用户敲击按键时

img

三.事件语法语句:(要记住,很重要)

js中事件分为三大类:mouseEvent鼠标事件、keyEvent键盘事件、其他html事件。
属性此事件发生在何时…
onabort图像的加载被中断。
onblur元素失去焦点。
onchange域的内容被改变。
onclick当用户鼠标点击某个对象时调用的事件句柄。
ondblclick当用户双击某个对象时调用的事件句柄。
onerror在加载文档或图像时发生错误。
onfocus元素获得焦点。
onkeydown某个键盘按键被按下。
onkeypress某个键盘按键被按下并松开。
onkeyup某个键盘按键被松开。
onload一张页面或一幅图像完成加载。
onmousedown鼠标按钮被按下。
onmousemove鼠标被移动。
onmouseout鼠标从某元素移开。
onmouseover鼠标移到某元素之上。
onmouseup鼠标按键被松开。
onreset重置按钮被点击。
onresize窗口或框架被重新调整大小。
onselect文本被选中。
onsubmit确认按钮被点击。
onunload用户退出页面。
var oBtn = document.querySelector('#btn');

oBtn.onclick = function(e){
    console.log(e)
   this.value = '不要点我'; 
}

//事件回调函数会回调形参 e Event事件对象形参,即oBtn.onclick这个onclick属性是一个事件对象来的.
//不要和oBtn事件源头对象弄混了. !== oBtn.onclick事件对象

举例:如下是在鼠标事件中,鼠标Event对象集合中的各种相对位置:

鼠标event对象给我们展示了 client offset page screen系列的X Y坐标 可以用于在不同需求下获取鼠标的相对位置

属性说明
clientX以浏览器左上顶角为原点,定位 x 轴坐标
clientY以浏览器左上顶角为原点,定位y轴坐标
offsetX以当前事件的目标对象左上角为原点,定位x轴坐标
offsetY以当前事件的目标对象左上角为原点,定位y轴坐标
pageX以Document 对象(即文本窗口)左上角为原点,定位x轴坐标
pageY以Document 对象(即文本窗口)左上角为原点,定位y轴坐标
screenX计算机屏幕左上角为原点,定位x轴坐标
screenY计算机屏幕左上角为原点,定位y轴坐标
layerX最近的绝对定位的父元素(如果没有,则为Document对象)左上角为原点,定位x轴坐标
layerY最近的绝对定位的父元素(如果没有,则为Document对象)左上角为原点,定位y轴坐标
图例

在这里插入图片描述

兼容

在这里插入图片描述

四.深入事件基础:触发 - 响应机制

Event接口表示在DOM中发生的任何事件,一些是用户生成的(例如鼠标或键盘事件),而其他由API生成。

1.事件三要素:

  • 事件源:触发(被)事件的元素 (如下的oDiv对象引用)
  • 事件类型:事件的触发方式(如下onclick鼠标点击 或 onkeydown键盘点击)
  • 事件处理程序:事件触发后要执行的function函数代码(如下的function函数形式)
  • (PS:事件回调函数中的this指向 触发事件的对象 this. => oDiv.)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efvIFPrp-1620307183618)(C:\Users\tuyue\AppData\Local\Temp\1617210308907.png)]

2.事件三阶段(深入了解):

事件有三个阶段: (PS:event.eventPhase属性可以查看事件触发时所处的阶段 )
第1阶段:在捕获阶段,返回1
第2阶段:在当前目标阶段,返回2 ,如果不出现冒泡穿透,就只到当前目标就会返回并且最终绑定事件了,不会到冒泡的.
第3阶段:在冒泡阶段,返回3,如果出现冒泡穿透,就会到这一阶段3.
1、事件捕获:(从最不精确到最精确事件对象,即捕获是从父到子这样按顺序一层一层捕获的)

捕获型事件(event capturing):
事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)

在这里插入图片描述
在这里插入图片描述

2、事件目标获取: 不发生冒泡,大部分事件都是到这一步就直接注册触发绑定事件了.
3、事件冒泡:
①专业描述:
事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
②通俗描述:
(前提:父和子都绑定同一事件.这玩意就是事件的一个层叠穿透, 从最精确到最不精确,即从子弹栈回溯到父,即点击一下父盒子嵌套的图片就都会同时触发同一事件即出现穿透冒泡, 会先子后父去绑定事件)
③代码案例:
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>捕获 冒泡 阻止冒泡</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    #box {
      display: flex;
      width: 200px;
      background-color: #222;
      transition: .5s;
      color: #fff;
    }

    #child {
      background-color: #999;
    }

    img {
      width: 50px;
      height: 50px;
    }
  </style>
</head>

<body>
  <div id="box">
    <div id="child">
      <img src="images/p1.jpg" alt="">
    </div>
    聊天信息内容
  </div>

  <script>

    var oBox = document.querySelector('#box');
    var oChild = document.querySelector('#child');

    oBox.onclick = function (e) {
      console.log('点击整体信息');
      console.log('我是父亲');
      console.log(event.eventPhase);
      
    }

    oChild.onclick = function (e) {
      // e.stopPropagation();//阻止冒泡
      console.log('点击头像');
      console.log("我是儿子");
      console.log(event.eventPhase); //查询事件处于什么阶段.
    }

  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Moj324qZ-1620307183623)(C:\Users\tuyue\AppData\Local\Temp\1617680457864.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BYm6CFJp-1620307183624)(C:\Users\tuyue\AppData\Local\Temp\1617686026835.png)]

3.如何阻止冒泡事件:

给最详细目标子对象写上e.stopPropagation();阻止冒泡穿透就可以防止向子以外的的父级外层穿透一起弹出结果.

 //第一种:
	oChild.onclick = function (e) {
      e.stopPropagation();//阻止冒泡行为
      console.log('点击头像');
      console.log("我是儿子");
      console.log(event.eventPhase);
    }
    
//第二种:事件最后 return false (黑科技)
    //但返回false这样即,阻止冒泡传递 同时阻止默认行为 ,会有副作用的

    //且新版本的chrome 
    return false //不再执行 stopPropagation()的 职能
4.总结: 捕获和冒泡,类似压栈和弹栈.遵守先进后出原则
  1. 事件会由'最外层''最内层'进行捕获传递 html>body>box>child ,类似压栈

  2. 事件传递到'最底层'之后 会进行回溯向'最外层'冒泡 child>box>body>html,类似弹栈

  3. 发生冒泡后,事件绑定(注册) 默认的事件回调函数执行最终是在冒泡阶段执行,

3.事件对象的回调函数形参function(event)即事件对象属性和方法

  • event.type 获取事件类型
  • clientX/clientY 所有浏览器都支持,窗口位置
  • pageX/pageY IE8以前不支持,页面位置
  • event.target || event.srcElement 用于获取触发事件的目标对象元素
  • event.preventDefault() 取消默认行为
    //如何绑定事件: 在js内单独寻找到对应的标签,然后再js内实现事情的绑定,实现了js和html标签分离,因此推荐
        // 节点元素对象.onclick属性  =  事件匿名函数function(event){}    实现事件绑定
        //事件的回调函数 用户触发了 click操作的时候 执行了这个函数   
         var oDiv = document.querySelector('div');
        
          oDiv.onclick = function (event) {
              console.log(event); //event对象包含了当前这一次行为所有的事件信息
              console.log(event.target); //触发事件的元素对象目标目标 target即var oDiv事件源头对象
              console.log(event.type); //事件类型
              console.log(event.pageX, event.pageY); //事件触发时 鼠标相对window的位置,即鼠标的绝对定位
              alert(this.innerText); 
              //弹出div文本内容的,事件回调函数中的this指向 触发事件的对象 this. => oDiv.
            }   
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZUBD79T-1620307183626)(C:\Users\tuyue\AppData\Local\Temp\1617691163402.png)]

PS: 回调函数function的事件对象形参(Event) !== 事件目标源头(oLink) 一个外部一个内部的不要弄混,但是也有相等时候.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rASK6fdp-1620307183628)(C:\Users\tuyue\AppData\Local\Temp\1617692508038.png)]

4.JS阻止默认事件对象Event行为:

很多标签拥有默认的事件行为 比如a标签 点击会执行跳转页面行为 , 我们可以通过代码阻止a标签默认跳转行为.
PS: 回调函数function的事件对象形参(Event) !== 事件目标源头(oLink)
var oLink = document.querySelector('a'); //

//第一种阻止方式:
oLink.onclick = function(e){ 
	e.preventDefault(); //取消事件目标a的默认跳转行为
    //preventDefault它是事件对象(Event)的一个方法,作用是取消一个目标元素a的默认行为
}

//第二种阻止方式:少用,黑科技写法,既阻止默认行为也阻止冒泡行为.一棍子打死
oLink.onclick = function(e){
	//代码
    return false; //回调函数最后返回false也可以阻止默认行为
}

//第三种方式:仅仅针对a标签使用,阻止a标签的默认跳转
<a href="javascript:;">聊天信息内容</a>
// 针对a标签href的值设置为javascript:;由js接管href行为
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>阻止默认行为</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    #box {
      display: flex;
      width: 200px;
      background-color: #222;
      transition: .5s;
      color: #fff;
    }

    #child {
      background-color: #999;
    }

    img {
      width: 50px;
      height: 50px;
    }
  </style>
</head>

<body>
  <div id="box">
    <div id="child">
      <img src="images/p1.jpg" alt="">
    </div>
    <a href="https://www.baidu.com/">聊天信息内容</a>
  </div>

  <script>

    /*
    很多标签拥有默认的事件行为 比如 a标签拥有href属性的时候 我们点击a标签会发生默认跳转行为


    第一种: e.preventDefault(); 阻止默认行为
    第二种:针对a标签href的值设置为javascript:;由js接管href行为
  	第三种:事件函数最后 我们可以return false 
    
    
    */

    var oBox = document.querySelector('#box');
    var oChild = document.querySelector('#child');
    var oLink = document.querySelector('a');

    oBox.onclick = function () {
      console.log(this);
      // return false;
    }
    oChild.onclick = function (e) {
      e.stopPropagation();
    }
    oLink.onclick = function (e) {
      // e.preventDefault();
      console.log(e.target);
      return false;
    }

  </script>
</body>

</html>

5.复习阻止事件传递(即阻止冒泡):

所有的事件类型都会经历事件捕获,但是只有部分事件会经历事件冒泡阶段,例如submit事件就不会被冒泡。
/*事件的传播是可以阻止的:
w3c规范下,使用stopPropagation()方法
在IE版本下设置eve.cancelBubble = true; 废弃
在捕获的过程中stopPropagation();后,后面的冒泡过程就不会发生了。
*/

var oLink = document.querySelector('a');

oLink.onclick = function(e){
	e.stopPropagation(); 
   
}

6.如何事件解绑: oBtn.onclick = null 即可

事件绑定之后 如果需要解绑 可以销毁

var oBtn = document.querySelector('#btn');
var oClean = document.querySelector('#clean');

oBtn.onclick = function(){
    console.log('btn成功绑定点击事件');
}
oClean.onclick = function(){
    oBtn.onclick = null;
    console.log('btn已解绑点击事件');
}

7.如何事件委托:即在执行函数内部写if条件语句就是事件提前委托,在还未创建出来的节点的时候就预判写好它的行为,即就是提前写好if语句就可以了

当需要对多个子元素进行循环事件绑定的时候,可以将事件委托与他们的共同父级,通过event对象属性来进行筛选和操作,节省开销。

var oUl = document.querySelector('list');

//监听在oUl上发生的点击事件 利用事件的传递性 获取e.target判断触发事件的实际DOM是否为li 
oUl.onclick = function(e){
    if(e.target.toLowerCase() === 'li'){
    	e.target.style.backgroundColor = '#368';
    }
}

8.事件分派:

当一个容器有多个元素需要绑定同一个事件, 而点击不同元素所需要执行的操作不同时可以进行分派映射

 var oBox = document.querySelector('#box');

var eventMap = {
    'stretch': function (ele) {
        ele.style.width = '400px';
        ele.style.height = '400px';
    },
    'discolor': function (ele) {
        ele.style.backgroundColor = '#368';
    },
    'rotate': function (ele) {
        ele.style.transform = 'rotate(10deg)';
    }
}

document.onclick = function (e) {
    if (eventMap[e.target.id.toLowerCase()]) {
        eventMap[e.target.id.toLowerCase()](oBox);
    }
}

五:汇总事件的小练习:一定要自己多去模仿和积累

1.鼠标事件、键盘事件案例:

    <!DOCTYPE html>
    <html lang="zh-cn">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>事件</title>
      <style>
        * {
          margin: 0;
          padding: 0;
        }
    
        div {
          float: left;
          width: 200px;
          height: 200px;
          margin: 10px;
          border: 2px solid red;
          background-color: #368;
          /*隐士切换span的display展示模式为block*/
        }
    
        input {
          width: 500px;
          height: 90px;
          font-size: 30px;
          padding: 10px;
        }
      </style>
    </head>
    
    <body>
      <div>点我 我就告诉你</div>
      <input type="text" id="input" value=''>
      <script>
        /*
          什么是事件
    
        - 当用户点击鼠标时
        - 当网页加载后
        - 当图像加载后
        - 当鼠标移至元素上时
        - 当输入字段被改变时
        - 当 HTML 表单被提交时
        - 当用户敲击按键时
    
    
        点击div标签 弹出div的内容
        */
    
        var oDiv = document.querySelector('div');
    
        //将事件匿名函数 赋值给 元素对象的 onclick属性 事件绑定
        //事件的回调函数 用户触发了 click操作的时候 执行了这个函数
        oDiv.onclick = function (event) {
          console.log(event); //event对象包含了当前这一次行为所有的事件信息
          console.log(event.target); //触发事件的目标 target 目标
          console.log(event.type); //事件类型
          console.log(event.pageX, event.pageY); //事件触发时 鼠标相对window的位置
          alert(this.innerText); //弹出div文本内容的,事件回调函数中的this指向 触发事件的对象 this. => oDiv.
        }
    
        var oInput = document.querySelector('#input');
        oInput.onkeydown = function () {//在input上写键盘按键的时候触发,即你打字会在控制台也显示所打的字
          console.log(this.value);
        }
    
        oInput.onfocus = function () {//在input上敲下键盘按键的时候触发
          console.log('你聚焦在了input上');
        }
    
        oInput.onblur = function () {//在input上敲下键盘按键的时候触发
          console.log('input失去了焦点');
        }
    
      </script>
    </body>
    
    </html>



[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VoSu92xK-1620307183630)(C:\Users\tuyue\AppData\Local\Temp\1617212124286.png)]

2.其他html事件: img图像加载完成 和 加载中断 和 加载报错事件.

扩展细节事件: window.onload = function () {} (事件:网页加载完成即网页加载完才去加载这段代码片段)
否则如下的代码是会报错的,因为你的其中一段script写在head上,但是主体input对象却写在body内,js是从上到下执行的,因此会报错,但是用了window.onload = function () {}包裹着head的script则不会报错,因为等其他都加载完他才加载的.
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>onload事件</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    div {
      float: left;
      width: 200px;
      height: 200px;
      margin: 10px;
      border: 2px solid red;
      background-color: #368;
      /*隐士切换span的display展示模式为block*/
    }

    input {
      width: 500px;
      height: 90px;
      font-size: 30px;
      padding: 10px;
    }
  </style>
  <script>
    window.onload = function () { //网页加载完成
      var oInput = document.querySelector('#input');
      console.log(oInput); //执行选择器获取的时候 浏览器还没有读到 body标签没有渲染input标签呢
        
      oInput.onkeydown = function () {//在input上敲下键盘按键的时候触发
        console.log(this.value);
      }

      oInput.onfocus = function () {//在input上敲下键盘按键的时候触发
        console.log('你聚焦在了input上');
      }

      oInput.onblur = function () {//在input上敲下键盘按键的时候触发
        console.log('input失去了焦点');
      }
    }

  </script>
</head>

<body>
  <div>点我 我就告诉你</div>
  <input type="text" id="input" value=''>
  <img src="images/bird.png" alt="">

  <script>
      //图片加载事件.
    var oImg = document.querySelector('img');
    oImg.onload = function (e) { //加载完成
      console.log(this.src, e.type);
    }
    oImg.onabort = function (e) {//加载中断
      console.log(this.src, e.type);
    }
    oImg.onerror = function (e) {//加载报错
      console.log(this.src, e.type);
    }
  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gN1QuAzQ-1620307183633)(C:\Users\tuyue\AppData\Local\Temp\1617212171220.png)]

3.通过鼠标点击图片事件 来切换img图片案例:

要求:点击img切换图片 随机换 p1 - p4

<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    img {
      width: 400px;
      height: auto;
    }
  </style>

</head>

<body>
  <!-- 点击img切换图片 随机换 p1 - p4 -->

  <img id='pic' src="images/p1.jpg" alt="">

  <script>

    /*
      es6字符串拼接模板新写法,  ` `反引号  +  ${变量}
    
    */
    var oPic = document.querySelector('#pic');

    oPic.onclick = function () {
      //随机 1 2 3 4 Math.random()
      var randomIdx = ~~(Math.random() * 4) + 1; //这里是让随机数能为1-4之间. PS:取反
      console.log(randomIdx);
      this.src = 'images/p'+ randomIdx +'.jpg' //this指向的是,当前的img节点对象,让img的src随机变化.
      //this.src = `images/p${randomIdx}.jpg`;
    
    }

  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SU7bs4PI-1620307183635)(C:\Users\tuyue\AppData\Local\Temp\124.gif)]

4.通过鼠标点击按钮控件事件 来让div盒子隐藏或者显示案例:

<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    div {
      width: 200px;
      height: 200px;
      background-color: #368;
    }

    input {
      position: absolute;
      top: 200px;
      left: 200px;
      width: 180px;
      height: 90px;
      border: 0;
      background-color: #222;
      color: #fff;
      font-size: 20px;
    }
  </style>

</head>

<body>
 

  <div id="box">我出来了</div>
  <input id="btn" type="button" value="隐藏">
  <script>
    /* 
    //要求:
      点击input控件时 切换div的box的显示状态  点一下控件显示/点一下控件隐藏
      开关 => boolean => true false
    
     */
    var oDiv = document.querySelector('#box');
    var oBtn = document.querySelector('#btn');
    var toggle = true; //开关 默认为true 显示

   
    //初步代码,简单理解,但是冗余
    oBtn.onclick = function () {
      if (toggle === true) { //点击btn的时候判断开关是 true的时候 
        oDiv.style.display = 'none'; //把div隐藏
        toggle = false; //把开关改为false 为下一次点击做好准备
        this.value = '显示'; //开关的显示状态 提示语也要变化 再点就是要显示
      } else {
        oDiv.style.display = 'block'; //把div显示
        toggle = true;//把开关置为 true
        this.value = '隐藏';
      }
      console.log(toggle)
    }



    /* 
    //如何优化一段代码????
      1. 提取不变的行为 属性赋值操作 DOM api操作
      2. 辨别真正需要改变的是 值 还是 操作 本身\
      3. 思考如何将具体值剥离 => 变量
      4. 值是否可以进行预先预设结果 ,  尤其是两个值切换的这种情况下 
    
    
     */


    
    //进阶进化版:
    var oDiv = document.querySelector('#box');
    var oBtn = document.querySelector('#btn');
    var toggle = true; //开关 默认为true 显示 
    oBtn.onclick =  function () {
      var val = '隐藏', dis = 'block';  //预先预制结果

      if (toggle) {
        val = '显示';
        dis = 'none';
      }

      toggle = !toggle; //这里不能写具体的true/false,会写死了. 这样变量写就可以每次都能自己取反转结果
      oDiv.style.display = dis; //开关取反后,要把display也改回去,即再变化block即可
      this.value = val; //隐藏/显示值也要变回去.
    }




    //最终精华升级版:  三目究极起飞写法.
    var oDiv = document.querySelector('#box');
    var oBtn = document.querySelector('#btn');
    var toggle = true; //开关 默认为true 显示
    oBtn.onclick = function () {

      oDiv.style.display = toggle ? 'none' : 'block'; //三目写法,根据toggle决定开还是关
      this.value = toggle ? '显示' : '隐藏'; //也是三目写法,根据toggle决定显示还是隐藏
      toggle = !toggle; //最后取反true/false即可
    }

  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhHmhEZC-1620307183637)(C:\Users\tuyue\AppData\Local\Temp\81340e5c-e77e-4288-89c6-32f8d53f4009.gif)]

5.渲染动态ul>li标签案例:

①把ul内的四个li全部通过js来动态渲染出来,不要在html的body内静态写死出来.
②如何将数据 动态 渲染成标签:不用写html直接在js虚拟写 (不过实际开发不会用虚拟dom来渲染标签的),

数据源 + 模板(静态死的html和css样式) + JS渲染行为 = JS动态渲染内容

<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>事件和渲染 模板</title>
  <style>
    body {
      background-color: #f5f5f5;
      user-select: none;
    }

    ul {
      display: flex;
      justify-content: space-around;
      align-items: center;
      list-style: none;
      width: 960px;
    }

    li {
      width: 234px;
      height: 300px;
      margin-left: 20px;
      padding: 10px;
      background-color: #fff;
      text-align: center;
    }

    .red {
      color: #ff0084;
    }

    .pic {
      width: 160px;
      height: 160px;
    }

    .title {
      font-size: 14px;
      font-weight: 400;
      line-height: 42px;
    }

    .desc {
      width: 180px;
      height: 18px;
      font-size: 12px;
      color: #b0b0b0;
      text-align: center;
      text-overflow: ellipsis;
      white-space: nowrap;
      overflow: hidden;

    }

    .price {
      font-size: 12px;
      color: #444;
      line-height: 28px;
    }
  </style>
</head>

<body>

  <ul id="list">

  </ul>

  <script>
  

    var responseData = [
      {
        title: '腾讯黑鲨3S',
        des: '骁龙865处理器,120Hz刷新率',
        price: '3999',
        picSrc: '//cdn.cnbj1.fds.api.mi-img.com/mi-mall/237942bfcaf2bbe82fbe966c2f584d69.jpg?thumb=1&w=200&h=200&f=webp&q=90'
      },
      {
        title: '小米10 青春版 5G',
        des: '50倍潜望式变焦 / 轻薄5G手机',
        price: '1899',
        picSrc: '//cdn.cnbj1.fds.api.mi-img.com/mi-mall/8729282b199b3ec51e31c1b6b15f3f93.jpg?thumb=1&w=200&h=200&f=webp&q=90'
      },
      {
        title: '小米10',
        des: '骁龙865/1亿像素相机',
        price: '3699',
        picSrc: '//cdn.cnbj1.fds.api.mi-img.com/mi-mall/0099822e42b4428cb25c4cdebc6ca53d.jpg?thumb=1&w=200&h=200&f=webp&q=90'
      },
      {
        title: 'Redmi 9A',
        des: '5000mAh长循环大电量,6.53"超大护眼屏幕',
        price: '499',
        picSrc: '//cdn.cnbj1.fds.api.mi-img.com/mi-mall/c892a7640f58032489cbff8a948b50f9.jpg?thumb=1&w=200&h=200&f=webp&q=90'
      }
    ];

    var oUl = document.querySelector('#list');
    var aLi = oUl.querySelectorAll('li'); //还没有渲染到页面的标签无法获取li
    console.log(aLi); //因此获取的是空集合 NodeList(0)
    console.log(oUl); // 获取的是整个ul,包含内部的全部子元素
    
    drawHtml(oUl, formattingData(responseData)); //渲染li到ul内,此时才获取到ali

    aLi = oUl.querySelectorAll('li');//在渲染之后获取li
    console.log(aLi); //NodeList(4) [li, li, li, li]


    /* 
        点击li打印li里数据商品的标题 并且打印 对应li的下标

        把变量变成具体的值 传参可以让变量实参直接在函数内以形参的形式变成值
     */

    //另一个要求:循环给aLi集合内的每一个li元素对象绑定onclick事件函数
    //隐式:var i;
    for (var i = 0, len = aLi.length; i < len; i++) { //遍历四个li
      (function (idx) { //IFFE,自调用函数.
        aLi[idx].onclick = function () { 
          console.log(idx);//每个li盒子点一下,显示每个li的下标出来
          console.log(this); //this指向的是当前绑定点击事件的对象,即每个遍历的li =>aLi[idx]
          console.log(this.querySelector('.title').innerText);
         //每个li盒子点一下,显示每个li盒子下的h3标签的文本内容

        }
      })(i);  //IIFE (function(形参){})(实参).  i其实就是index下标
    }

   


      

    //将数据生成HTML模板字符串
    function formattingData(data) {
      return data.reduce(function (acc, curr, idx, arr) { 
    //遍历四个list对象节点出来,同时让四个list累加成为整个ul
    //然后再用`${}` 字符串拼接变量把每次curr即每次遍历的list设置为自己特有的属性.
        acc += `<li> 
                <img class="pic"
                  src="${curr['picSrc']}"
                  alt="${curr['title']}" width="200" height="200">
                <h3 class="title">${curr['title']}</h3>
                <p class="desc">${curr['des']}</p>
                <p class="price"><span class="red">${curr['price']}</span>元起</p>
              </li>`;
        return acc; 
       //原来这里是要写acc+curr的,但其实是一样的.上面acc += xx ,然后return acc
       //其实不也就等于return acc+curr ,只是这里把它acc = acc+xx 这样合并了
      }, '');
    }

    /* 
    这和下面原来的写法是 return acc+curr ,是一样的效果,看你怎么理解
        return acc+ `<li> 
                <img class="pic"
                  src="${curr['picSrc']}"
                  alt="${curr['title']}" width="200" height="200">
                <h3 class="title">${curr['title']}</h3>
                <p class="desc">${curr['des']}</p>
                <p class="price"><span class="red">${curr['price']}</span>元起</p>
              </li>`; 
    */


    function drawHtml(parent, htmlStr) {
      parent.innerHTML = htmlStr;
    }




  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zp6GMmg6-1620307183639)(C:\Users\tuyue\AppData\Local\Temp\1617272737007.png)]

ps扩展: 直接写下标和使用IIFE的区别???

为什么上面要使用IIFE自调用函数: 其实是如下代码的升级版但是这个是for和function函数分离: 目的是为了拿到每次的下标,通过单独另外一个封装函数来拿到下标,使下标i进入封装函数变为局部变量.即可让事件函数能够执行输出idx.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vBWOGkiG-1620307183640)(C:\Users\tuyue\AppData\Local\Temp\1617766613648.png)]

终极升华版使用IIFE自调用函数:
 /* 
        点击li打印li里数据商品的标题 并且打印 对应li的下标
        把变量变成具体的值 传参可以让变量实参直接在函数内以形参的形式变成值
        
        
       这里的自调用函数,其实就和上面的目的是一样的,就是为了让事件函数function的i下标变量变为局部变量,而不是全局变量,自己细品下面两个function形成一个作用域链,事件函数上面是一个自调用函数,onclick事件函数的idx下标变量提升上去就是自调用函数的作用域内的局部变量,就不会提升到全局变量去了.
     */


    //另一个要求:循环给aLi集合内的每一个li元素对象绑定onclick事件函数
    for (var i = 0, len = aLi.length; i < len; i++) { //遍历四个li
      (function (idx) { //IFFE,五启用自调用函数,让for中的i变量下标从全局变量i变为局部变量参数idx,能进去匿名事件函数内部去输出下标,自己细品
        aLi[idx].onclick = function () { 
          console.log(idx);//每个li盒子点一下,显示每个li的下标出来
          console.log(this); //this指向的是当前绑定点击事件的对象,即每个遍历的li =>aLi[idx]
          console.log(this.querySelector('.title').innerText);
         //每个li盒子点一下,显示每个li盒子下的h3标签的文本内容

        }
      })(i);  //IIFE (function(形参){})(实参).  i其实就是index下标
    }

如下是反例案例代码:为什么不能这么写呢 ? 直接打印下标i不就行了??? ,但是如下结果只能全部为4.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMikCXKt-1620307183641)(C:\Users\tuyue\AppData\Local\Temp\1617277817487.png)]


          
//因为for内的i其实是全局变量来的,因此for在外部隐式声明var i;之后才去for内部暂时形成一个封闭空间自己玩自己的让i随便去变化,但是一旦循环出来,还是得老老实实最终结果变回全局变量,即循环完的最终结果,这就为什么最终结果如下都是4就是这个原因,因为是i是全局,只有for循环遍历完了,i全局就是4.内部的i是暂时的局部因此管不着外面的全局i.
          

   

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-inaJLkEo-1620307183644)(C:\Users\tuyue\AppData\Local\Temp\1617296480693.png)]

分析for这个控制循环语句很特殊:内部的i在没有能结束for循环条件的时候是局部变量来的,但是能够结束for循环条件的最终那个i变量值是全局变量.很特别(在js引擎预解析有一个隐式的全局var i )
//我们先来分析一个for循环的进进出出的解析,一个函数 才是一个作用域 if() for() 这些控制流程语句 不构成作用域
<script>
       var aLi =[1,10,2,34]
      //隐式:var i;  因为for其实不是作用域是一个全局的执行语句而已, 否则为什么出了for上下否则输出i呢?
	  //说明for是外部隐式提升一个全局i,内部在自己for循环一个局部i,最终让i循环执行=4就结束了该执行语句.
      console.log(i);//undefined,js可以先斩后奏.
      for (var i = 0, len = aLi.length; i < len; i++) { 
   
           
          /*
          //声明
          var i;
          //执行
          i=0
          0<4?
          console(aLi[0]);
          0++
          
          i=1
          1<4?
          console(aLi[1]);
          1++
          
          i=2
          2<4?
          console(aLi[2]);
          2++
          
          ...
          
          */
          
        console.log(aLi[i]); 
          //正常的i,作用域还是在全局内的,for不算作用域
          //但是绑定事件的回调函数function,就是另外一个单独的作用域,因此在内部直接写i是找不到局部变量i
          //只能去上一级的全局for内去寻找变量i,但此时for还没循环完不知道最后的全局i是多少,因此for循环完后
          //才知道最终的全局i是多少,才能进去事件函数function

      }
      //此时结束for循环此处有 i = 4的全局赋值的.
      console.log(i);//4,不要以为是3,因为最终到全局var i=4才会发现 i< len是不成立的,才结束循环
      console.log(aLi[i]);//undefined,此时aLi[4]不存在啊,返回undefined
  </script>

6.选项卡切换事件案例:(选项卡切换思想很重要)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6E8Ecw0o-1620307183646)(C:\Users\tuyue\AppData\Local\Temp\127.gif)]

<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>选项卡切换</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      list-style-type: none;
    }

    html,
    body {
      height: 100%;
    }

    body {
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .wrap {
      display: flex;
      flex-direction: column;
      width: 600px;
      height: 320px;
      box-shadow: 0 0 4px #333;

    }

    .tab {
      display: flex;
      background-color: #666;
    }

    .tab li {
      width: 80px;
      height: 45px;
      line-height: 45px;
      font-size: 20px;
      text-align: center;
      color: #fff;
      background-color: #666;
      border-right: 2px solid orange;
      cursor: pointer;
    }

    .tab li:hover {
      opacity: .8;
    }

    .content {
      position: relative;
    }

    .content li {
      display: none;
      position: absolute;
      width: 100%;
      height: 220px;
      background-color: #368;
      color: #fff;
      font-size: 30px;
    }

    .tab li.on {
      background-color: #fff;
      color: orange;
      font-weight: 700;
    }

    .content li.active {
      display: block;
    }
  </style>
</head>

<body>
  <div class="wrap">
    <ul class="tab"><!-- 切换卡 -->
      <li class="on">图片</li><!-- 一开始默认激活的切换卡li -->
      <li>专栏</li>
      <li>热点</li>
    </ul>
    <ul class="content">
      <li class="active">我是图片的内容</li><!-- 一开始默认激活的切换卡对应图片内容 -->
      <li>我是专栏的内容</li>
      <li>我是热点的内容</li>
    </ul>
  </div>
  <script>
    /*
      选项卡切换原理分析:

      tabbar  content 两部分的内容一一对应
      我们点击某一个tab的时候
       该tab的类名设置为on 其他的tab要清除on类名
       对应的content的类名要设置为 active 其他的content清除active类名

      1. 素材获取  tab>li      content>li

      2. 点击 (onclick)tab>li 设置类名 on 清除其他tab>li的类名 on

         ①获取点击的 tab>li的下标,(即获取的tab下li标签对象是一个节点集合)
         ②根据下标再去设置 content>li[idx] 的 类名为 active 其他的 删除类名active
         ③总结:根据用户的点击/xx行为,先来切换index,再根据index切换其他效果:选项卡/内容
    */

    var aTab = document.querySelectorAll('.tab li');
    var aCon = document.querySelectorAll('.content li');

    function switchTab() {//封装为一个方法.
        var index = 0;//公共下标
        for (var i = 0, len = aTab.length; i < len; i++) { //遍历三个li,长度为3
        (function (i) {
          aTab[i].onclick = function () { //传入i=0是默认激活状态,给第一个去调类名,此时index再等于0也是给第一个切换卡又重新给类名即点击第一个切换卡所有东西是不变的.
            //因此我们只去考虑当点击i=1时即点击第2个Tab切换键时会发生什么
            aTab[index].className = '';//首先index还是=0 ,即aTab[0].className = ''; 即第一个li默认值的on样式状态消失了
            aCon[index].className = '';//同时让第一个tab键的第一个li的active内容消失了变为默认none.
             
            //这里开始改写命运 
            index = i;  // index = 1; 因为此时i循环为1了,让index变为1了即去到第二个给第二个修改效果了
            aTab[index].className = 'on';//然后再让第二个Tab切换键 即aTab[1].className = 'on' ;即轮到第二个li变为激活状态了,让其on样式生效,即等于Tab切换键切换过来了
            aCon[index].className = 'active';//同理第二个Tab切换键下的第二个li内容变为active,即变为block展现出来,即也内容等于切换过来了
          
          }
        })(i); 
      }
    }

    switchTab();


    //第一种写法:
    // function switchTab() {
    //   var index = 0;//公共下标
    //   for (var i = 0, len = aTab.length; i < len; i++) {
    //     (function (i) {
    //       aTab[i].onclick = function () {
    //         aTab[index].className = '';
    //         aCon[index].className = '';
    //         index = i;
    //         aTab[index].className = 'on';
    //         aCon[index].className = 'active';
    //       }
    //     })(i);
    //   }
    // }



    


    //第二种写法:

    //    //排他法 先把所有的都重置 然后单独设置某一个
    //       for (var j = 0; j < len; j++) {
    //         aTab[j].className = '';
    //       }

    //第三种写法:
    //   //轮转法
    //       aTab[index].className = ''; //aTab[1].className = '';
    //       index = i; //index => 2
    //       aTab[index].className = 'on';//aTab[2].className = '';


    //  */

  </script>
</body>

</html>
升级版:利用事件委托:
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>选项卡切换 事件委托</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      list-style-type: none;
    }

    html,
    body {
      height: 100%;
    }

    body {
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .wrap {
      display: flex;
      flex-direction: column;
      width: 600px;
      height: 320px;
      box-shadow: 0 0 4px #333;

    }

    .tab {
      display: flex;
      background-color: #666;
    }

    .tab li {
      width: 80px;
      height: 45px;
      line-height: 45px;
      font-size: 20px;
      text-align: center;
      color: #fff;
      background-color: #666;
      border-right: 2px solid orange;
      cursor: pointer;
    }

    .tab li:hover {
      opacity: .8;
    }

    .content {
      position: relative;
    }

    .content li {
      display: none;
      position: absolute;
      width: 100%;
      height: 220px;
      background-color: #368;
      color: #fff;
      font-size: 30px;
    }

    .tab li.on {
      background-color: #fff;
      color: orange;
      font-weight: 700;
    }

    .content li.active {
      display: block;
    }
  </style>
</head>

<body>
  <div class="wrap">
    <ul class="tab">
      <li class="on">图片</li>
      <li>专栏</li>
      <li>热点</li>
    </ul>
    <ul class="content">
      <li class="active">我是图片的内容</li>
      <li>我是专栏的内容</li>
      <li>我是热点的内容</li>
    </ul>
  </div>
  <script src="js/common.js"></script> <!-- 单独开一个script标签引入 -->
  <script>


    var oTab = document.querySelector('.tab');
    var aCon = document.querySelectorAll('.content li');



    var index = 0;


    //事件委托
    oTab.onclick = function (e) {
      // console.log(e.target); //触发事件的DOM目标
      if (e.target.tagName.toLowerCase() === 'li') { //如果触发事件的目标是的标签名称是li的话
        oTab.children[index].className = '';
        aCon[index].className = '';
        index = getElementIdx(e.target);
        oTab.children[index].className = 'on';
        aCon[index].className = 'active';
      }
    }






  </script>
</body>

</html>
common.js:
//获取元素对象下标
function getElementIdx (item) {
  var elements = item.parentNode.children;
  for (var i = 0, len = elements.length; i < len; i++) {
    if (item === elements[i]) {
      return i;
    }
  }
}

//设置任意的标签中间的任意文本内容
function setInnerText (element, text) {
  var key = element.textContent == "undefined" ? 'innerText' : 'textContent';
  element[key] = text;
  // //判断浏览器是否支持这个属性
  // if (typeof element.textContent == "undefined") {//不支持
  //   element.innerText = text;
  // } else {//支持这个属性
  //   element.textContent = text;
  // }
}

//获取元素实际样式
function getStyle (obj, attr) {
  return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, false)[attr];
}



function $ (ele) {
  return document.querySelector(ele);
}

function $$ (ele) {
  return document.querySelectorAll(ele);
}

7.轮播图事件案例:(很重要)

①最基础版本:onclick点击span圆图标即可切换图片.
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 基础轮播图 banner</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      display: flex;
      justify-content: center;
    }

    .banner {
      width: 500px;
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      box-shadow: 0 0 8px #333;

    }

    .slider {
      display: flex;
      justify-content: space-around;
      align-items: center;
      position: absolute;
      bottom: 10px;
      width: 380px;
    }

    .slider span {
      width: 45px;
      height: 45px;
      line-height: 45px;
      background-color: orange;
      text-align: center;
      font-size: 20px;
      color: #fff;
      border-radius: 50%;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="banner">
    <img id="pic" src="images/p1.jpg" width="500" height="375" alt="pkq">
    <div class="slider">
      <span>1</span>
      <span>2</span>
      <span>3</span>
      <span>4</span>
    </div>
  </div>
  <script>
    /*
      丐中丐版轮播图
      点击对应的slider 根据slider的值替换 图片的src
    */

    var oPic = document.querySelector('#pic');
    var oSlider = document.querySelector('.slider');

    oSlider.onclick = function (e) { //鼠标在div点击的时候
      if (e.target.tagName.toLowerCase() === 'span') {  //如果点击的是div下的span标签则让文本内容
        oPic.src = `images/p${e.target.innerText}.jpg`; //这里的巧妙之处就是文本内容时1 2 3,正好对应图片名称也是1 2 3.
      }
    }

  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjGHDMa5-1620307183648)(C:\Users\tuyue\AppData\Local\Temp\123.gif)]

②轮播升级版: 不用点击,用onmouseover鼠标滑过来切span圆图标,并且改变图标颜色为粉红色

<!--
 * @Author: your name
 * @Date: 2021-03-02 15:26:38
 * @LastEditTime: 2021-04-06 17:54:57
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \第十九天 页面练习d:\前端资料\js_20200713_224341\js第二十四天 event 属性与方法\案例\case07.html
-->
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 基础轮播图 banner 移入移出</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      display: flex;
      justify-content: center;
    }

    .banner {
      width: 500px;
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      box-shadow: 0 0 8px #333;

    }

    .slider {
      display: flex;
      justify-content: space-around;
      align-items: center;
      position: absolute;
      bottom: 10px;
      width: 380px;
    }

    .slider span {
      width: 45px;
      height: 45px;
      line-height: 45px;
      background-color: orange;
      text-align: center;
      font-size: 20px;
      color: #fff;
      border-radius: 50%;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="banner">
    <img id="pic" src="images/p1.jpg" width="500" height="375" alt="pkq">
    <div class="slider">
      <span>1</span>
      <span>2</span>
      <span>3</span>
      <span>4</span>
    </div>
  </div>
  <script>
    /*
      丐中丐版轮播图 顺滑版
      点击对应的slider 根据slider的值替换 图片的src
    */

    var oPic = document.querySelector('#pic');
    var oSlider = document.querySelector('.slider');
      
      
	//onmouseover  和  onmouseout 移入和移走都要写
    oSlider.onmouseover = function (e) { //用js充当hover的效果,鼠标移入的时候
      if (e.target.tagName.toLowerCase() === 'span') {	//鼠标移入div时,if如果移入的div下的span标签时
        oPic.src = `images/p${e.target.innerText}.jpg`; //会根据文本内容1234切换图片对应的路径也是1 2 3 4一一对应的,不用循环因为这是原点图标不是轮播,轮播会一直点下去,就要循环
        e.target.style.backgroundColor = 'pink';//鼠标移入图片改变同时颜色也变为粉色
      }
    }

   //用js充当hover的效果,鼠标移走的时候,span圆图标的粉红颜色变回去橙色
    //而轮播那里没用这个,因为是进去changeSlider封装函数改变回为橙色
    oSlider.onmouseout = function (e) { 
      if (e.target.tagName.toLowerCase() === 'span') {
        e.target.style.backgroundColor = 'orange';  
      }
    }
    
    /*
    颜色这块其实也可以直接用css解决背景颜色的问题,更简便
     .slider span:hover {
      background-color: green;
    }
    */

  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1PWIGsKu-1620307183650)(C:\Users\tuyue\AppData\Local\Temp\122.gif)]

③进阶升级版:使用左右箭头的轮播来切换图片
<!--
 * @Author: your name
 * @Date: 2020-08-10 20:31:13
 * @LastEditTime: 2021-04-08 16:00:41
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \案例\case00.html
-->
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 轮播图 进阶丐版 slideShow + 按钮</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      display: flex;
      justify-content: center;
    }

    .banner {

      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      position: relative;
      width: 500px;
      box-shadow: 0 0 8px #333;

    }

    .slider {
      display: flex;
      justify-content: space-around;
      align-items: center;
      position: absolute;
      bottom: 10px;
      width: 380px;
    }

    .slider span {
      width: 45px;
      height: 45px;
      line-height: 45px;
      background-color: orange;
      text-align: center;
      font-size: 20px;
      color: #fff;
      border-radius: 50%;
      cursor: pointer;
    }

    .btn-wrap span {
      user-select: none;
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto;
      width: 40px;
      height: 85px;
      line-height: 85px;
      font-size: 32px;
      color: #fff;
      text-align: center;
      background-color: rgba(0, 0, 0, .4);
      cursor: pointer;
    }

    .btn-wrap span:hover {
      background-color: rgba(0, 0, 0, .8);
    }

    .prev {
      left: 0;
    }

    .next {
      right: 0;
    }
  </style>
</head>

<body>
  <div class="banner">
    <img id="pic" src="images/p1.jpg" width="500" height="375" alt="pkq">
    
    <div class="btn-wrap">
      <span class="prev">&lt;</span>
      <span class="next">&gt;</span>
    </div>
  </div>
  <script>
    /*

      点击对应的slider 根据slider的值替换 图片的src

      1-4 点击 next的时候 下标++ 点击 prev的时候 下标--

      图片进行循环 0 1 2 3 0 1 2 3 0 1 2 3


      代码的优化合并 

        1. 梳理 哪些操作(行为)是重复的 

          1.  oPic.src = `images/p${index + 1}.jpg`;
          2.  oSlider.children[index].style.backgroundColor = 'pink';
          3.  oSlider.children[index].style.backgroundColor = 'orange';

        2. 分类 行为进行分类

          1. 点击 prev next 或 移入 slider的span => 修改了 index下标
          2. 根据 index 下标 切换展示的图片 index + 1
          3. 根据 index 下标 切换展示状态的 slider>span


        3. 事件对应行为分类

          1. 点击左右按钮
            1. 点击左按钮
              index-- /
              index = (count + index) % count;/
              图片根据index切换 
              小圆点根据index切换
            2. 点击右按钮
              index++/
              index %= count; /
              图片根据index切换 
              小圆点根据index切换
          2. 移入小圆点 轮转or排他(选项卡切换)
              index = e.target.innerText - 1;/
              图片根据index切换 
              小圆点根据index切换

              
        4. 封装
              图片根据index切换 
              小圆点根据index切换
        

        事件的回调函数内 负责index下标的改变

        封装函数内 只负责 图片和小圆点 根据下标来切换

    */

    var oPic = document.querySelector('#pic');

    var btnPrev = document.querySelector('.prev');
    var btnNext = document.querySelector('.next');
    var index = 0; //下标从0开始 图片对应需要是 p(index+1) 0 - 3  p1 - p4
    var count = 4;


    //点击右按钮会发生什么???  p1-p2 - p3- p4 - p1... 
    btnNext.onclick = function () { //点击右轮播的时候
        index++; 
        //因为图片默认是从p1开始的,因此右点击的目的就是为了让图片跳到p1-p2 - p3- p4 - p1... 
        //其实index初始值赋值为1是最好的,直接循环改变即可,不用++了,但是我们js规则就是index最好为0
        //然后index=0进来会变为1了


        //思路一:菜鸟写法正向反复循环;
        // if(index > 3){
        //   index = count - index;
        // }
        
        //思路2:高级写法求模
         index %= count;// index =index % count;
         //模=数字总长度,可以让0-3下标某特定的数字段可以一直反复循环 ,
        //1%4=1,2%4=2,3%4=3,4%4=0 
        //之后index+1 1+1  2+1 3+1 0+1即可

        oPic.src = `images/p${index + 1}.jpg`; //第四步
    }


    //点击左按钮会发生什么??  p1- p4- p3 - p2 -p1... 
    btnPrev.onclick = function () {
        index--; //下标最小为0  
        //因为图片默认是从p1开始的,左点击的目的就是为了让图片跳到p1 - p4- p3 - p2 -p1... 
        //思路一:菜鸟写法反向反复循环;
        // if(index < 0){
        //    index = count - 1;
        //  }
        
       //思路2:高级写法求模
        index = (count + index) % count; 
        //index=0 index-- index=-1
        //  (4-1)%4 = 3  此时index=3  3+1=p4
        //(4+2)%4 = 2   此时index=2  2+1=p3
        //(4+1)%4 = 1    此时index=1  1+1=p2
        //(4+0)%4 = 0   此时index=0  0+1=p1
        oPic.src = `images/p${index + 1}.jpg`;
    }



  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hfIFMcEl-1620307183652)(C:\Users\tuyue\AppData\Local\Temp\126.gif)]

④终极升级版:
功能一:onclick点击左右箭头轮播来切换图片同时下面的span圆图标也跟着变颜色
功能二:onmouseover鼠标滑过span圆图标鼠标滑过可以切换图片
<!--
 * @Author: your name
 * @Date: 2020-08-10 20:31:13
 * @LastEditTime: 2021-04-07 15:34:34
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \案例\case00.html
-->
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 轮播图 进阶丐版 slideShow + 按钮</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      display: flex;
      justify-content: center;
    }

    .banner {

      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      position: relative;
      width: 500px;
      box-shadow: 0 0 8px #333;

    }

    .slider {
      display: flex;
      justify-content: space-around;
      align-items: center;
      position: absolute;
      bottom: 10px;
      width: 380px;
    }

    .slider span {
      width: 45px;
      height: 45px;
      line-height: 45px;
      background-color: orange; /*默认都是为橙色的*/
      text-align: center;
      font-size: 20px;
      color: #fff;
      border-radius: 50%;
      cursor: pointer;
    }

    .btn-wrap span {
      user-select: none;
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto;
      width: 40px;
      height: 85px;
      line-height: 85px;
      font-size: 32px;
      color: #fff;
      text-align: center;
      background-color: rgba(0, 0, 0, .4);
      cursor: pointer;
    }

    .btn-wrap span:hover {
      background-color: rgba(0, 0, 0, .8);
    }

    .prev {
      left: 0;
    }

    .next {
      right: 0;
    }
  </style>
</head>

<body>
  <div class="banner">
    <img id="pic" src="images/p1.jpg" width="500" height="375" alt="pkq">
    <div class="slider">
      <span style="background-color: pink;">1</span> 
      <span>2</span>
      <span>3</span>
      <span>4</span>
    </div>
    <div class="btn-wrap">
      <span class="prev">&lt;</span>
      <span class="next">&gt;</span>
    </div>
  </div>
  <script>
    /*

      点击对应的slider 根据slider的值替换 图片的src

      1-4 点击 next的时候 下标++ 点击 prev的时候 下标--

      图片进行循环 0 1 2 3 0 1 2 3 0 1 2 3


      代码的优化合并 

        1. 梳理 哪些操作(行为)是重复的 

          1.  oPic.src = `images/p${index + 1}.jpg`;
          2.  oSlider.children[index].style.backgroundColor = 'pink';
          3.  oSlider.children[index].style.backgroundColor = 'orange';

        2. 分类 行为进行分类

          1. 点击 prev next 或 移入 slider的span => 修改了 index下标
          2. 根据 index 下标 切换展示的图片 index + 1
          3. 根据 index 下标 切换展示状态的 slider>span


        3. 事件对应行为分类

          1. 点击左右按钮
            1. 点击左按钮
              index-- /
              index = (count + index) % count;/
              图片根据index切换 
              小圆点根据index切换
            2. 点击右按钮
              index++/
              index %= count; /
              图片根据index切换 
              小圆点根据index切换
          2. 移入小圆点 轮转or排他(选项卡切换)
              index = e.target.innerText - 1;/
              图片根据index切换 
              小圆点根据index切换

              
        4. 封装
              图片根据index切换 
              小圆点根据index切换
        

        一.事件的回调函数内 , 只负责index下标的改变

        二.封装函数内, 只负责图片和小圆点 根据下标来切换

    */

     
    var oPic = document.querySelector('#pic');
    var oSlider = document.querySelector('.slider');
    var btnPrev = document.querySelector('.prev');
    var btnNext = document.querySelector('.next');
    var index = 0; //下标从0开始 图片对应需要是 p(index+1) 0 - 3  p1 - p4
    var count = 4;



    /*   
       1. 需要让上一次激活(pink)的小圆点     取消激活(orange)
       2. 修改下标
       3. 激活修改后下标对应的小圆点
       4. 根据下标切换图片路径赋值给src


       封装之后 想办法把 第二步 插入封装函数让第二步在对应的位置执行
    
     */   
    function changeSlider(callback) { //这个函数是为了点击左边滑轮的时候可以同步让下面粉色点击键一起走.
      //形参如果没有传入对应实参 undefined
      //第一步,先把当前div内部的当前span标签的颜色先变为橙色先,因为默认第一个span原点是粉色的.
      //每次都要先把当前一张的粉色图片变为橙色先,再去下一张切换图片和颜色  
      oSlider.children[index].style.backgroundColor = 'orange'; //index=0
      //第二步 ,传一个回调函数过来会拿到当前用户即将要看到的这张图片下标,然后再把当前这span圆轮滑变为粉色
      callback && callback(); //undefined() => 报错 一切非函数+()执行都会报错  
      //为什么要这么干是因为没传实参过来时  callback()会变为undefined();会报错,这么写是黑科技写法
      //又有人问为什么为什么要单独进入回调去让index变为index++/--而不是直接写在这里?
      //因为你格局小了 ,直接写只能写一个  index++或者index-- ,而用回调函数的磨练可以提扩解耦,需要++/--再单独调用回调函数来改变index即可.这样一个方法可以提高复用性,细品.
        
      //第三步,经过回调函数的磨练之后index要index++/index--
        oSlider.children[index].style.backgroundColor = 'pink'; //因此这里是下一张/上一张图片变为pink
      oPic.src = `images/p${index + 1}.jpg`; //第四步,同时图片内容路径会更新到当前图片展示给用户看.
    }

      
    //如下的事件里面只做下标的修改.
     //点击右按钮,进入事件执行函数干活
    btnNext.onclick = function () {
      changeSlider(function () { //启动中间库回调函数,封装调用函数的
        index++;
        //思路一:菜鸟写法正向反复循环;
        // if(index > 3){
        //   index = count - index;
        // }
        
        //思路2:高级写法求模
         index %= count;//模=数字总长度,可以让0-3下标某特定的数字段可以一直反复循环 ,
        //0%4=0 1%4=1,2%4=2,3%4=3,4%4=0;
      });
    }


    //点击左按钮 ,也进入函数干活    2下标 => p3 1下标 => p2
    btnPrev.onclick = function () {
      changeSlider(function () {
        index--; // 下标最小为0 0 - 3 -1 => 3   3 2 1 0 3 2 1 0
        //思路一:菜鸟写法反向反复循环;
        // if(index < 0){
        //    index = count - 1;
        //  }
        
       //思路2:高级写法求模
        index = (count + index) % count; //(4+2)%4 = 2 (4 - 1)%4 = 3 (4+0)%4 = 0
      });
    }


    //这里是鼠标移入的时候,进入changeSlider封装函数实现span圆图标鼠标滑过可以切换图片
    oSlider.onmouseover = function (e) {
      if (e.target.tagName.toLowerCase() === 'span') {
        changeSlider(function () {
          index = e.target.innerText - 1; //1-1=0 =>进入封装会++第1张pic  1=>第2张pic
        });
      }
    }

    
   /*
   回调机制的优势? (让index实现不同的功能,一个回调是实现index++,一个回调实现index--;)

分解来讲就是: 因为回调函数就是主函数套回函数,先主后回.主函数会从回调函数那里谋取某些数据,来响应给主函数去执行输出

1.回调function函数体{con}作为中间库函数例如map的实参 , 通过中间的库函数可被唤醒去调用回调 .

2.然后再从中间库函数中谋取一些数据(比如index)用来给回调函数充当局部实参,如果index是全局变量则不用实参也可直接在回调函数内修改(即从中间库函数拿到需要调用,回调函数的实参数据,才能进入回调函数的调用), ,

3.最后调用回调函数callback();时,实参会对应回调回去给function回调函数体形参那里,然后输出形参即可拿到库函数内的一些实参数据.比如foreach遍历拿到数组每项元素/下标/整个数组.
(这里因为index是全局变量,因此callback();不用实参也可以直接修改index变为index++/index--)

4.总结简单粗暴:回调函数体function(){con}就是一个中间接口,优点是可插拔,可以随意更换不同的回调函数体,然后去在js内置的库方法函数内的一些数据拿来当调用回调函数的实参.

因此:   传入不同功能的回调函数,回调回来结果表现也不同,这就是回调机制的优势所在

   
   */
    
    
    
  
  //下面是你不理解回调函数原理时:就看看下面的例子明白回调函数用来干啥的. 
  /*
  回调函数就是用来处理map原生库方法数组遍历的每项元素的,具体怎么处理看你,然后再返回去给主函数接收. 	map方法接收用来当成新数组的每一项.然后输出. (新数组每一项其实 就是 原数组的每一项数经过回调函数的历练计算然后从回调那里return接收回来再干别的事, 最终在主函数方法return输出的 )
  */
   /*
   //map原理:
	this.map = function (callback) {
          var nw = [];		//创建新数组nw,准备拿来放最终结果
          for (var i = 0; i < this.arr.length; i++) {
            nw[i] = callback(this.arr[i], i, this.arr); // 
          }
          return nw; 
        }
    }
    
  //map
 var originArr =  [1,2,3,4,5];
var newArr = originArr.map(function(current,index,array){ //中间库函数,启动回调也是放一个回调函数
    return current * 2;
});
console.log(newArr); //最终输出map方法的返回值,死记
//[2,4,6,8,10]
   */
      
      

   


  </script>
</body>
</html>
不封装的源代码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuZF9vcI-1620307183654)(C:\Users\tuyue\AppData\Local\Temp\1617790769201.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3oHuLNto-1620307183656)(C:\Users\tuyue\AppData\Local\Temp\125.gif)]

⑤实际开发的轮播: ul>li ,并且不会只写一个img和src
<!--
 * @Author: your name
 * @Date: 2020-08-10 20:31:13
 * @LastEditTime: 2020-08-11 21:50:08
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \案例\case00.html
-->
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 轮播图sliderShow 基础班</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      list-style: none;
    }

    body {
      display: flex;
      justify-content: center;
    }

    .banner {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      position: relative;
      width: 500px;
      height: 290px;
      margin-top: 100px;
      box-shadow: 0 0 12px #333;
    }

    .pic li {
      display: none;
      position: absolute;
      top: 0;
      left: 0;
    }

    .pic li.on {
      display: block;
    }

    .pic li img {
      width: 500px;
      height: 290px;
    }

    .slider {
      display: flex;
      justify-content: space-around;
      align-items: center;
      position: absolute;
      bottom: 10px;
      width: 380px;
    }

    .slider span {
      width: 45px;
      height: 45px;
      line-height: 45px;
      background-color: orange;
      text-align: center;
      font-size: 20px;
      color: #fff;
      border-radius: 50%;
      cursor: pointer;
    }

    .slider span.active {
      background-color: pink;
    }

    .btn-wrap span {
      user-select: none;
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto;
      width: 40px;
      height: 85px;
      line-height: 85px;
      font-size: 32px;
      color: #fff;
      text-align: center;
      background-color: rgba(0, 0, 0, .4);
      cursor: pointer;
    }

    .btn-wrap span:hover {
      background-color: rgba(0, 0, 0, .8);
    }

    .prev {
      left: 0;
    }

    .next {
      right: 0;
    }
  </style>
</head>

<body>
  <div class="banner">
    <ul class="pic">
      <li class="on bg333 c368"><img src="images/p1.jpg" alt=""></li>
      <li class="bg333 c368"><img src="images/p2.jpg" alt=""></li>
      <li class="bg333 c368"><img src="images/p3.jpg" alt=""></li>
      <li class="bg333 c368"><img src="images/p4.jpg" alt=""></li>
    </ul>
    <div class="slider">

    </div>
    <div class="btn-wrap">
      <span class="prev">&lt;</span>
      <span class="next">&gt;</span>
    </div>
  </div>
  <script src='js/common.js'></script>
  <script>
    /*
      基础版本轮播图

      1. pic 实际开发并下面不是直接通过修改一个img的src来进行切换 而是通过直接列入多个轮播项(pic>li)

      2. span 滑轮slider 指示器需要根据 li的数量 动态生成

      3. 轮播的主要思想:
      就是进行切换 通过公共下标 确定展示哪个picLi 其他的 li 隐藏 指示器同理


      ----------------------------------------------------------------------------------------
	我们写DOM事件的时候,怎么搞思路和步骤呢?

      1. 开始提前布局配菜获取dom节点元素先: 思考那些元素是需要用到的 .pic>li .slider .prev .next

      2. 需要的功能函数 getElementIdx获取元素下标  createSlider   switchTab/changeSlider(切换卡思想)

      2. 写思考事件交互 onclick:[.prev,.next] onmouseenter:[sliders]

      3. 具体内部主要行为有哪些 
        1. 根据 index 切换 aPicList的 类名(.on) 以及 sliders的 active类名 
        当前index所对应的 picList 需要设置类名为 on 其他的picList类名设置为 '' sliders当前index对应的设置类名为 active 其他的设置类名为 ''

        2. 根据用户的交互事件 修改index
        即③总结:根据用户的点击/xx行为,先来切换index,再根据index切换其他效果:选项卡/内容

      4. 主要的操作API 或者 技巧
        1. 修改index  index++  限制 index-- 限制 getElementIdx
        2. .className 操作 (classList获取某个标签节点对象的类名总列表)
        3. 回调函数




    console.log(aPicList[0].classList) //指定DOM对象的类名列表

    aPicList[0].classList.add('w1000'); //添加 如果不存在添加上
    aPicList[0].classList.add('c368'); //添加 如果存在 就忽略

    aPicList[0].classList.remove('c368');//删除 如果类名列表 上存在 c368 就删掉

    aPicList[0].classList.toggle('w1000'); //开关 如果有就删 如果没有就添 

    aPicList[0].classList.replace('bg333', 'bg222'); //repace(A,B) 把列表中的类名A替换成 B


    */

    var aPicList = $$('.pic>li'),
      oSLider = $('.slider'),
      oBtnWrap = $('.btn-wrap'),
      sliderIdx = 0, sliderLen = aPicList.length;



    //映射地图 
    var btnTypeMap = {
      prev: function () {
        sliderIdx--;
        sliderIdx = (sliderLen + sliderIdx) % sliderLen;
      },
      next: function () {
        sliderIdx++;
        sliderIdx = sliderIdx % sliderLen;
      }
    }


    oBtnWrap.addEventListener('click', function (e) {
      if (e.target.tagName.toLowerCase() === 'span') {
        var btnType = e.target.className; //next prev
        btnTypeMap[btnType] && switchSlider(function () {
          btnTypeMap[btnType]();
        });
      }
    }, false);


    //监听sliders > span的 mouseover 鼠标移入事件 
    oSLider.addEventListener('mouseover', function (e) {
      if (e.target.tagName.toLowerCase() === 'span') {
        //事件委托 可以作用于还未创建出来的DOM节点
        switchSlider(function () {
          sliderIdx = getElementIdx(e.target);
        })
      }
    }, false);


    function switchSlider(callback) {
      /*
        1. 让上一次index对应的picList 和 sliderSpan 都隐藏 类名= ''
        2. 设置index = 当前用户选中的index
        3. 让当前index对应的picList 和sliderSPan 的类名分别设置为 on active
      */
      aPicList[sliderIdx].classList.remove('on');
      oSLider.children[sliderIdx].classList.remove('active');
      callback && callback();
      aPicList[sliderIdx].classList.add('on');
      oSLider.children[sliderIdx].classList.add('active');
    }

    /**
     * @description:  根据 picList的数量 创建span添加到 oSlider 中 功能性函数 fragment节点片段
     * @Date: 2020-08-11 20:52:36
     */
    function createSlider() {
      var fragment = document.createDocumentFragment();
      var vDom;
      for (var i = 0; i < sliderLen; i++) {
        vDom = document.createElement('span');
        vDom.innerText = i + 1;
        fragment.appendChild(vDom);
      }
      fragment.children[0].classList.add('active');
      oSLider.appendChild(fragment);
    }

    createSlider();

  </script>
</body>

</html>

classList获取某个标签节点对象的类名总列表):


console.log(aPicList[0].classList) //指定DOM对象的类名列表

    aPicList[0].classList.add('w1000'); //添加 如果不存在添加上
    aPicList[0].classList.add('c368'); //添加 如果存在 就忽略

    aPicList[0].classList.remove('c368');//删除 如果类名列表 上存在 c368 就删掉

    aPicList[0].classList.toggle('w1000'); //开关 如果有就删 如果没有就添 

    aPicList[0].classList.replace('bg333', 'bg222'); //repace(A,B) 把列表中的类名A替换成 B

//为什么需要这个,看如下代码.
//原来:是很暴力直接把标签的类名干掉aTab[index].className = '';,然后on激活状态就取消了
//可是问题来了,这样暴力全部干掉就会让其他的样式类名也一起干死了,这样的话就样式发生出错了不匹配了

  function switchTab() {//封装为一个方法.
        var index = 0;//公共下标
        for (var i = 0, len = aTab.length; i < len; i++) { //遍历三个li,长度为3
        (function (i) {
          aTab[i].onclick = function () { //传入i=0是默认激活状态,给第一个去调类名,此时index再等于0也是给第一个切换卡又重新给类名即点击第一个切换卡所有东西是不变的.
            //因此我们只去考虑当点击i=1时即点击第2个Tab切换键时会发生什么
            aTab[index].className = '';//首先index还是=0 ,即aTab[0].className = ''; 即第一个li默认值的on样式状态消失了
            aCon[index].className = '';//同时让第一个tab键的第一个li的active内容消失了变为默认none.
             
            //这里开始改写命运 
            index = i;  // index = 1; 因为此时i循环为1了,让index变为1了即去到第二个给第二个修改效果了
            aTab[index].className = 'on';//然后再让第二个Tab切换键 即aTab[1].className = 'on' ;即轮到第二个li变为激活状态了,让其on样式生效,即等于Tab切换键切换过来了
            aCon[index].className = 'active';//同理第二个Tab切换键下的第二个li内容变为active,即变为block展现出来,即也内容等于切换过来了
          
          }
        })(i); 
      }
    }

//因此,有了.classList获取某个标签节点对象的类名总列表:
//现在,可以通过获取标签节点的类名列表然后单独干掉某个js需要干掉激活样式类名即可,不需要全部干死了
  function switchSlider(callback) {
      /*
        1. 让上一次index对应的picList 和 sliderSpan 都隐藏 类名= ''
        2. 设置index = 当前用户选中的index
        3. 让当前index对应的picList 和sliderSPan 的类名分别设置为 on active
      */
      aPicList[sliderIdx].classList.remove('on');
      oSLider.children[sliderIdx].classList.remove('active');
      callback && callback();
      aPicList[sliderIdx].classList.add('on');
      oSLider.children[sliderIdx].classList.add('active');
    }


8.input输入款案例:

<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 输入验证 </title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      display: flex;
      justify-content: center;
    }

    input {
      outline: none; /* 不要聚焦框,用边框颜色代替 */
      width: 240px;
      height: 45px;
      margin-top: 100px;
      padding: 4px 8px;
      border: 2px solid #222;
      line-height: 45px;
      font-size: 18px;
      border-radius: 4px;
    }
  </style>
</head>

<body>
  <input id="user" type="text" name="userName" placeholder="请设置账号 长度6-20">
  <script>
    /*
      用户在input中输入账号 如果不符合要求就input边框为红色
      如果符合要求了 边框为绿色

      onkeydown 用户按下按键 但是值还没有正式被输入框录入,
    */

    var oUser = document.querySelector('#user');

    oUser.onkeydown = function () {
      // console.log('hahaha')
       console.log(this.value);
      var len = this.value.length;
      var color = 'red'; //预制结果.
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }


    oUser.onkeyup = function () {
      console.log(this.value)
      var len = this.value.length;
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }

    oUser.onkeypress = function () {
      //键盘响应到输入 中文输入法输入的时候 无响应
      console.log(this.value)
      var len = this.value.length;
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }

    oUser.oninput = function () {
      //input内容有输入的时候触发 响应输入法
      var len = this.value.length;
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }


    oUser.onchange = function () {
      //只有当输出框失去焦点的时候 input的value才会发生了改变 
      var len = this.value.length;
      console.log('hahah')
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }


  </script>
</body>

</html>

onkeydown:一边打一边输出,但是要第二次才会显示输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mi9amYj3-1620307183660)(C:\Users\tuyue\AppData\Local\Temp\1617696383070.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NYoGghIE-1620307183661)(C:\Users\tuyue\AppData\Local\Temp\1617697829645.png)]

onkeyup:松开键盘才会打印,不然就会叠加一次性输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9fUMNtH-1620307183663)(C:\Users\tuyue\AppData\Local\Temp\1617696626580.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-heiyn96A-1620307183664)(C:\Users\tuyue\AppData\Local\Temp\1617697749076.png)]

onkeypress:也是一边打一边输出,但是也要第二次才会显示输出,对于中文失效.

因为我们的中文都是输出到输入法软件去的,比如如下的案例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vw4QkuRl-1620307183666)(C:\Users\tuyue\AppData\Local\Temp\1617698891929.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9RPzfCmx-1620307183668)(C:\Users\tuyue\AppData\Local\Temp\1617697651034.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fbBnxc2Y-1620307183670)(C:\Users\tuyue\AppData\Local\Temp\1617698014298.png)]

oninput:也是一边打一边输出,对于中文是有效.(目前用最多,最完美的输出)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9mbvpa0y-1620307183673)(C:\Users\tuyue\AppData\Local\Temp\1617699573352.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QM0QM8HF-1620307183675)(C:\Users\tuyue\AppData\Local\Temp\1617699703415.png)]

onchange: 只有当输出框失去焦点的时候 input的value才会发生了改变

aPicList[sliderIdx].classList.add(‘on’);
oSLider.children[sliderIdx].classList.add(‘active’);
}




# 8.input输入款案例:

```html
<!DOCTYPE html>
<html lang="zh-cn">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title> 输入验证 </title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      display: flex;
      justify-content: center;
    }

    input {
      outline: none; /* 不要聚焦框,用边框颜色代替 */
      width: 240px;
      height: 45px;
      margin-top: 100px;
      padding: 4px 8px;
      border: 2px solid #222;
      line-height: 45px;
      font-size: 18px;
      border-radius: 4px;
    }
  </style>
</head>

<body>
  <input id="user" type="text" name="userName" placeholder="请设置账号 长度6-20">
  <script>
    /*
      用户在input中输入账号 如果不符合要求就input边框为红色
      如果符合要求了 边框为绿色

      onkeydown 用户按下按键 但是值还没有正式被输入框录入,
    */

    var oUser = document.querySelector('#user');

    oUser.onkeydown = function () {
      // console.log('hahaha')
       console.log(this.value);
      var len = this.value.length;
      var color = 'red'; //预制结果.
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }


    oUser.onkeyup = function () {
      console.log(this.value)
      var len = this.value.length;
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }

    oUser.onkeypress = function () {
      //键盘响应到输入 中文输入法输入的时候 无响应
      console.log(this.value)
      var len = this.value.length;
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }

    oUser.oninput = function () {
      //input内容有输入的时候触发 响应输入法
      var len = this.value.length;
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }


    oUser.onchange = function () {
      //只有当输出框失去焦点的时候 input的value才会发生了改变 
      var len = this.value.length;
      console.log('hahah')
      var color = 'red';
      if (len >= 6 && len <= 20) {
        color = 'green';
      }
      this.style.borderColor = color;
    }


  </script>
</body>

</html>

onkeydown:一边打一边输出,但是要第二次才会显示输出:

[外链图片转存中…(img-Mi9amYj3-1620307183660)]

[外链图片转存中…(img-NYoGghIE-1620307183661)]

onkeyup:松开键盘才会打印,不然就会叠加一次性输出:

[外链图片转存中…(img-v9fUMNtH-1620307183663)]

[外链图片转存中…(img-heiyn96A-1620307183664)]

onkeypress:也是一边打一边输出,但是也要第二次才会显示输出,对于中文失效.

因为我们的中文都是输出到输入法软件去的,比如如下的案例:
[外链图片转存中…(img-Vw4QkuRl-1620307183666)]

[外链图片转存中…(img-9RPzfCmx-1620307183668)]
[外链图片转存中…(img-fbBnxc2Y-1620307183670)]

oninput:也是一边打一边输出,对于中文是有效.(目前用最多,最完美的输出)

[外链图片转存中…(img-9mbvpa0y-1620307183673)]

[外链图片转存中…(img-QM0QM8HF-1620307183675)]

onchange: 只有当输出框失去焦点的时候 input的value才会发生了改变

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YPI9B7kL-1620307183677)(C:\Users\tuyue\AppData\Local\Temp\1617700767890.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值