事件的简谈

208 阅读14分钟

1.什么是懒加载?

懒加载也就是延迟加载。
当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径 (这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时, 才设置图片正真的路径,让图片显示出来。这就是图片懒加载。

2.什么是预加载?

提前加载图片,当用户需要查看时可直接从本地缓存中渲染

EVENT

什么是 事件

  • 一个事件的组成
    • 触发谁的事件: 事件源
    • 触发什么事件: 事件类型
    • 触发后做什么: 事件处理函数
var oDiv = document.querySelector("div");

oDiv.onclick = function () {};
/**
 * 触发谁的事件 ---> oDiv ---> 事件源就是 oDiv
 * 触发什么事件 ---> onclick ---> 事件类型就是 click
 * 触发后做什么 ---> function () {} ---> 这个事件的处理函数
 */
var oDiv = document.querySelector("div");

oDiv.onclick = function () {
    console.log("你点击了 div");
};
  • 当我们点击 div 的时候, 就会执行事件处理函数内部的代码
  • 每点击一次, 就会执行一次事件处理函数

EVENT对象属性了解

   /* 
        isTrusted:false  只读 是否使用dispatchEvent派发的事件(手动触发) 
        false表示手动触发,true系统触发
        bubbles:false  是否允许冒泡 只读 在抛发事件中用于描述是否冒泡
        cancelBubble:false  阻止冒泡的兼容写法,已经废除
        cancelable:false  是否可以被取消 如果是true,表示有默认行为,
        可以使用e.preventDefault();取消默认行为
        
        currentTarget:null  侦听事件的对象
        defaultPrevented:false preventDefault()是否被执行调用
        eventPhase:0  0表示事件没有被触发  1 捕获阶段  2 目标阶段  3 冒泡阶段
        returnValue:true 取消默认行为 废弃
        srcElement:document  当前目标对象 废弃
        target:document  当前目标对象
        timeStamp:27.399999976158142  从当前页面运行开始到现在触发事件的毫秒数
        type:"abc" 就是设的啥事件类型,比如随便设了个abc
        preventDefault() 阻止默认行为
        stopImmediatePropagation() 阻止同事件类型后续函数执行
        stopPropagation() 阻止冒泡
    */

事件的绑定方式

  • 我们现在给一个注册事件都是使用 onXXX 的方式
  • 但是这种方式不是很好, 只能给一个元素注册一个事件, 如果写了第二个, 那么第一个会被覆盖
oDiv.onclick = function () {
    console.log("第一个事件");
};
oDiv.onclick = function () {
    console.log("第二个事件");
};
  • 我们这种绑定方式, 只会执行第二个, 第一个就没了
  • 如果想要两个都存在, 我们可以使用 事件监听的方式 去给元素绑定事件
  • 使用 addEventListener 的方式添加
    • 在 IE 中要使用 attachEvent

事件监听

addEventListener (非 IE7 8 下使用)
  • 语法: 元素.addEventListener('事件类型', 事件处理函数, 冒泡还是捕获)
oDiv.addEventListener(
    "click",
    function () {
        console.log("我是第一个事件");
    },
    false
);
oDiv.addEventListener(
    "click",
    function () {
        console.log("我是第二个事件");
    },
    false
);
     事件驱动型语言
     EventTarget  事件目标
     Event  事件

     EventTarget 事件目标对象包括三个方法
     addEventListener  侦听事件
     
     removeEventListener  删除侦听
     bn.removeEventListener("click",clickhandler);删除事件监听
     当一个事件不需要再次被触发了,就需要删除事件,否则会造成内存泄漏
     
     dispatchEvent  抛发事件  (代表默认)

   
     var target=new EventTarget();
     target.addEventListener("abc",abcHandler);  // 给target 设置监听事件 
                                                    事件发生执行涵数
     target.addEventListener("cde",cdeHandler);

     var evt=new Event("cde"); // 设置事件
     target.dispatchEvent(evt); // 给target 抛发事件
     
 // 使用抛发事件流程
    var evt = new Event("aa");  // 设置事件
    
    注意对象e里面添加属性 用e.target 找不到
    evt.item = this.currentItem; // 往e里面添加属性 
    evt.data = this.data;       // 往e里面添加属性   
    this.dispatchEvent(evt);  // 抛发事件
}

        1、事件目标对象必须继承EventTarget  就是 所有的dom节点都可以绑定事件
        2、必须使用addEventListener侦听事件,侦听事件事件有两个参数,
            第一个是事件的类型,第二个是事件触发时执行的回调函数
        3、创建一个事件消息对象,并且这个消息对象中事件类型必须和侦听的事件类型一致
        4、针对事件目标对象抛发这个消息(事件)对象,这时候就会触发事件,
        并且执行事件侦听时写入的回调函数
        重要
        侦听必须在抛发之前
        侦听的对象必须和抛发的目标对象一致

