day15 事件对象
1.回顾
2.==懒加载==
-
懒加载的应用场景:在一些电商类平台网站上 由于页面要加载的数据量较庞大,因此如果直接将页面所有内容都加载出来,会导致页面的加载时间过长,导致页面白屏。
因此,开发者们想出了懒加载的办法——只加载用户看得见的部分,看不见的部分不加载。这样单次加载的内容就相对较少,加载时间减短,从而提升用户体验。
-
懒加载实现思路:
-
第一步:先渲染图片结构,把图片资源先暂时给img的src1属性
-
第二步:显示第一屏效果,只要图片的位置小于窗口可视高度就显示出来
-
只加载可视区域内的照片
-
窗口的可视高度 document.documentElement.clientHeight
-
图片在页面中的位置 图片.offsetTop
-
默认情况所有的图片都不显示 先将图片路径给自定义属性src1 如果要显示该图片将src1给src
-
-
第三步:当滚动滚动的时候,再次判断图片是否在可视范围内容
-
判断范围:页面的可视高度+页面卷起的高度 document.documentElement.scrollTop + document.documentElement.clientHeight
-
-
<body> <ul></ul> <script> // 1.通过for循环渲染结构 var oUl = document.getElementsByTagName("ul")[0]; var str = ""; for (var i = 0; i < arr.length; i++) { str += `<li><img src1="${arr[i]}" alt=""></li>` } // console.log(str); oUl.innerHTML = str; // 2.显示第一屏效果 /* 只加载可视区域内的照片 窗口的可视高度 document.documentElement.clientHeight 图片在页面中的位置 图片.offsetTop 默认情况所有的图片都不显示 先将图片路径给自定义属性src1 如果要显示该图片将src1给src */ var oImg = document.getElementsByTagName("img"); for (var i = 0; i < oImg.length; i++) { // console.log(oImg[i].offsetTop); if (oImg[i].offsetTop <= document.documentElement.clientHeight) { console.log("第" + i + "张图片"); oImg[i].src = oImg[i].getAttribute("src1"); } } // 2.页面滚动 显示可视范围内容的数据 window.onscroll = function () { var sT = document.documentElement.scrollTop + document.documentElement.clientHeight // 将所有的图片再判断一次 for (var i = 0; i < oImg.length; i++) { if (oImg[i].offsetTop <= sT) { console.log("第" + i + "张图片"); oImg[i].src = oImg[i].getAttribute("src1"); } } } </script> </body>
3.==事件对象==
3.1事件对象
-
事件对象:每一个事件都会有一个对象,这个对象用来记录和该事件有关的一些信息
-
如何获取事件对象
-
标准浏览器和IE浏览器:window.event
-
低版本火狐浏览器:火狐低版本浏览器 在事件处理函数中的第一个参数就是事件对象
-
-
兼容事件对象
-
window.event || 第一个参数
-
<body> <div></div> <script> var oDiv = document.getElementsByTagName("div")[0]; oDiv.onclick = function (eve) { console.log(window.event);//标准浏览器和IE浏览器 // 火狐低版本浏览器 在事件处理函数中的第一个参数就是事件对象 console.log(eve); // 兼容事件对象 window.event || 第一个参数 var ev = window.event || eve; console.log(ev); } </script> </body>
-
事件对象中的属性
-
altKey/shiftKey/ctrlKey:表示在执行事件的时候,是否同时按住alt shift ctrl键,执行的时候按住是返回true,否则返回false
-
clientX/clientY:表示鼠标都可视窗口左侧和上侧的距离
-
pageX/pageY:表示鼠标位置到页面左侧和上侧的距离,==存在IE兼容问题==
-
pageX = clientX + 页面卷起的宽度
-
pageY = clientY + 页面卷起的高度
-
在IE低版本去获取pageX和pageY,因为在IE版本没有办法获取Pagex和pageY,所以我们可以用卷起的高度+clientx
-
-
target:目标源/事件源,事件触发事件的元素,==存在IE兼容问题==
-
标准浏览器:事件对象.target
-
IE低版本:事件对象.srcElement
-
-
type:添加事件的类型,没有on
-
3.2事件绑定
3.2.1之前绑定事件
-
语法:标签.事件类型 = function(){}
-
==缺点:同种事件类型一次只能绑定一个,后者会覆盖前者==
<button>按钮1</button> <script> // 1.之间的方式绑定事件 var btn = document.getElementsByTagName("button")[0]; // 标签.事件类型 = function(){} 缺点:只能绑定一个事件 // 程序员1 btn.onclick = function () { console.log("按钮1") } // 程序员2 btn.onclick = function () { console.log("按钮2") } </script>
3.2.2事件绑定
基础语法
-
标准浏览器:标签.addEventListener(事件类型(不加on),事件处理函数,事件捕获)
-
IE低版本浏览器:标签.attachEvent(事件类型(加on),事件处理函数)
//标准浏览器 btn.addEventListener("click", function () { console.log("按钮1") }) btn.addEventListener("click", function () { console.log("按钮2") }) // IE低版本 btn.attachEvent("onclick", function () { console.log("按钮3") }) btn.attachEvent("onclick", function () { console.log("按钮4") })
==两者区别==
-
==面试题:addEventListener和attachEvent事件绑定有什么区别?==
-
addEventListener 事件类型不加on,有事件捕获,执行顺序从前往后执行
-
attachEvent 事件类型加on 没有事件捕获 执行顺序从后往前执行
-
浏览器兼容
-
事件绑定浏览器兼容 if(判断某个方法是否存在){}else{}
// 事件绑定兼容 方法兼容 window.getComputedStyle() if (btn.addEventListener) {//标准浏览器 console.log("标准浏览器"); btn.addEventListener("click", function () { console.log("按钮1"); }) } else {//IE低版本浏览器 console.log("IE低版本"); btn.attachEvent("onclick", function () { console.log("按钮1") }) }
==事件绑定函数封装==
function bind(elem, type, fun) { //elem:绑定事件的标签 type:事件类型 fun:事件处理函数 if (elem.addEventListener) {//标准浏览器 console.log("标准浏览器"); elem.addEventListener(type, fun) } else {//IE低版本浏览器 console.log("IE低版本"); elem.attachEvent("on" + type, fun) } } //调用 bind(btn, "click", function () { console.log("按钮1") }) bind(btn, "click", function () { console.log("按钮2") })
3.3事件取消
3.3.1之间的事件取消
-
标签.事件类型 = null
// 之间的事件绑定 btn.onclick = function () { console.log("按钮1"); // 执行一次之后 解除事件 标签.事件类型 = null btn.onclick = null; }
3.3.2事件取消
基础语法
-
标准浏览器:标签.removeEventListener(事件类型(不加on),事件处理函数,是否捕获)
-
IE低版本:标签.detachEvent(事件类型(加on),事件处理函数)
// 标准浏览器 事件取消 btn.removeEventListener("click", fun1) // IE低版本 事件取消 btn.detachEvent("onclick", fun1)
浏览器兼容
// 浏览器兼容 事件取消 if (btn.removeEventListener) { btn.removeEventListener("click", fun1) } else { btn.detachEvent("onclick", fun1); }
事件取消函数封装
//事件取消 function unbind(elem, type, fun) { if (elem.removeEventListener) { elem.removeEventListener(type, fun) } else { elem.detachEvent("on" + type, fun); } }
3.4事件流
-
事件流:当事件发生的时候,事件在字符节点之间的固定传递顺序
-
捕获型事件(标准) 冒泡性事件
-
事件流会经历三个阶段
-
捕获阶段:当事件发生的时候 事件从window开始往子元素传递
-
确定目标:确定真正触发事件的元素
-
冒泡阶段:目标源接受到事件之后开始处理事件,处理完成之后,会将事件从当前往父节点传递 直到window
-
<body> <div class="box1"> box1盒子 <div class="box2"> box2盒子 <div class="box3">box3盒子</div> </div> </div> <script> // 1.绑定事件 addEventListener(事件类型,事件处理函数,是否事件捕获) true事件捕获 false事件冒泡 默认是false var oDiv = document.getElementsByTagName("div"); oDiv[0].addEventListener("click", function () { console.log("box1") }) oDiv[1].addEventListener("click", function () { console.log("box2") }) oDiv[2].addEventListener("click", function () { console.log("box3") }) </script> </body>
3.5阻止事件冒泡
-
标准浏览器 事件对象.stopPropagation()
-
IE低版本 事件对象.cancelBubble = true
-
阻止事件冒泡兼容
-
ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true
-
<body> <button>按钮1</button> <script> document.documentElement.onclick = function () { console.log("这是全局window的事件") } var btn = document.getElementsByTagName("button")[0]; btn.onclick = function (eve) { console.log("按钮1"); // 阻止冒泡 // 标准浏览器 事件对象.stopPropagation() var ev = window.event || eve;//事件对象 // ev.stopPropagation(); // IE低版本 事件对象.cancelBubble = true // ev.cancelBubble = true // 阻止事件冒泡兼容 ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true } </script>
3.6阻止默认行为
有很多标签都是有默认行为的,例如:a标签的跳转、右键菜单、图片拖拽保存等等
-
return false; ==只适用用绑定方式是:标签.事件类型=function(){}==
-
标准浏览器:事件对象.preventDefault()
-
IE低版本:事件对象.returnValue = false;
-
阻止事件默认行为兼容
-
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
-
<body> <a href="">跳转</a> <script> var oA = document.getElementsByTagName("a")[0]; oA.onclick = function (eve) { console.log(1); return false;//阻止默认行为,但是只适用于绑定方式是标签.事件类型这种方法 // 标准浏览器:事件对象.preventDefault() var ev = window.event || eve; ev.preventDefault(); // IE低版本:事件对象.returnValue = false; ev.returnValue = false; // 阻止默认行为兼容 ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; } oA.addEventListener("click", function (eve) { //return false 没有效果 var ev = window.event || eve; console.log(2); ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; }) </script> </body>
3.7事件委托
-
在我们需要添加大量事件的时候,为了节省性能,我们一般会用到事件委托(事件代理)
-
实现场景:我们现在有10000个li标签,要给给每个li标签都添加点击事件,如果用for循环添加 需要执行的时间比较长,会浪费计算机性能 此时我们推荐用事件委托
-
事件委托实现的思路
-
给所有要添加事件元素的父元素添加事件
-
在父元素执行的时候,找到目标源执行操作
-
// 事件委托:给li添加点击事件 点谁就改变谁的背景色 // 1.找添加事件元素的共同父元素,将事件添加给共同父元素 var oul = document.getElementsByTagName("ul")[0]; oul.onclick = function (eve) { // 2.找目标源 真正触发事件的元素 事件对象.target || 事件对象.srcElement var ev = window.event || eve;//事件对象 var target = ev.target || ev.srcElement; console.log(target) // 3.判目标源是不是真正要添加事件的元素 nodeName 节点的名称 if (target.nodeName == "LI") { //4.执行操作 target.style.backgroundColor = "red"; } }