day10

179 阅读12分钟

1.认识事件

认识事件(DOM 事件)
    + 就是和页面的某一个元素约定好一个事情, 当行为发生的时候, 执行指定的一段代码

  事件三要素:
    1. 事件源: 给谁绑定事件
    2. 事件类型: 绑定什么事件
    3. 事件处理函数: 当行为发生的时候, 所执行的函数
    + 例子:
      box.onclick = function () { }
      => box 就是事件源
      => click 是事件类型
      => function () {} 事件处理函数
      => 和浏览器做了一个约定
        -> 当有 click 行为发生在 box 这个元素身上的时候, 执行后面的函数

  事件绑定的方式
    + DOM 0级 事件
      => 语法: 事件源.on事件类型 = 事件处理函数
      => 同一个事件源的同一个事件类型只能绑定一个事件处理函数
    + DOM 2级 事件(事件侦听器 / 事件监听器)
      => 标准浏览器
        -> 语法: 事件源.addEventListener('事件类型', 事件处理函数)
        -> 特点: 可以给同一个事件源的同一个事件类型绑定多个事件处理函数, 顺序绑定顺序执行
      => IE 低版本
        -> 语法: 事件源.attachEvent('on事件类型', 事件处理函数)
        -> 特点: 可以给同一个事件源的同一个事件类型绑定多个事件处理函数, 顺序绑定倒序执行

  事件解绑的方式
    + DOM 0级 事件
      => 语法: 事件源.事件类型 = null
    + DOM 2级 事件
      => 标准浏览器: 事件源.removeEventListener('事件类型', 要解绑的事件处理函数)
      => IE 低版本: 事件源.detachEVent('on事件类型', 要解绑的事件处理函数)
      => 注意: DOM 2级 事件, 如果你需要解绑, 那么绑定的时候, 必须要把函数单独书写出来, 以函数名的形式进行绑定和解绑
      
// 获取元素
var ele = document.querySelector('div')
var btn = document.querySelector('button')

// 1. DOM 0级 事件
ele.onclick = function () { console.log('我是第一个事件处理函数') }

// 2. DOM 2级事件
ele.addEventListener('click', function () { console.log('DOM 2级 事件 111') })
ele.addEventListener('click', function () { console.log('DOM 2级 事件 222') })
ele.addEventListener('click', function () { console.log('DOM 2级 事件 333') })

// 事件解绑
// 第一步: 先绑定事件
// 绑定 DOM 0级 事件
ele.onclick = function () { console.log('我被点击了') }

// 绑定 DOM 2级 事件
function handler() { console.log(222) }
ele.addEventListener('click', function () { console.log(111) })
ele.addEventListener('click', handler)

// 第二步: 解绑事件
btn.onclick = function () {

  console.log('我要解绑事件了')

  // 解绑 DOM 0级 事件
  ele.onclick = null

  // 解绑 DOM 2级 事件
  ele.removeEventListener('click', handler)

  console.log('解绑事件的代码执行了')
}

2.事件对象

事件对象
    + 一个记录本次事件触发的时候, 所有的相关信息, 一个对象数据类型
    + 例子: 当一个鼠标事件发生的时候
      => 针对当前本次的事件触发会有一些信息出现
        -> 坐标位置 x: 100, y: 200
        -> 谁触发的事件: div
        -> 什么事件: click
        -> ...
      => 浏览器把这些信息记录下来了
        -> 放在了一个对象数据类型内
        {
          x: 100,
          y: 200,
          target: div,
          type: 'click',
          ...
        }
    + 当你需要获取一些本次事件相关的信息的时候
      => 需要先拿到事件对象
      => 从事件对象内去获取

  获取事件对象的方式
    => 标准浏览器: 直接给事件处理函数书写形参, 会在事件触发的时候, 有浏览器自动传递实参
    => IE 低版本: 直接使用 window.event
    => 兼容: e = e || window.event

var ele = document.querySelector('div')
ele.onclick = function (e) {
  // 这个事件处理函数的第一个形参
  // 会在你触发该事件的时候, 有浏览器传递实参
  // 传递进来的实参就是本次事件触发的事件对象
  // 处理事件对象兼容
  e = e || window.event
}

3.事件的传播

