博客列表 >第六章 JS事件

第六章 JS事件

刘静的博客
刘静的博客原创
2020年08月22日 23:51:21967浏览

第六章 JS事件

事件流介绍

  1. js操作css: 脚本号的css,js与html交互通过事件完成
  2. 事件: 文档或浏览器窗口中发生一些特定的交互性瞬间
  3. 事件流(事件传播): 描述从页面中接受事件的顺序

[^IE事件流是事件冒泡流;Netscape事件流式事件捕获流]:

事件冒泡的概念

事件冒泡: 事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)

事件捕获的概念

  1. 事件捕获:有不太具体的节点更早的接收事件,而最具体的节点应该最后接收到事件

  2. 方法:addEventListener() 参数:类型,回调函数,默认false(冒泡阶段) 事件监听者

  3. 事件流:事件捕获阶段;处于目标阶段;事件冒泡阶段

    1. var box = document.getElementById('box');
    2. box.addEventListener('click',function(){
    3. box.innerHTML += 'box\n';
    4. },true)//捕获阶段
    5. document.body.addEventListener('click',function(){
    6. box.innerHTML += 'body\n';
    7. },true)//捕获阶段
    8. document.documentElement.addEventListener('click',function(){
    9. box.innerHTML += 'html\n';
    10. },true)//捕获阶段
    11. document.addEventListener('click',function(){
    12. box.innerHTML += 'document\n';
    13. },true)//捕获阶段
    14. window.addEventListener('click',function(){
    15. box.innerHTML += 'window\n';
    16. },true)//捕获阶段
    17. //冒泡阶段
    18. box.addEventListener('click',function(){
    19. box.innerHTML += 'box\n';
    20. },false)
    21. document.body.addEventListener('click',function(){
    22. box.innerHTML += 'body\n';
    23. },false)
    24. document.documentElement.addEventListener('click',function(){
    25. box.innerHTML += 'html\n';
    26. },false)
    27. document.addEventListener('click',function(){
    28. box.innerHTML += 'document\n';
    29. },false)
    30. window.addEventListener('click',function(){
    31. box.innerHTML += 'window\n';
    32. },false)

    得到的结果如下:

HTML事件处理程序

缺点: html+js无分离,后期不易维护

特别,注意不论在函数内还是函数外,this都是指向window对象

  1. console.log(this);//指向window对象
  2. function test(){
  3. // console.log(this); 指向window对象
  4. document.getElementById('box').innerHTML += '1';
  5. }

DOM_0级事件处理程序

优点:1.简单 2.跨浏览器

缺点:不能给同一个元素来绑定相同的事件处理程序,如果绑定了,会有覆盖现象

  1. var box = document.getElementById('box');
  2. box.onclick = function(){
  3. this.innerHTML += 1;
  4. }
  5. //删除事件处理程序
  6. box.onclick = null;
  7. // 垃圾回收机制
  8. //缺点:不能给同一个元素来绑定相同的事件处理程序,如果绑定了,会有覆盖现象
  9. box.onclick = function(){
  10. this.innerHTML += 2;
  11. }

DOM_2级事件处理程序

  1. addEventListener(事件名,处理程序的函数,布尔值)
  2. removeEventListener()
  3. 优点:没有事件覆盖现象

[^布尔值默认false是处于冒泡阶段,如果是true,是处于捕获阶段]:

IE8浏览器不支持DOM2处理程序

  1. //没有事件覆盖现象
  2. setTimeout(function(){
  3. box.addEventListener('click',function(){
  4. this.innerHTML += 1;
  5. },false);
  6. },10)
  7. // //监听函数传参,可以用匿名函数包装一个监听函数
  8. box.addEventListener('click',function(){
  9. //监听匿名函数
  10. test(2);
  11. },false);
  12. // box.addEventListener('click',test(3),false);
  13. function test(x){
  14. alert(x);
  15. }

无效的移除事件的方式

  1. //添加事件监听者
  2. box.addEventListener('click',function(){
  3. this.innerHTML += 1;
  4. },false);
  5. //移除事件
  6. box.removeEventListener('click',function(){
  7. this.innerHTML += 1;
  8. },false);

