事件

  • 注意点: 事件方法都是没有驼峰的
  • ==移动端和 PC 端各自有特有的事件==
  • css 的 pointerevents: none; 能使对应选择器选到的 dom 不响应不拦截事件 css 的 pointerevents: none; 能使对应选择器选到的 dom 不响应不拦截事件

移入, 移出, 移动 (移动端没有移入移出事件)

  • .onmouseover .onmouseenter
  • .onmouseout .onmouseleave
  • .onmousemove
  • 淦!居然没驼峰
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>13-JavaScript-移入移出事件</title><style>*{margin: 0;padding: 0;
        }div{width: 300px;height: 300px;background: red;
        }</style></head><body><div></div><script>let oDiv = document.querySelector("div");// 1.移入事件// oDiv.onmouseover = function () {//     console.log("移入事件");// }// 注意点: 对于初学者来说, 为了避免未知的一些BUG, 建议使用onmouseenteroDiv.onmouseenter = function () {console.log("移入事件");
    }// 2.移出事件// oDiv.onmouseout = function () {//     console.log("移出事件");// }// 注意点: 对于初学者来说, 为了避免未知的一些BUG, 建议使用onmouseleaveoDiv.onmouseleave = function () {console.log("移出事件");
    }3.移动事件
    oDiv.onmousemove = function () {console.log("移动事件");
    }</script></body></html>复制代码

表单焦点事件

  • .onfocus
  • .onblur
  • .onchange (只在失焦后才能拿到修改后的数据)
  • .oninput (实时获取到修改后的数据)
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>17-JavaScript-焦点事件</title></head><body><input type="text"><script>let oInput = document.querySelector("input");// 1.监听input获取焦点oInput.onfocus = function () {console.log("获取到了焦点");
    }// 2.监听input失去焦点oInput.onblur = function () {console.log("失去了焦点");
    }// 3.监听input内容改变// 注意点: onchange事件只有表单失去焦点的时候, 才能拿到修改之后的数据oInput.onchange = function () {console.log(this.value);
    }// oninput事件可以时时获取到用户修改之后的数据, 只要用户修改了数据就会调用(执行)// 注意点: oninput事件只有在IE9以上的浏览器才能使用// 在IE9以下, 如果想时时的获取到用户修改之后的数据, 可以通过onpropertychange事件来实现oInput.oninput = function () {console.log(this.value);
    }</script></body></html>复制代码

添加事件的三种方式

  1. element.onxxx
  2. element.attachEvent (上古, 了解即可)
  3. element.addEventListener (现代,可选事件冒泡 or 捕获)

方法一:onxxx

注意点:

  1. 由于是给属性赋值, 所以后赋值的会覆盖先赋值
  2. 缺点很明显: 不能通过一个事件触发多个方法, 不利于维持方法的细粒度
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>onclick</title></head><body><button id="btn">我是按钮</button><script>// 这点击事件只会输出 777, 原理就是给对象属性重赋值会对原有的值进行覆盖var oBtn = document.getElementById("btn");

    oBtn.onclick = function () {
        alert("666");
    }
    oBtn.onclick = function () {
        alert("777");
    }</script></body></html>复制代码

方法二:attachEvent

注意点:

  1. 事件名称必须加上on
  2. 后添加的不会覆盖先添加的
  3. 只支持低版本的浏览器
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>attachEvent</title></head><body><button id="btn">我是按钮</button><script>// 既输出 666 也输出 777,但现代浏览器已经摒弃了这个方法var oBtn = document.getElementById("btn");

    oBtn.attachEvent("onclick", function () {
        alert("666");
    });
    oBtn.attachEvent("onclick", function () {
        alert("777");
    });</script></body></html>复制代码

方法三:addEventListen

注意点:

  1. 事件名称不需要添加 on
  2. 后添加的不会覆盖先添加的
  3. 只支持现代浏览器(其实完全足够了)
  4. 这是三个里唯一可自定义事件是冒泡行为还是捕获行为的方法
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>addEventListener</title></head><body><button id="btn">我是按钮</button><script>// 既输出 666 也输出 777,现代浏览器通用这个方法var oBtn = document.getElementById("btn");

    oBtn.addEventListener("click", function () {
        alert("666");
    });
    oBtn.addEventListener("click", function () {
        alert("777");
    });</script></body></html>复制代码

强行兼容

看似考虑周全,实则没有必要

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>加个判断</title></head><body><button id="btn">我是按钮</button><script>var oBtn = document.getElementById("btn");function addEvent(ele, name, fn) {if(ele.attachEvent){
            ele.attachEvent("on"+name, fn);
        }else{
            ele.addEventListener(name, fn);
        }
    }</script></body></html>复制代码