事件的传播
    + 当行为发生的时候, 按照元素结构父级的顺序, 向上传递该事件行为, 直到 window 为止

  问题1: 如果 inner 身上没有绑定点击事件, 会不会继续传播了 ?
    => 会
    => 因为传递的是 事件行为
  问题2: 如果 center 身上没有绑定点击事件, 会不会继续传播了 ?
    => 会
    => 因为传递的是 事件行为
  问题3: 如果点击在 center 身上, 会不会传播到 inner 身上 ?
    => 不会
    => 因为是按照 结构父级 的顺序向上传播

  在事件对象内, 有一个成员叫做 path
    => 表示本次事件触发的时候, 事件传播的路径

  事件流机制(了解)
    => 当一个行为发生的时候, 从浏览器反映到元素身上的过程
    => 并且包含触发事件的时机问题
    => 机制是 浏览器 给的
    => 所有浏览器的共同点
      -> 虽然一次事件, 一个内容接受了两次事件行为, 但是是在一次事件内接受的
      -> 只会触发一次事件处理函数
    => 各个浏览器对事件流解析的不通电
      -> 标准浏览器: 默认是在 冒泡阶段 触发事件函数
      -> IE 低版本: 只能在 冒泡阶段 触发事件函数

  事件流的三个阶段
    => 事件捕获: 从 window 向 事件目标 传播的过程
    => 事件目标: 准确触发事件的元素
    => 事件冒泡: 从 事件目标 向 window 传播的过程

  在捕获阶段触发事件
    => 只能在标准浏览器内使用
    => 并且一定是 DOM 2级 事件绑定方式才可以
    => addEventListener('事件类型', 事件处理函数, 冒泡或者捕获阶段触发)
      -> 冒泡或者捕获阶段触发
      -> 默认值是 false, 表示 冒泡(从里面往外面穿)
      -> 选填内容 true, 表示 捕获(从外面往里面穿)
      
      
var outer = document.querySelector('.outer')
var center = document.querySelector('.center')
var inner = document.querySelector('.inner')

// 当你点击在 inner 身上的时候, 因为事件传播, 会把点击行为向父元素传递
inner.onclick = function (e) { console.log('inner') }
// 相当于点击在 center 身上, 此时 center 身上的点击事件就会触发
// 当有点击行为发生在 center 身上的时候, 就会触发
center.onclick = function () { console.log('center') }
outer.onclick = function () { console.log('outer') }
document.body.onclick = function () { console.log('body') }
document.documentElement.onclick = function () { console.log('html') }
document.onclick = function () { console.log('document') }
window.onclick = function () { console.log('window') }

// DOM二级事件
inner.addEventListener('click', function () { console.log('inner') }, false)
center.addEventListener('click', function () { console.log('center') }, false)
outer.addEventListener('click', function () { console.log('outer') }, true)
document.body.addEventListener('click', function () { console.log('body') }, false)
document.documentElement.addEventListener('click', function () { console.log('html') }, false)
document.addEventListener('click', function () { console.log('document') }, false)
window.addEventListener('click', function () { console.log('window') }, false)

//对比(捕获)
inner.addEventListener('click', function () { console.log('inner') }, true)
center.addEventListener('click', function () { console.log('center') }, true)
outer.addEventListener('click', function () { console.log('outer') }, true)
document.body.addEventListener('click', function () { console.log('body') }, true)
document.documentElement.addEventListener('click', function () { console.log('html') }, true)
document.addEventListener('click', function () { console.log('document') }, true)
window.addEventListener('click', function () { console.log('window') }, true)

 //对比(冒泡)
inner.addEventListener('click', function () { console.log('inner') },  false)
center.addEventListener('click', function () { console.log('center') },  false)
outer.addEventListener('click', function () { console.log('outer') },  false)
document.body.addEventListener('click', function () { console.log('body') },  false)
document.documentElement.addEventListener('click', function () { console.log('html') },  false)
document.addEventListener('click', function () { console.log('document') },  false)
window.addEventListener

4.阻止事件的传播(冒泡)

阻止事件传播
    + 就是不让事件行为继续向上传递
    + 到自己为止了

  语法:
    => 标准浏览器: 事件对象.stopPropagation()
    => IE 低版本: 事件对象.cancelBubble = true
    
    
var eleDiv = document.querySelector('div')
var eleP = document.querySelector('p')

eleDiv.onclick = function () {
  console.log(window.getComputedStyle(this).backgroundColor)
}

eleP.onclick = function (e) {
  // 阻止事件传播
  // e.stopPropagation()
  console.log(window.getComputedStyle(this).backgroundColor)
}

微信图片_20220614002549.png

5.阻止默认行为

阻止默认行为

  默认行为
    => 元素本身自带的行为, 不需要你进行事件绑定
      -> 鼠标右键单击事件: 弹出菜单
      -> a 标签的点击事件: 跳转连接
      -> 表单的提交按钮: 表单提交

  阻止默认行为
    => 在同类型事件内, 阻止默认出现的行为
    => 标准浏览器: 事件对象.preventDefault()
    => IE 低版本: 事件对象.returnValue = false
    => 通用: return false