正确移除事件方式

  1. function handler(){
  2. this.innerHTML += 1;
  3. }
  4. box.addEventListener('click',handler,false);
  5. box.removeEventListener('click',handler,false);

IE事件处理程序

IE: attachEvent() detachEvent()

[^IE10以下浏览器可以使用 默认冒泡]:

  1. var box = document.getElementById('box');
  2. box.attachEvent('onclick',function (){
  3. this.innerHTML += '1';
  4. })

事件绑定兼容写法

1.DOM2级事件处理程序 addEventListener() IE8不支持, ie attachEvent()

[^IE8浏览器不支持DOM2处理程序]:

2.attachEvent()内部的this指向了window,我们要对this的指向也做兼容

ie8的写法如下:

  1. var btn = document.getElementById('btn');
  2. function handler(){
  3. console.log(this.innerHTML);
  4. }
  5. btn.attachEvent('onclick',function(){
  6. handler.call(btn);//将方法绑定到对象上,这时候this指向btn对象
  7. })
  8. btn.addEventListener('click',fn,false); 默认为false,冒泡 this指向当前btn对象
  9. btn.attachEvent('onclick',fn) this指向window

全浏览器事件处理程序的兼容性代码:

  1. addEvent(btn,'click',function(){
  2. console.log(this.innerHTML);
  3. })
  4. function addEvent(target,eventType,handler){
  5. if(target.addEventListener){
  6. //chrome ff safari都可以
  7. target.addEventListener(eventType,handler,false);//事件冒泡
  8. }else{
  9. target.attachEvent('on' + eventType,function(){
  10. handler.call(target);//将方法绑定到对象上,这时候this指向对象
  11. });
  12. }
  13. }

call方法可以改变this指向问题

  1. console.log(this);//chrome ff 指向window对象
  2. var obj = {
  3. innerHTML : 'liujing'
  4. }
  5. function fn(){
  6. console.log(this.innerHTML);
  7. }
  8. //call方法可以改变this指向问题
  9. fn.call(obj);//chrome ff this指向obj对象
  10. fn.call();//chrome ff 指向window对象

事件调用顺序总结

  1. 相同点:如果同时出现HTML事件处理程序和DOM0级事件处理程序,DOM0级会覆盖HTML事件处理程序

  2. 不同点:

    2.1 chrome,safari,FF浏览器以及IE11结果: DOM0级 DOM2级
    2.2 IE9、10结果为:DOM0级 DOM2级 IE
    2.3 ie8结果: DOM0级 IE

DOM0级事件处理程序

  1. box.onclick = function(){
  2. this.innerHTML += 'DOM0级\n';
  3. }

DOM2级事件处理程序

  1. if(box.addEventListener){
  2. box.addEventListener('click',function(){
  3. this.innerHTML += 'DOM2级\n';
  4. })
  5. }

IE级事件处理程序

  1. if(box.attachEvent){
  2. box.attachEvent('onclick',function(){
  3. box.innerHTML += 'IE\n';
  4. })
  5. }

如何获取事件对象

1.如何获取事件对象
2.事件目标
3.事件代理
4.事件冒泡
5.事件流阶段 eventPhase
6.取消默认事件 //javascript:void(0);

  1. // 兼容性
  2. window.onload = function() {
  3. var box = document.getElementById('box');
  4. // 1.event对象是事件处理程序的第一个参数 ie8浏览器不兼容
  5. // ie8浏览器得到的结果是undefined,其它浏览器[object MouseEvent]
  6. box.onclick = function (e){
  7. console.log(e);
  8. this.innerHTML = e;
  9. }
  10. // 2.直接可以使用event变量 火狐浏览器低版本获取出来的是undefined
  11. box.onclick = function() {
  12. this.innerHTML = event;
  13. }
  14. // 兼容性代码
  15. box.onclick = function(e){
  16. console.log(e);
  17. // 兼容性写法
  18. e = e || window.event;//[object MouseEvent]
  19. box.innerHTML = e; //[object Event]
  20. }
  21. }

事件目标

1.currentTarget属性:返回事件当前所在的节点,正在执行的监听函数所绑定的节点