冒泡与捕获

-        事件触发分为三个阶段
         1、捕获阶段
         2、目标阶段
         3、冒泡阶段
         默认状态下事件触发的顺序是按照冒泡阶段触发的
         捕获:从父级传递到子级
         冒泡:从子级传递到父级
          MouseEvent(和鼠标事件相关)系统属性 部分系统属性可以通过MouseEvent
            第二个参数带入的 (也就是改变一下属性 )
     var evt=newMouseEvent("click{clientX:129,clientY:199,button:1,bubbles:true});

          手动抛发事件默认不会触发冒泡
          var evt=new MouseEvent("click"); 
          如果需要冒泡,那么在事件的对象中写入bubbles:true,表示默认允许冒泡
          var evt = new MouseEvent("click", { bubbles: true })
          div3.dispatchEvent(evt);
    
    
     true就是捕获阶段,false是冒泡阶段
     div2.addEventListener("click",clickHandler2,true);
     
      e.stopPropagation();  停止向上冒泡或者停止捕获   在涵数中写
      e.preventDefault(); 在涵数中写  阻止默认行为  表单的提交、表单重置、
        图片的禁拖、文本选中
      e.returnValue=false; 也是阻止默认行为,是兼容写法
    
     once:true 只触发一次,然后就自动删除事件侦听
     capture:true 触发捕获
     触发一次捕获事件就移除
     div2.addEventListener("click",clickHandler2,{once:true,capture:true});
    
    
     this.iconList.addEventListener("mouseover", e => this.mouseHandler(e));
     设置鼠标事件  MouseEvent 与鼠标事件相关  { bubbles: true } 触发冒泡 
     当父级有监听事件,给他的子级增加事件,必须加冒泡,不然无法触发
    var evt = new MouseEvent("mouseover", { bubbles: true });
    this.iconList.dispatchEvent(evt);  抛发事件  给 this.iconList  抛发

e.target,e.currentTarget

     事件函数有且仅有一个参数e  这个参数e就是上面抛发事件evt对象 
     事件侦听的回调函数中,this被指向侦听事件的对象 就是div2.addEventListener的 div2
     this 和e.currentTarget都是侦听事件的对象
    当this指向已经不是侦听对象时,可以通过这个e.currentTarget获取
    
     e.target和e.srcElement是相同的,都是指被触发的目标对象
    ,也就是事件过程的目标阶段目标对象  
     e.target 谁触发事件就是谁 不一定是addEventListener 前面的 事件目标 
      也可能是它的子级节点 
     e.stopImmediatePropagation();在函数中写  阻止同一个事件绑定后续事件函数的执行,
                       就是在函数中写了这个除了这个函数,后面的函数不执行这一事件了
    
    
 
    因为子元素的事件可以冒泡给父元素,因此我们可以不侦听子元素事件,
    而侦听父元素事件,当子元素触发事件时
    冒泡给了父元素,这时候就是事件委托,
    可以用e.target获取目标触发的对象也就是子元素,e.currentTarget 是父元素
attachEvent (IE 7 8 下 使用)
  • 语法: 元素.attachEvent('事件类型', 事件处理函数)
oDiv.attachEvent("click", function () {
    console.log("我是第一个事件");
});
oDiv.attachEvent("click", function () {
    console.log("我是第二个事件");
});
  • 点击 div 时, 两个函数都会执行, 并且会按照你注册的顺序倒叙执行
  • 先打印 我是第二个事件, 然后打印 我是第一个事件
  • 注意: 事件类型需要要写 on, 点击事件就是 onclick
两个方式的区别
  • 注册事件的时候事件类型参数的书写
    • addEventListener: 需要写 on
    • attachEvent: 不需要写 on
  • 参数个数
    • addEventListener: 一般是三个常用参数
    • attachEvent: 两个参数
  • 执行顺序
    • addEventListener: 顺序注册, 顺序执行
    • attachEvent: 顺序注册, 倒叙执行
  • 适用浏览器
    • addEventListener: 非 IE 7 8 的浏览器
    • attachEvent: IE 7 8 浏览器

常见的事件 (了解)

  • 事件分类
    • 浏览器事件
    • 鼠标事件
    • 键盘事件
    • 表单事件
    • 触摸事件
浏览器事件
  • load: 页面全部资源加载完毕

  • error 错误事件

  • scroll: 浏览器滚动的时候触发

    window.addEventListener("scroll",scrollHandler);
    
    function scrollHandler(e){
        console.log(document.documentElement.scrollTop)
    }
    
  • resize 用于window窗口的大小改变触发事件

鼠标事件
  • click: 点击事件
  • dblclick: 双击事件
  • contextmenu: 右键事件
  • mousedown: 鼠标左键按下事件
  • mouseup: 鼠标左键抬起事件
  • mousemove: 鼠标移动
  • mouseover: 鼠标移入事件 移入子元素的时候也会触发事件
  • mouseout: 鼠标移出事件 移入子元素的时候也会触发事件
  • mouseenter: 鼠标移入事件 这个不会
  • mouseleave: 鼠标移出事件 这个不会
  • ...
键盘事件
  • keyup: 键盘抬起事件
  • keydown: 键盘按下事件
  • keypress: 键盘按下在抬起事件 对中文不行
  • ...
  • 注意键盘事件对div不起作用,用页面document做事件源
确定按键
  • 键盘的每一个按键都有一个自己的编码

  • 我们可以通过 事件对象.keyCode 或者 事件对象.which 来获取

       inp.onkeyup = function (e) {
                  // console.log(e.key)   编码就是键盘字母
                  console.log(e.which)   通过键盘事件获取字母的编号(数字)
                   console.log(e.keyCode) 通过键盘事件获取字母的编号(数字)
              }
     
    
表单事件
  • focus: 输入框获取焦点 就是点击输入框内部

  • blur: 输入框失去焦点 点击input之外的地方

  •       <form action="">
              <input type="text" name="user">
              <!-- 所有password都必须增加 autocomplete属性-->
              <input type="password" name="password" autocomplete>
              <button type="submit">提交</button>
          </form>
          <!-- <div contenteditable></div> -->
          <p contenteditable></p>
    
         /* 
           所有的表单元素和超链接还有带有contenteditable属性的元素都是可以聚焦
          //  focus和blur不能做事件委托给form表单,不会冒泡
           focus 聚焦
           blur 失焦
          // focusin和focusout可以做事件委托给form表单,会冒泡
           focusin 聚焦
           focusout 失焦
           console.log(e.relatedTarget);//触发这回的聚焦事件,
                                          可以打印上一个聚焦的元素节点
          */
    
  • change: 表单内容改变事件

    1. 就是 这次输入的与上次做对比,一但内容有变就做出反应
    2.  一般用于表单元素委托给表单(form标签),一旦表单元素的value发生修改则会触发
    
  • input: 表单内容输入事件 输一个字/字母/符号之类就反应一次

            /* 
                 input 当输入内容时,触发事件  input文本框、textArea文本域、
                 带有contenteditable属性元素
                input是可以做事件委托给form表单,冒泡
    
            */
    
  • submit和reset仅用于表单form

    submit 提交表单时
    reset 用于重置表单时
    提交表单或者重置表单时,不要侦听提交按钮或者重置按钮的点击事件,
    必须使用form侦听submit或者reset 下面的就是form
    

image.png

  • select 用于表单元素中input文本框或者textArea内容的文本选中事件

           var input=document.querySelector("input");
           input.addEventListener("select",selectHandler);
    
           function selectHandler(e){
               // 获取文本框中被选中内容的起始和结束下标
         console.log(input.selectionStart,input.selectionEnd)
         // 获取文本框中被选中内容
         console.log(input.value.slice(input.selectionStart,input.selectionEnd));
           }
    

图片与load error

    var img=new Image();
    等同于document.createElement("img");
     // 设全局变量n代表从储存那张图片开始
    var n=39;
    //设空数组储存图片
    var arr=[];
    //设置函数1储存图片
    function loadImage(n){
        //创建img标签
        var img=new Image();
        // 告诉img标签储存那张图片,运用img.src属性
        //填入n
        img.src="./img/img_"+n+".JPG";
        //给img设立加载完成事件,并每完成一次就删除一次
        img.addEventListener("load",loadHandler,{once:true});
    }
    //设置函数2结束储存图片
    function loadHandler(e){
        //给数组arr储存图片数据,e.taget表示传入图片
        arr.push(e.target);
        //给变量n递增
        n++;
        //判断n>43时结束运行代码,并调用函数3
        if(n>43){
            //所有的加载完成,图片没有44.jpg地址
            // arr.forEach(item=>{
            //     console.log(item.src)
            // })
            loadFinish();
            return
        }
        //n>43之前通过递归运行函数1,把不断增加的变量n传入
        loadImage(n);
    }
    //运行函数3,通过遍历数组方法在控制台打印数组的数据
    function loadFinish(){
        arr.forEach(item=>{
            console.log(item.src)
        })
    }
    //开始运行函数1并传参变量n
    loadImage(n);

鼠标滚轮事件 下面俩事件一般都写

    // 火狐浏览器的事件
    document.addEventListener("DOMMouseScroll",scrollHandler);
    // e.detail : 1

    // 火狐以外的浏览器的事件
    document.addEventListener("mousewheel",scrollHandler)
    /* 
    deltaX:-0
    deltaY:-5
    deltaZ:0
    detail:0
    wheelDelta:30
    wheelDeltaX:0
    wheelDeltaY:30
    
    */

    function scrollHandler(e){
        // console.log(e)
        var detail=0;
        if(e.detail){
            detail=e.detail
        }else{
            detail=e.deltaY/Math.abs(e.deltaY);
        }
        console.log(detail)
    }
触摸事件
  • touchstart: 触摸开始事件
  • touchend: 触摸结束事件
  • touchmove: 触摸移动事件
  • ...

事件对象

  • 什么是事件对象
    • 当触发一个事件以后, 对该事件的一些描述信息
    • 比如: 点击的位置坐标是什么, 触发键盘事件时按的那个按钮
  • 每一个事件都会有一个对象的对象来描述这些信息, 我们就把这个对象叫做 事件对象
  • 浏览器给了我们一个 黑盒子, 叫做 window.event, 就是对事件信息的所有描述
    • 比如点击事件, 我们可以通过 event 对象知道我们点击了那个位置
oDiv.onclick = function () {
    console.log(window.event.X轴坐标点信息);
    console.log(window.event.Y轴坐标点信息);
};
  • 但这东西有兼容性问题, 在低版本IE里很好用, 但是在高版本IE和Chrome 里不好使了
  • 所以我们需要换一个方式来获取, 就是在每一个事件处理函数的形参位置, 默认第一个就是 事件对象
oDiv.onclick = function (e) {
    console.log(e.X轴坐标点信息);
    console.log(e.Y轴坐标点信息);
};
  • 综上所述, 我们以后在每一个事件里, 都采用兼容写法
oDiv.onclick = function (e) {
    e = e || window.event;
    console.log(e.X轴坐标点信息);
    console.log(e.Y轴坐标点信息);
};

点击事件的光标点获取

  • 我们点击事件的坐标点都不是一堆, 所以要有一个相对的坐标系
  • 例如:
    • 相对于事件源(就是我们点击的那个元素)
    • 相对于页面
    • 相对于浏览器窗口
  • 因为这些都不一样, 所以我们获取的方式也不一样
相对于事件源
  • offsetX 和 offsetY
  • 相对于我们点击的元素的边框内开始计算
* {
	margin: 0;
	padding: 0;
}
div {
	width: 300px;
	height: 300px;
	padding: 20px;
	border: 10px solid #333;
	margin: 20px 0 0 30px;
}

<div></div>

var oDiv = document.querySelector('div')

// 注册点击事件
oDiv.onclick = function (e) {
	// 事件对象兼容写法
	e = e || window.event

	console.log(e.offsetX)
	console.log(e.offsetY)
}
相对于浏览器窗口你点击的坐标点
  • clientX 和 clientY 或 x,y
  • 相对于浏览器窗口(相对视口)来计算的, 不管你页面滚动到什么情况, 都是根据窗口(窗口大小一般不变)来计算坐标
* {
	margin: 0;
	padding: 0;
}
body {
	width: 2000px;
	height: 2000px;
}
div {
	width: 300px;
	height: 300px;
	padding: 20px;
	border: 10px solid #333;
	margin: 20px 0 0 30px;
}

<div></div>

var oDiv = document.querySelector('div')

// 注册点击事件
oDiv.onclick = function (e) {
	// 事件对象兼容写法
	e = e || window.event

	console.log(e.clientX)
	console.log(e.clientY)
}
相对于页面你点击的坐标点
  • pageX 和 pageY
  • 是相对于整个页面的坐标点, 不管有没有滚动, 都是相对于页面拿到的坐标点(有滚动,根据滚动距离来加减)
* {
	margin: 0;
	padding: 0;
}
body {
	width: 2000px;
	height: 2000px;
}
div {
	width: 300px;
	height: 300px;
	padding: 20px;
	border: 10px solid #333;
	margin: 20px 0 0 30px;
}

<div></div>

var oDiv = document.querySelector('div')

// 注册点击事件
oDiv.onclick = function (e) {
	// 事件对象兼容写法
	e = e || window.event

	console.log(e.pageX)
	console.log(e.pageY)
}

在父元素盒子中进行 拖拽

      getBoundingClientRect()
      获取元素相对视口的矩形范围
   /* 
     x left  相对视口的左边距
     y top   相对视口的顶边距
     width 元素的宽度 offsetWidth
     height 元素的高度 offsetHeight
     right  x+width 相对视口的左边距+宽度
     bottom   y+height 相对视口的顶边距+高度
    
    */
    
    
    
  标签  
   <div class="div2">
    <div class="div1"></div>
    <div class="div1"></div>
    <div class="div1"></div>
    <div class="div1"></div>
    <div class="div1"></div>
    <div class="div1"></div>
    <div class="div1"></div>
  </div>
    
    
 代码   
    //给页面设置鼠标按下事件
document.addEventListener("mousedown", mouseHandler);

function mouseHandler(e) {
// 判断事件是鼠标按下事件时运行代码
  if (e.type === "mousedown") {
  // 判断按的不是标签div1就跳出
    if (e.target.className !== "div1") return;
    // console.log(e.target); //被拖拽的div
    // this是 div1
    document.x = e.offsetX; // 鼠标点击事件源的的坐标
    document.y = e.offsetY; // document 相当于对象储存一下属性
    document.div = e.target;//储存你点的标签
    //设置鼠标移动事件
    document.addEventListener("mousemove", mouseHandler);
    //设置鼠标抬起事件
    document.addEventListener("mouseup", mouseHandler);
  // 判断鼠标移动事件触发时
  } else if (e.type === "mousemove") {
    // this 是document
    // parent 是div1的父元素
    var parent = document.div.parentElement;
   
    // rect是div1的父级元素div2的一个对象
    //可视窗口就是浏览器窗口也就是相对窗口
    var rect = parent.getBoundingClientRect();
    //e.clientX 相对视口也就是浏览器窗口的距离
    //document.x 也就是e.offsetX 鼠标点击在事件源上,事件源从左上角到点击处的距离
    //rect.x  就是 x left  相对视口的左边距 ,也是浏览器窗口到父元素盒子的左边距
   
    //他们相减得到是拖拽元素要赋值的具体坐标
    //拖拽元素外面有几个父元素就减几个相对视口边距,现在就一个就减一个rect.x
    var x = e.clientX - document.x - rect.x;
    var y = e.clientY - document.y - rect.y;
   
    if (x <= 0) x = 0;
    //  width 元素的宽度 offsetWidth 减去拖拽的盒子元素宽度,等于可移动的横坐标最大距离
    if (x >= rect.width - document.div.offsetWidth) x = rect.width - 
    document.div.offsetWidth;
    if (y <= 0) y = 0;
    if (y >= rect.height - document.div.offsetHeight) y = rect.height - 
    document.div.offsetHeight;
  //用style赋值,移动被拖拽的盒子
    document.div.style.left = x + "px";
    document.div.style.top = y + "px";
    //判断是鼠标抬起事件
  } else if (e.type == "mouseup") {
    // this 是document
    //删除函数
    document.removeEventListener("mousemove", mouseHandler);
    document.removeEventListener("mouseup", mouseHandler);
  }
}