window.oncontextmenu = function (e) {
  // 阻止默认行为
  // e.preventDefault()
  console.log('右键单击')

  return false
}

document.querySelector('form').onsubmit = function (e) {
  // e.preventDefault()
  console.log('对表单填写的内容进行验证, 验证合适以后在发给服务器')     
  return false
}

5.1阻止默认行为例子补充

 有很多的系统事件除了会触发执行函数,还会触发执行部分特有的内容
1.比如submit,当收到这个事件后会跳转到表单所对应的action地址
 reset...
2.比如超链接点击时,默认有hash改变添加历史记录,使用e.preventDefault();就不会有hash改变了,也不会有历史记录
3.图片拖拽时产生禁拖标记,使用它也可以不产生禁拖标记
4.侦听mousedown事件时,如果设置e.preventDefault();就不能拖选中文本内容了
5.当点击鼠标右键时,一般会触发右键菜单,e.preventDefault();不会触发右键菜单
 
 例:
4.submit演示-阻止默认行为
 var form=document.querySelector("form");
 form.addEventListener("submit",submitHandler);

 function submitHandler(e){
    console.log(e)
    e.preventDefault();        //阻止默认行为事件
    
}

4.1 操作超链接试试-阻止默认行为
 var a=document.querySelector("a");
 a.addEventListener("click",clickHandler);

 function clickHandler(e){
    e.preventDefault();       //阻止超链接跳转
    
}

4.2 默认文字选中      mousedown 鼠标按下操作
 var div=document.querySelector("div");
 div.addEventListener("mousedown",mouseHandler);

 function mouseHandler(e){
    e.preventDefault();      //阻止文字选中
    
}

4.3 contextmenu鼠标右键函数
 document.addEventListener("contextmenu",contextmenuHandler);

 function contextmenuHandler(e){
    e.preventDefault();     //阻止右键菜单
       
}

6.阻止当前事件类型的函数列表中的后续函数的执行

e.stopImmediatePropagation();  //阻止当前事件类型的函数列表中的后续函数的执行 (同事件类型)

div1.addEventListener("click",clickHandler1);
div1.addEventListener("click",clickHandler2);
div1.addEventListener("click",clickHandler3);
div1.addEventListener("mousedown",clickHandler4);

function clickHandler1(e){
    console.log("a")
}
function clickHandler2(e){
    console.log("b");
    e.stopImmediatePropagation();  //阻止当前事件类型的函数列表中的后续函数的执行 (同事件类型)
}         //只有同事件的下一个函数会被阻止  这里c被阻止c的事件是(click)  d没被阻止d的事件(mousedown)
function clickHandler3(e){
    console.log("c")
}

function clickHandler4(e){
    console.log("d");
}

7.事件委托

事件委托
    + 把自己的事件委托给某一个结构父级

  循环绑定事件
    + 缺点:
      1. 对于后期动态操作的元素不够友好
      2. 大量的 DOM 操作, 性能在浪费

  事件委托
    + 优点:
      1. 对于后期动态操作的元素足够友好
      2. 少量的 DOM 操作
 
将所有事件委托给父级元素的方式叫做事件委托
把所有子元素的事件委托给父元素,这样减少了多个事件侦听,通过
一个事件侦听执行所有子元素事件问题,当使用事件委托时,就可以
不再使用e.stopPropagation();阻止冒泡了,因为只执行了最后一层函数(最上面一层)

// 现在: 事件委托
var ul = document.querySelector('ul')
// 当你点击 ul 的时候, 可以直接触发
// 当你点击 li 的时候, 因为事件传播, 也会触发
// 为什么要给 ul 绑定事件, 为了把 li 的事件委托给 ul
//   点击 ul 应该什么事情都不做
//   点击 li 的时候才应该做
ul.onclick = function (e) {
  // 当你因为点击 ul 而触发了这个函数的时候, 事件目标 => ul
  // 当你因为点击 li 而触发了这个函数的时候, 事件目标 => li
  // if (事件目标 === li标签) {
    // 本来应该在 li 内做的事情书写在这里
  // }

  // 如何拿到事件目标
  // 语法: 事件对象.target
  // 得到: 一个节点
  // console.log(e.target)
  if (e.target.nodeName === 'LI') {
    console.log(e.target.innerText)
  }
}

// 委托给结构父级
ul.onclick = function (e) {
  if (e.target.nodeName === 'LI') {
    console.log(e.target.innerText)
  }
}

var btn = document.querySelector('button')
btn.onclick = function () {
  ul.innerHTML += '<li>新来的</li>'
}