事件对象

  • 事件对象就是一个系统自动创建的一个对象
  • 当注册的事件被触发的时候, 系统就会自动创建事件对象
  • 事件对象的属性海了去了

注意点:

  1. 在高级版本的浏览器中, 会自动将事件对象传递给回到函数
  2. 在低级版本的浏览器中, 不会自动将事件对象传递给回调函数, 需要通过 window.event 来获取事件对象

关于阻止默认行为:

  1. event.preventDefault(); 只支持现代浏览器
  2. event.returnValue = false; 只支持上古浏览器(了解即可, 这年头谁还用 IE8 啊)
  3. return false; 通吃
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>事件对象</title></head><body><button id="btn">我是按钮</button><a href="http://www.baidu.com">百度首页</a><script>
   var oBtn = document.getElementById("btn");
   oBtn.onclick = function (event) {       // 兼容性的写法   event = event || window.event;       // alert("666");   console.log(event);       console.log(typeof event);
   }   let oA = document.querySelector("a");
    oA.onclick = function (event) {// 兼容性的写法event = event || window.event;

        alert("666");// 阻止默认行为return false; // 企业开发推荐// event.preventDefault(); // 高级浏览器// event.returnValue = false; // IE9以下浏览器}</script></body></html>复制代码

事件执行的三个阶段

三个阶段

  1. 捕获阶段(从外向内的传递事件)
  2. 当前目标阶段
  3. 冒泡的阶段(从内向外的传递事件)

注意点:

  • 三个阶段只有两个会被同时执行
  • 要么捕获和当前, 要么当前和冒泡

为什么要么只能是捕获和当前, 要么只能是当前和冒泡?

这是JS处理事件的历史问题

早期各大浏览器厂商为争夺定义权, 以及对事件的理解不同, 产生了捕获和冒泡两种流向

后续W3C为了兼容, 将两种方式都纳入标准

冒泡还是捕获

如何设置事件到底是捕获还是冒泡?

通过addEventListener方法, 这个方法接收三个参数

  • 第一个参数: 事件的名称
  • 第二个参数: 回调函数
  • 第三个参数: ==false 冒泡== / ==true 捕获==

注意点:

  • onXxx的属性, 不接收任何参数, 所以默认就是冒泡
  • attachEvent方法, 只能接收两个参数, 所以默认就是冒泡
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>41-JavaScript-事件执行的三个阶段</title><style>*{margin: 0;padding: 0;
        }.father{width: 300px;height: 300px;background: red;
        }.son{width: 150px;height: 150px;background: blue;
        }</style></head><body><div class="father"><div class="son"></div></div><script>let oFDiv = document.querySelector(".father");let oSDiv = document.querySelector(".son");
    oFDiv.addEventListener("click", function () {console.log("father");
    }, false);
    oSDiv.addEventListener("click", function () {console.log("son");
    }, false);</script></body></html><!--
默认就是 false,也就是冒泡
设置为 true 的元素及其子元素链条都变为捕获,且仅影响自身及其子代,不影响其父元素
-->复制代码

关于冒泡的细节

IE6.0: div -> body -> html -> document

其他浏览器: div -> body -> html -> document -> window

注意: 不是所有的事件都能冒泡,有些事件不冒泡,如 blur、 focus、 load、 unload 等

阻止事件冒泡 (强行兼容)

首先要明确:阻止的前提是有事件,阻止事件冒泡的操作是写在实践方法的回调函数里的

  1. event.cancelBubble = true; (上古)
  2. event.stopProgagation(); (现代,知道这个才要紧)
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>43-JavaScript-阻止事件冒泡</title><style>*{margin: 0;padding: 0;
        }.father{width: 300px;height: 300px;background: red;
        }.son{width: 150px;height: 150px;background: blue;
        }</style></head><body><div class="father" id="father"><div class="son" id="son"></div></div><script>// 1.拿到需要操作的元素var oFDiv = document.getElementById("father");var oSDiv = document.getElementById("son");    // 2.注册事件监听oFDiv.onclick = function () {console.log("father");
    }
    oSDiv.onclick = function (event) {
        event = event || window.event;// event.stopPropagation(); // 高级浏览器// event.cancelBubble = true; // 低级浏览器if(event.cancelBubble){
            event.cancelBubble = true;
        }else{
            event.stopPropagation();
        }console.log("son");
    }</script></body></html>复制代码

不同移入移出事件辨析