[^target和srcElement功能一样]:

  1. box.onclick = function (e){
  2. e = e || window.event;
  3. // console.log(e);//MouseEvent对象中的cancelBubble,cancelable;clientX;clientY属性
  4. //e,currentTarget 值是null //ie8低版本
  5. //e.srcElement值是li.item
  6. console.log(e.currentTarget);//整个ul对象
  7. var items = document.getElementsByTagName('li');
  8. items[0].innerHTML = e.currentTarget;//[object HTMLListElement]
  9. }
  10. //监听的是li的父级节点ul

2.target属性:返回的是事件的实际目标对象

[^注意:target属性 ie8不支持]:

  1. box.onclick = function (e){
  2. e = e || window.event;
  3. console.log(e.target);//<li class="item">1</li>
  4. console.log(e.target===this);//false
  5. // this对象跟e.currentTarget属性是一致的
  6. console.log(e.currentTarget===this);//true
  7. }

3.srcElement跟target功能是一致的,FF低版本的浏览器不支持

  1. box.onclick = function(e) {
  2. e = e || window.event;
  3. // console.log(e.srcElement);//<li class="item">1</li>
  4. var target = e.target || e.srcElement;
  5. target.style.backgroundColor = 'red';
  6. }
  7. box.onmouseout = function(e) {
  8. e = e || window.event;
  9. var target = e.target || e.srcElement;
  10. target.style.backgroundColor = 'lightblue';
  11. }

事件代理

css代码如下:

  1. <style type="text/css">
  2. * {
  3. padding: 0;
  4. margin: 0;
  5. }
  6. ul {
  7. list-style: none;
  8. overflow: hidden;
  9. margin-top: 80px;
  10. }
  11. ul li {
  12. float: left;
  13. width: 100px;
  14. height: 30px;
  15. text-align: center;
  16. line-height: 30px;
  17. color: #fff;
  18. background-color: #000;
  19. margin: 0 10px;
  20. }
  21. </style>

html代码:

  1. <ul id="box">
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. <li>5</li>
  7. </ul>

javascript代码:

  1. window.onload = function() {
  2. // 常规方法实现
  3. // 1.获取标签
  4. var lis = document.getElementsByTagName('li');
  5. for(var i = 0; i < lis.length; i++){
  6. lis[i].onmouseover = function (){
  7. this.style.backgroundColor = 'blue';
  8. }
  9. lis[i].onmouseout = function (){
  10. this.style.backgroundColor = 'black';
  11. }
  12. }
  13. // 事件代理的方式实现 事件实际目标对象来实现
  14. // 事件代理应用: 事件实际目标对象target和srcElement属性完成
  15. // 优点: 提高性能以及降低代码的复杂度
  16. //ul 也被触发了
  17. var box = document.getElementById('box');
  18. box.onmouseover = function(e) {
  19. e = e || window.event;
  20. var target = e.target || e.srcElement;
  21. target.style.backgroundColor = 'blue';
  22. }
  23. box.onmouseout = function(e) {
  24. e = e || window.event;
  25. var target = e.target || e.srcElement;
  26. target.style.backgroundColor = 'black';
  27. }
  28. }

[^ul 也被触发了]:

事件代理的应用

  1. //模拟未来的某个事件来添加对应的数据
  2. var box = document.getElementById('box');
  3. setTimeout(function(){
  4. var item = document.createElement('li');
  5. item.innerHTML = '6';
  6. box.appendChild(item);
  7. },100);

target本身就会因为事件捕获而指向具体的节点

  1. // target本身就会因为事件捕获而指向具体的节点
  2. var box = document.getElementById('box');
  3. // 给未来的元素绑定事件,使用事件代理
  4. box.onmouseover = function (e){
  5. e = e || window.event;
  6. var target = e.target || e.srcElement;
  7. target.style.backgroundColor = 'blue';
  8. }
  9. box.onmouseout = function (e){
  10. e = e || window.event;
  11. var target = e.target || e.srcElement;
  12. target.style.backgroundColor = 'black';
  13. }

事件冒泡的用法

属性: bubbles; cancelBubble

方法:stopPropagation() ;stopImmediatePropagation()

1.bubbles 返回一个布尔值 表示当前事件是否会冒泡,只读 true:冒泡;false:非冒泡