// 未知节点.nodeName === 'LI' 为 true, 说明, 未知节点是一个 li 标签

8.This指向

 this 指向
    + 指向: 指引用地址的方向
    + 表达: this 到底是什么
    + 需要结合上下文, 决定不同位置的 this 指向的内容不一样

  this 是一个关键字(熟读并背诵全文, 手抄)
    + 是一个使用在作用域内的关键字
      => 要么用在全局
        -> 因为在全局使用 this 的时候
        -> this 指向 window
      => 要么用在函数内
    + 函数内的 this            (this只看函数调用   哪个函数里的this就看哪个函数)
      => 重点: 不管函数定义在哪, 不管函数怎么定义, 只看函数如何被调用(箭头函数除外)
      => 普通调用
        -> 函数名()
        -> this 指向 window
      => 对象调用
        -> 对象名.函数名()
        -> this 指向 对象(点前面是谁就是谁)
      => 定时器调用
        -> setTimeout(函数, 数字)
        -> setInterval(函数, 数字)
        -> this 指向 window
      => 事件处理函数
        -> 事件源.on事件类型 = 函数
        -> 事件源.addEventListener(事件类型, 函数)
        -> this 指向 事件源
      => 未完待续 ...
      
      
function fn() {
  console.log('fn 函数内的打印信息')
  console.log('this : ', this)
  console.log('------------------------------')
}

// 开始调用
// 标准的 普通调用, this => window
// fn()

var obj = {
  name: '我是 obj 对象',
  // fn 这个名字内存储的是 fn 函数的地址
  // 赋值给 obj 的 f 成员
  // 从此以后, obj.f 和 fn 变量存储的是一个函数地址
  f: fn
}
// 标准的对象调用, this => obj
obj.f()

var btn = document.querySelector('button')
// obj.f 存储的是一个函数地址
// 把这个函数地址赋值给了 btn 的 click 事件
// 当你点击 btn 的时候, 会触发 obj.f 也就是全局 fn 函数
// 事件处理函数调用, this => 事件源(btn)
btn.onclick = obj.f

// 把 fn 函数当做事件处理函数使用
// 2000ms 以后执行 fn 函数
setTimeout(fn, 2000)

// 哪个函数内的 this 就看哪个函数是怎么调用的

9. on事件和addEventListener事件区别

1、只有系统事件使用on  不能自定义事件
2on事件可以在标签上定义,但是不能通过标签中传事件参数
3、onclick只能赋值一个函数,如果赋值多个函数会被替换,addEventListener可以侦听多次
4、大多数的on事件函数都是匿名函数,造成同一个函数不能复用,不能抽象出来

10.Event事件(记)

 change
 error
 load
 reset
 resize
 select
 submit
 scroll
 
1.change 可以针对表单元素,也可以针对表单
        修改触发事件
        
例:
 var form=document.querySelector("form");
    var input=document.querySelector("input"); //修改并且失去焦距时
    var radio=document.querySelector("[type=radio]");   //侦听第一个男的
    // 表单内子元素修改后冒泡会触发父元素的事件,支持冒泡  (文本框一修改)
    form.addEventListener("change",changeHandler);

    function changeHandler(e){
        console.log(e)
    }


2.select  选择,文本框选择
        文本框中文本被选中时   
  
例:
var input=document.querySelector("input");
input.addEventListener("select",selectHandler);

    function selectHandler(e){
        console.log(input.selectionStart,input.selectionEnd) //选择的起始位置和结束位置
        console.log(e)
    }  
    
    
3.  submit  提交
    reset   重置
    针对form表单
    
例:
var form=document.querySelector("form");
    form.addEventListener("submit",submitHandler);
    form.addEventListener("reset",submitHandler);   //设置了reset 重置时不会清空

    function submitHandler(e){
        e.preventDefault();
        console.log(e)
    }
    

4.  resize  用于window对象 缩放事件
    rem em   
    window.addEventListener("resize",resizeHandler);
    
例:
function resizeHandler(e){
    // console.log("aa")
    // console.log(document.documentElement.clientWidth,"--可视窗口宽度");
    // console.log(screen.width,"---屏幕宽度")
    // 根据比例进行 自适应宽度
  document.documentElement.style.fontSize=document.documentElement.clientWidth/screen.width*100+"px"
   }
   
   
5. load  加载  
   error  加载错误
   
   预加载案例
   
6. scroll 滚动条事件 
   window document
   所有的可以设置  overflow: scroll;的容器都可以增加这个事件

例:   
document.addEventListener("scroll",scrollHandler);
function scrollHandler(e){
    console.log("aa")
}

10.1 案例-预加载