区别在于是否触发冒泡(或捕获)

  1. onmouseover 和 onmouseenter 的区别
  • onmouseover 移入到子元素,父元素的移入事件也会被触发
  • onmouseenter 移入到子元素,父元素的移入事件不会被触发
onmouseout 和 onmouseleave 的区别
  • onmouseout 移出到子元素,父元素的移入事件也会被触发
  • onmouseleave 移出到子元素,父元素的移入事件不会被触发
简单来说, enter 和 leave 比较干净不拖泥带水
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>44-JavaScript-移入移出事件区别</title><style>*{margin: 0;padding: 0;
        }.father{width: 300px;height: 300px;background: red;
        }.son{width: 150px;height: 150px;background: blue;
        }</style></head><body><div class="father"><div class="son"></div></div><script>let oFDiv = document.querySelector(".father");let oSDiv = document.querySelector(".son");/*
    oFDiv.onmouseover = function () {
        console.log("father");
    }
    oSDiv.onmouseover = function () {
        console.log("son");
    }
     *//*
    oFDiv.onmouseenter = function () {
        console.log("father");
    }
    oSDiv.onmouseenter = function () {
        console.log("son");
    }
     */oFDiv.onmouseleave = function () {console.log("father");
    }
    oSDiv.onmouseleave = function () {console.log("son");
    }</script></body></html>复制代码

通过事件获取元素位置

  • offsetX/offsetY: 事件触发点相对于当前元素自身以左上为原点的位置
  • clientX/clientY: 事件触发相对于浏览器可视区域的位置(上古浏览器不支持)
  • 注意点:
    • 显示器区域不包括滚动出去的部分(这个开发中用的少)
  • screenX/screenY: 事件触发相对于屏幕的位置
  • 整个网页包括滚动出去的部分 pageX/pageY: 事件触发相对于整个网页的位置(在页面不滚动时拿到的值和 clientX/clientY 是一样的)

细节们

  • 调用事件方法时 return false 可以禁用默认事件, 或者用 event.preventDefault() 也行

  • 如果想获取 query 到的 input 标签对象中输入的内容, 只能通过其 value 属性

    html 可以给标签设置自定义标签属性, 可以给 JS 用,

    甚至可以通过 JS 给指定 DOM 添加自定义属性标签

  • 在 JS 中如果 HTML 标签的属性名称和取值名称一样的时候, JS 会返回 true/false 但如果是通过代码给 input 设置的数据, 那么不会触发 oninput 事件

  • 对上古浏览器的兼容只需了解即可

移动端事件

移动端特有事件对象

  1. Touch事件对象
  • 移动端的touch事件也是一个事件, 所以被触发的时候系统也会自动传递一个事件对象给我们
移动端touch事件对象中比较重要的三个子对象
  1. touches: 当前屏幕上所有手指的列表
  2. targetTouches: 保存了当前元素上所有的手指里列表 (这个用的多)
  3. changedTouches: 当前屏幕上刚刚接触的手指或者离开的手指

移动端点透问题

  1. 移动端点透问题
  • 当一个元素放覆盖了另一个元素, 覆盖的元素监听 ==touch== 事件,而下面的元素监听 ==click== 事件
  • 并且touch事件触发后覆盖的元素就消失了, 那么就会出现点透问题
移动端点透问题出现的原因
  1. 当手指触摸到屏幕的时候,系统生成两个事件,一个是touch 一个是click
  2. touch 事件先执行,执行完后从文档上消失
  3. click 事件有 100~300ms 延迟, 所以后执行. (理由不对嗷, 我加了 content="scalable=no" 也还能点透)
  4. 但 click 事件执行的时候触发的元素已经消失了, 对应的位置现在是下面的元素, 所以就触发了下面元素的 click    事件
移动端点透问题解决方案 在touch事件中添加event.preverDefault(); 阻止事件扩散
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>10-移动端点透问题</title><style>
			* {				margin: 0;				padding: 0;
			}			div {				text-align: center;				font-size: 40px;
			}			.click {				width: 300px;				height: 300px;				background: red;				position: absolute;				left: 50%;				transform: translateX(-50%);				top: 100px;
			}			.tap {				width: 200px;				height: 200px;				background: blue;				position: absolute;				left: 50%;				transform: translateX(-50%);				top: 150px;
			}		</style></head><body><div class="click">click</div><div class="tap">tap</div><!-- 两元素在同级, 但展现时两个块块有重叠 --><script>let oClick = document.querySelector(".click");			let oTap = document.querySelector(".tap");

			oTap.ontouchstart = function (event) {				this.style.display = "none";
				event.preventDefault(); //  阻止事件扩散
			};
			oClick.onclick = function () {				console.log("click");
			};		</script></body></html>复制代码