[^大部分事件都会冒泡,但是focus blur scroll事件不会冒泡]:

  1. var btn = document.getElementById('btn');
  2. var test = document.getElementById('test');
  3. btn.onclick = function(e) {
  4. e = e || window.event;
  5. console.log(e.bubbles);//true
  6. }
  7. test.onfocus = function (e){
  8. e = e || window.event;
  9. console.log(e.bubbles);//false
  10. }

2.stopPropagation()表示取消事件的进一步冒泡 无返回值,但是无法阻止同一事件的其它监听函数被调用

[^ie8浏览器不支持]:

  1. btn.onclick = function(e){
  2. e = e || window.event;
  3. //阻止冒泡
  4. e.stopPropagation();
  5. this.innerHTML = '阻止冒泡';
  6. }
  7. document.body.onclick = function(e){
  8. e = e || window.event;
  9. console.log('body');
  10. }
  11. btn.addEventListener('click',function(e){
  12. e = e || window.event;
  13. e.stopPropagation();
  14. this.innerHTML = '修改了';
  15. },false);
  16. btn.addEventListener('click',function(e){
  17. e = e || window.event;
  18. this.style.backgroundColor = 'blue';//上面没有阻止这个操作
  19. },false);
  20. document.body.onclick = function (e){
  21. e = e || window.event;
  22. console.log('body');//阻止这个操作
  23. }

3.stopImmediatePropagation()既可以阻止冒泡,也可以阻止同一事件的其它监听函数被调用

  1. btn.addEventListener('click', function(e) {
  2. e = e || window.event;
  3. e.stopImmediatePropagation();
  4. this.innerHTML = '修改了';
  5. }, false);
  6. btn.addEventListener('click', function(e) {
  7. e = e || window.event;
  8. this.style.backgroundColor = 'blue';
  9. }, false);
  10. document.body.onclick = function(e) {
  11. e = e || window.event;
  12. console.log('body');
  13. }

4.cancelBubble 属性用于阻止冒泡 可读写 默认值为false,当设置为true,cancelBubble可以取消事件冒泡

  1. btn.onclick = function(e) {
  2. e = e || window.event;
  3. if(e.stopPropagation){
  4. e.stopPropagation();
  5. }else{
  6. e.cancelBubble = true;//全局浏览器支持
  7. }
  8. this.innerHTML = '修改了';
  9. }
  10. document.body.onclick = function(e) {
  11. e = e || window.event;
  12. console.log('body');
  13. }

兼容stopPropagation() stopImmediatePropagation()ie8不支持

[^e.cancelBubble = true;全浏览器都支持 不是标准写法]:

  1. var handler = function (e){
  2. e = e || window.event;
  3. if(e.stopPropagation){
  4. e.stopPropagation();
  5. }else{
  6. e.cancelBubble = ture;
  7. }
  8. }

事件流阶段属性

e.eventPhase 0 表示事件没有发生 1 表示捕获阶段 2目标阶段 3冒泡阶段

  1. var btn = document.getElementById('btn');
  2. // 2 目标阶段
  3. btn.onclick = function (e){
  4. e = e || window.event;
  5. this.innerHTML = e.eventPhase + '阶段';
  6. console.log(e.eventPhase);
  7. }
  1. // 1 捕获阶段
  2. document.body.addEventListener('click',function (e){
  3. e = e || window.event;
  4. console.log(e.eventPhase);
  5. },true);
  1. // 3 冒泡阶段
  2. document.body.addEventListener('click',function (e){
  3. e = e || window.event;
  4. console.log(e.eventPhase);
  5. },false);

取消默认事件

事件对象中两个方法 阻止默认事件: 方法:preventDefault() 属性:returnValue兼容ie8以下浏览器 return fasle

  1. var apeland = document.getElementById('apeland');
  2. // 1.preventDefault() ie8不支持
  3. apeland.onclick = function (e){
  4. e = e || window.event;
  5. // 阻止冒泡
  6. // e.stopPropagation();
  7. // 阻止默认事件 ie8以下不支持
  8. // e.preventDefault();
  9. // 阻止默认事件 FF ie8以上不支持 ie9不支持
  10. // e.returnValue = false;
  11. // 兼容性写法
  12. if(e.preventDefault){
  13. e.preventDefault();
  14. }else{
  15. //兼容IE8以下的浏览器
  16. e.returnValue = false;
  17. }
  18. // 阻止默认事件
  19. return false;
  20. }

事件对象中的坐标位置

事件对象中提供了:clientX/Y,x/y,offsetX/Y,screenX/Y,pageX/pageY

clientX/Y和x/y: 相对于浏览器(浏览器的有效区域)的X轴和Y轴的距离

  1. this.innerHTML = `clientX:${e.clientX};clientY:${e.clientY};X:${e.x};Y:${e.y}`;
  2. //clientX:8;clientY:8;X:8;Y:8

screenX/Y:相对于显示器屏幕的X轴和Y轴的距离

  1. this.innerHTML = `screenX:${e.screenX};screenY:${e.screenY};`;
  2. //screenX:8;screenY:110;

pageX/Y: 相对于页面的X轴和Y轴的距离 滚动和clientY不同

  1. this.innerHTML = `pageX:${e.pageX};pageY:${e.pageY};`;
  2. //pageX:8;pageY:1316;

offsetX/Y:相对于事件源的X轴和Y轴的距离

  1. this.innerHTML = `offsetX:${e.offsetX};offsetY:${e.offsetY};`;
  2. //offsetX:0;offsetY:0;

事件总结

事件
1.事件流
描述的是从页面接收事件的顺序
IE事件流是事件冒泡流,Netscape的事件流是事件捕获流
2.事件流阶段
(1)事件捕获阶段 (2)处于目标阶段 (3)事件冒泡阶段
事件捕获阶段:从最不具体的节点(window/document)接收事件 往具体的节点进行传播
事件冒泡阶段:从具体的节点开始接收事件,逐级往上传递到最不具体的节点。
3.事件对象
3.1 e.eventPhase 描述事件发生的阶段
事件捕获阶段 1
处于目标阶段 2
事件冒泡阶段 3
3.2 事件目标
e.currentTarget === this

​ e.target
​ e.srcElement(FF浏览器兼容)

​ //兼容性代码

  1. var target = e.target || e.srcElement;

​ 3.3 事件代理 也叫事件委托
​ 3.4 取消默认行为

  1. e.preventDefault();//ie8不兼容
  2. e.returnValue = false;//兼容
  3. return false;

​ 3.5 事件冒泡

  1. e.bubbles
  2. blur focus scroll三个事件返回值为false
  3. e.stopPropagation(); //常用
  4. e.stopImmediatePropagation();
  5. e.cancelBubble = true;
  6. var handler = function(e){
  7. e = e || window.event;
  8. if(e.stopPropagation){
  9. e.stopPropagation();
  10. }else{
  11. e.cancelBubble = true;
  12. }
  13. }

​ 4.事件处理程序

​ 1) HTML事件处理程序
​ 2) DOM0级事件处理程序

  1. btn.onclick = function(e){
  2. e = e || window.event;
  3. }
  4. //有事件覆盖现象
  5. btn.onclick = function(e){
  6. e = e || window.event;
  7. }

​ 3) DOM2级事件处理程序

  1. btn.addEventListener('click',function (){
  2. },false);
  3. btn.addEventListener('click',function (){
  4. },false);
  5. var handler = function(){
  6. ....
  7. }
  8. btn.addEventListener('click',handler,false);
  9. btn.removeEventListener('click',handler)

​ 4) IE事件处理程序

  1. btn.attachEvent('onclick',function(){
  2. //在ie中小心this 这个this指向了window
  3. })
  4. btn.detachEvent('onclick',function(){
  5. })
  6. 处理this的指向问题,函数中的call(target);
  1. 事件对象中的属性 坐标位置
    5.1 clientX/Y x/y
    1. 相对于当前的浏览器(有效的浏览器区域)的x轴和y轴的距离,与滚动条无关
    5.2 screenX/Y
    1. 相对于显示器屏幕的x轴和y轴的距离
    5.3 pageX/Y
    1. 相对于页面的x轴和y轴的距离,如果有滚动条,包含整个页面,与滚动条有关
    5.4 offsetX/Y
    1. 相对于事件源x轴和y轴的距离

放大镜效果结构样式搭建

css代码

  1. <style type="text/css">
  2. *{margin:0px;padding:0px;}
  3. #box{width:430px;height:430px;border:1px solid #DDD;position:relative;margin:50px;}
  4. #small_box{width:430px;height:430px;position:relative;}
  5. #small_box #mask{position:absolute;width:210px;height:210px;background:url(images/dotted.png) repeat;top:0px;left:0px;display:none;}
  6. #big_box{position:absolute;left:440px;top:0px;width:430px;height:430px;border:1px solid #ddd;overflow:hidden;display:none;}
  7. #big_box img{position:absolute;z-index:5;}
  8. </style>

html代码

  1. <div id="box">
  2. <div id="small_box">
  3. <img src="images/photo.jpg">
  4. <span id="mask"></span>
  5. </div>
  6. <div id="big_box">
  7. <img src="images/photo01.jpg">
  8. </div>
  9. </div>

javascript代码

  1. window.onload = function(){
  2. //1.获取需要的标签
  3. var box = document.getElementById('box');
  4. var small_box = box.children[0];
  5. var big_box = box.children[1];
  6. var small_img = small_box.children[0];
  7. var mask = small_box.children[1];
  8. var big_img = big_box.children[0];
  9. //2.监听鼠标移动
  10. small_box.onmouseover = function(){
  11. //2.1让遮罩层和大盒子显示出来
  12. mask.style.display = 'block';
  13. big_box.style.display = 'block';
  14. //2.2监听鼠标移动
  15. small_box.onmousemove = function(e){
  16. e = e || window.event;
  17. //2.3求出小盒子移动的水平和垂直的距离
  18. var moveX = e.clientX - small_box.offsetLeft - box.offsetLeft - mask.offsetWidth*0.5;
  19. //small_box.offsetLeft 为0
  20. var moveY = e.clientY - small_box.offsetTop - box.offsetTop - mask.offsetHeight*0.5;
  21. //2.4移动边界处理
  22. if(moveX < 0){
  23. moveX = 0;
  24. }else if(moveX >= small_box.offsetWidth - mask.offsetWidth){
  25. moveX = small_box.offsetWidth - mask.offsetWidth;
  26. }
  27. if(moveY < 0){
  28. moveY = 0;
  29. }else if(moveY >= small_box.offsetWidth - mask.offsetWidth){
  30. moveY = small_box.offsetHeight - mask.offsetHeight;
  31. }
  32. //2.5让小盒子移动起来
  33. mask.style.left = moveX + 'px';
  34. mask.style.top = moveY + 'px';
  35. //2.6大图移动起来
  36. //公式:moveX/大图移动的距离 = (small_box宽度-mask宽度)/(big_img宽度-big_box宽度);
  37. // var x = moveX / (small_box.offsetWidth - mask.offsetWidth);
  38. // var y = moveY / (big_img.offsetWidth - big_box.offsetWidth);
  39. var scale = (big_img.offsetWidth - big_box.offsetWidth)/(small_box.offsetWidth - mask.offsetWidth);
  40. // console.log(small_box.offsetWidth);//430
  41. // console.log(mask.offsetWidth);//210
  42. // console.log(big_img.offsetWidth);//800
  43. // console.log(big_box.offsetWidth);//432
  44. // big_img.style.left = - x * (big_img.offsetWidth - big_box.offsetWidth) +'px';
  45. // big_img.style.top = - y * (big_img.offsetHeight - big_box.offsetHeight) +'px';
  46. big_img.style.left = - moveX * scale +'px';
  47. big_img.style.top = - moveY * scale +'px';
  48. // var lw = mask.offsetLeft;
  49. // var lh = mask.offsetTop;
  50. // var rate = big_img.offsetWidth/big_box.offsetWidth;
  51. // // var rate = small_box.offsetWidth/mask.offsetWidth;
  52. // var newX = lw * 1.68;
  53. // var newY = lh * 1.68;
  54. // big_img.style.left = -newX +'px';
  55. // big_img.style.top = -newY +'px';
  56. }
  57. }
  58. small_box.onmouseout = function(e){
  59. mask.style.display = 'none';
  60. big_box.style.display = 'none';
  61. }
  62. }
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议