懒加载,事件对象
1.懒加载
2.懒加载
-
懒加载的应用场景
- 在各大电商平台的网站上,由于页面需要记载很多很多图片,如果直接网页上的所有的图片都加载出来,数据比较庞大,会导致页面加载过长,页面会出现白屏效果,对用户体验不友好
-
懒加载的实现思路
- 在页面加载的时候 判断哪些内容是在用户的可视区域,只加载用户可视范围的内容,看不见的部分暂时不加载,等滚动条滚动到该区域的时候,再起加载图片
-
实现代码
var list = document.getElementsByTagName("ul")[0]; // 1.追加结构 // 如果直接将结构给innerHTML 会一直重写,也会影响页面性能 所以先将结构给一个空字符串,再将空字符串给页面结构 var str = ""; for (var i = 0; i < arr.length; i++) { // innerHTML有重写的功能 str += `<li> <img a="${arr[i]}" alt=""> </li>` } list.innerHTML = str // 2.显示第一屏效果 /* 只要在页面的可视范围内 都将图片显示出来 页面的可视范围高度 doucument.documentElement.clientHeight 图片在页面中的位置 图片.offsetTop 图片显示出来 将自定义属性src1 给src属性 */ var oImg = document.getElementsByTagName("img"); var pageClientHeight = document.documentElement.clientHeight; console.log(pageClientHeight) for (var i = 0; i < oImg.length; i++) { if (oImg[i].offsetTop <= pageClientHeight) { console.log("这是第一屏效果", "这是第" + i + "张图") oImg[i].src = oImg[i].getAttribute("a") } } // 2.页面滚动 显示可视范围内容的数据 /* 页面的范围:页面的可视高度+页面卷起的高度 */ window.onscroll = function () { // 页面卷去的高度 var sT = document.documentElement.scrollTop || document.body.scrollTop for (var i = 0; i < oImg.length; i++) { if (oImg[i].offsetTop <= (pageClientHeight + sT)) { console.log("第" + i + "张图", "window.onscroll判断") oImg[i].src = oImg[i].getAttribute("a") } } }
3.事件对象
3.1什么是事件对象
- 每一个事件都有事件对象 这个对象中用来记录和该事件有关的一些信息
- 注意:在事件处理函数中才可以使用事件对象
- 如何获取事件对象
- 标准浏览器和IE浏览器 window.event
- 老版本火狐浏览器 在事件处理函数中的第一个参数作为事件对象
- 事件对象兼容
- 标签.事件类型 = function(eve){ var ev = window.event || eve }
3.2事件对象中的属性
- altKey/shiftKey/ctrlKey
- 作用:用户在执行事件的时候,有没有同时按住alt shift ctrl键 如果按住了返回值为true,否者为false
- clientX和clientY
- 作用:获取鼠标的位置 表示鼠标位置相对于可视窗口左侧和上侧的距离
- pageX和pageY
- 作用:获取鼠标位置 表示鼠标位置到页面左侧和上侧的距离
- pageX = clientX + 卷去的宽度
- pageY = clientY + 卷去的高度
- 注意pageX和pageY存在IE低版本兼容问题 可以通过其他方式获取
- document.body.scrollLeft + clientX
- document.body.scrollTop + clientY
- 作用:获取鼠标位置 表示鼠标位置到页面左侧和上侧的距离
- target(标准浏览器)/srcElement(IE低版本)
- 作用:表示添加事件中实际触发的元素
3.3事件对象的相关练习
3.3.1元素跟随鼠标移动
3.3.2卡屏效果
<body>
<script>
document.documentElement.onmousemove = function(eve){
var ev = window.event || eve
// 每次移动都会生成一个div标签
var oDiv = document.createElement("div");
// 设置div标签的定位位置
oDiv.style.left = ev.clientX + "px";
oDiv.style.top = ev.clientY + "px";
// 设置背景色 背景色的范围是0-255
var r = Math.floor( Math.random()*(255-0+1)+0 )
var g = Math.floor( Math.random()*(255-0+1)+0 )
var b = Math.floor( Math.random()*(255-0+1)+0 )
oDiv.style.backgroundColor = "rgb("+r+","+g+","+b+")"
document.body.appendChild(oDiv);
}
</script>
</body>
3.4事件绑定和封装
事件绑定有两种方式
3.4.1普通方式绑定
-
标签.事件类型 = function(){ //要做的事 }
-
缺点:不能给同一个标签添加多次同事件类型
// 1.普通方式绑定 // 第一个人的逻辑 btn.onclick = function(){ console.log("第一次按钮") } // 第二个人的逻辑 btn.onclick = function(){ console.log("第二次按钮") } btn.onmouseover = function(){ console.log("移入按钮") }
3.4.2事件绑定
- 标准浏览器的事件绑定
- 标签.addEventListener(事件类型(不加on),事件处理函数,是否捕获(默认值是false))
// addEventListener 基础用法
btn.addEventListener("click",function(){
console.log("第一次按钮");
})
btn.addEventListener("click",function(){
console.log("第二次按钮")
})
// 将函数提出来
function btn1(){
console.log("第一次按钮");
}
btn.addEventListener("click",btn1)
function btn2(){
console.log("第二次按钮")
}
btn.addEventListener("click",btn2)
- IE低版本浏览器
- 标签.attachEvent(事件类型(加on),事件处理函数)
// 2.IE低版本浏览器
var add = document.getElementsByTagName("button")[1];
add.attachEvent("onclick",function(){
console.log("ie低版本浏览器第一次执行")
})
add.attachEvent("onclick",function(){
console.log("ie低版本第二次执行")
})
3.4.3两者绑定有什么区别
- addeventListener 和attachEvent有什么区别
- addeventListener 事件类型不需要加on 执行顺序是正序 从上到下 有事件捕获
- attachEvent 事件类型需要加on 执行顺序是倒叙 从后往前执行 没有事件捕获、
3.4.4 事件绑定浏览器兼容
// 4.方法兼容 如果是两个方法的兼容 判断某个方法是否为true
function fun1(){
console.log("这是兼容")
}
var add1 = document.getElementsByTagName("button")[2];
if(add1.addEventListener){ //标准浏览器
// 标签.addEventListener(事件类型,事件处理函数)
add1.addEventListener("click",fun1)
}else{ // IE低版本浏览器
// 标签.attachEvent(事件类型,事件处理函数)
add1.attachEvent("onclick",fun1)
}
3.4.5事件绑定函数封装
// 事件绑定函数封装
function bind(elem,type,fun) {
if (elem.addEventListener) { //标准浏览器
elem.addEventListener(type, fun); //标准浏览器绑定
} else { // IE低版本
elem.attachEvent("on"+type, fun);// iE低版本
}
}
3.5事件取消(解绑)和封装
3.5.1普通事件解绑
- 添加事件:标签.事件类型 = function(){}
- 取消事件:标签.事件类型 = null
- 说明:其实就是重新给事件对象赋值 后者覆盖前者 就重新赋值null
3.5.2事件解绑
-
标准浏览器解绑
-
绑定方式是addEventListner
- 解绑方法:元素.removeEventListener(要解绑的事件类型,要解绑的事件处理函数,是否捕获)
btn2.removeEventListener("click",fun1)
-
-
IE低版本浏览器解绑
-
绑定方式是attachEvent
- 解绑方法:元素.detachEVent(要解绑的事件类型(加on),要解绑的事件处理函数)
btn2.detachEvent("onclick",fun1)
-
3.5.3事件解绑浏览器兼容
// 兼容 判断某个方法是否存在 xxxx
if(btn2.removeEventListener){ //标准浏览器的解绑
btn2.removeEventListener("click",fun1)
}else{ //IE低版本的解绑
btn2.detachEvent("onclick",fun1)
}
3.5.4 事件解绑函数封装
function unbind(elem,type,fun) {
if (elem.removeEventListener) { //标准浏览器
elem.removeEventListener(type, fun)
} else { // IE低版本浏览器
elem.detachEvent("on" + type, fun)
}
}
3.6DOM事件流
3.6.1什么是事件流
- 事件流:当事件发生的时候 事件在父子节点之间固定的传递顺序
- 事件流包含两种事件机制
- 捕获型事件
- 第一步:捕获阶段:当事件发生的时候,事件从window(全局)开始往子元素传递
- 第二步:确定目标:确定鼠标的事件源
- 冒泡性事件
- 事件源收到事件后开始处理事件 处理完成后,会依次往父元素查找事件,如果找到就执行,直到找到window(全局)
- 捕获型事件
<body>
<div class="box1">box1
<div class="box2">box2
<div class="box3">box3</div>
</div>
</div>
<script>
var oBox = document.getElementsByTagName("div");
function fun1(){
console.log(this.className)
}
// addEventListener 第三个参数是是否捕获 默认是false(不捕获就是冒泡) true捕获
oBox[0].addEventListener("click",fun1,false);
oBox[1].addEventListener("click",fun1,false);
oBox[2].addEventListener("click",fun1,false);
//如果是捕获 输出结果是box1 box2 box3
//如果是冒泡 输出结果是box3 box2 box1
</script>
</body>
3.6.2阻止事件冒泡
- 标准浏览器:ev.stopPropagation()
- IE浏览器:ev.cancelBubble = true
- 兼容:ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true
3.6.3阻止默认行为
- 普通方式绑定事件阻止默认行为 return false即可
- 事件绑定方式阻止默认行为
- 标准浏览器:ev.preventDefault();
- IE低版本浏览器:ev.returnValue = false;
- 兼容:ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
3.7事件代理
- 事件代理的引用场景
- 我们需要给大量标签添加事件的时候,为了节省性能,我们一般会使用事件代理(事件委托)
- 假设一种场景:我们现在需要给10000个li添加点击事件,点击li输入对应的文本内容,如果按照之间的写法 需要循环10000次,会影响页面性能 浪费计算机性能
- 解决方法:采用事件代理
- 第一步:给所有要添加事件的元素的共同父元素添加事件
- 第二步:在父元素事件执行的时候 判断事件源的节点名称是不是li 如果是li就执行内容
<script>
// for(var i = 0;i<10000;i++){ //同步执行 在这里执行10000次需要花费很长的事件
// li[i].onclick = function(){
// // 输出对应的文本内容
// }
// }
// 1.事件代理
// 给父元素添加点击事件
var list = document.getElementsByTagName("ul")[0]
// 给父元素添加事件
list.onclick = function(eve){
var ev = window.event || eve;//兼容事件对象
// 当事件发生的时候去找事件目标(事件源)
var target = ev.target || ev.srcElement //兼容事件目标
// 判断元素节点是不是li
if(target.nodeName == "LI"){
// 执行逻辑
target.style.backgroundColor = "teal";
}
}
</script>
4.键盘及滚轮事件
4.1键盘事件
- onkeydown
- 键盘按下的时候触发,键盘上任何一个键都可以触发该事件 不区分大小写 返回的是大写的字符编码
- onkeyup
- 键盘抬起的时候触发
- onkeypress
- 键盘按下的时候触发 键盘上的特殊字符无法触发该事件 区分大小写 返回的是大写和小写的字符编码
document.documentElement.onkeydown = function(eve){
var ev = window.event|| eve
console.log("按下");
console.log(ev.key);//标准浏览器: 键盘上具体的字符 IE低版本:undefined
console.log(ev.keyCode);// ASCII码 不区分大小写,返回大写的字符编码
}
document.documentElement.onkeyup = function(){
console.log("抬起")
}
document.documentElement.onkeypress = function(eve){
var ev = window.event || eve;
console.log(ev.key);// 键盘上具体的字符
console.log(ev.keyCode);//ASCII码 区别大小写 但是不能输出特殊字符
}
</script>
4.2滚轮事件
- 添加滚轮事件
- 标准浏览器/IE浏览器:元素.onmousewheel
- 火狐浏览器:元素.DOMMouseScroll
- 获取滚轮的方向
- 标准浏览器/IE浏览器:ev.wheelDelta
- 向前 180/120 >0
- 向后 -180/-120 <0
- 火狐浏览器 ev.detail
- 向前 -3 <0
- 向后 3 >0
- 标准浏览器/IE浏览器:ev.wheelDelta
//标准浏览器绑定滚轮事件
document.documentElement.onmousewheel = function (eve) {
var ev = window.event || eve;
if(ev.wheelDelta > 0){
console.log("向前")
}else if(ev.wheelDelta<0){
console.log("向后")
}
console.log("标准浏览器和IE",ev.wheelDelta);
}
//火狐浏览器绑定滚轮事件 addEventListener在IE低版本下不兼容
if (document.documentElement.addEventListener) {
document.documentElement.addEventListener("DOMMouseScroll", function (eve) {
var ev = window.event || eve;
if(ev.detail <0){
console.log("向前")
}else if(ev.detail>0){
console.log("向后")
}
console.log("火狐浏览器",ev.detail)
})
}
- 滚轮事件函数兼容
function mousewheel(elem, upFunction, downFunction) {
function scroll(eve) {
var ev = window.event || eve;
var tag = true;// true向前 false向后
// 判断滚轮的方向
if (ev.wheelDelta) { //标准浏览器的滚轮方向 180/120 向前 -180/-120 向后
tag = ev.wheelDelta > 0 ? true : false
} else {//火狐浏览器的滚轮方向 -3向前 3向后
tag = ev.detail < 0 ? true : false
}
if (tag) { //滚轮向前做的事情
upFunction();
} else { //滚轮向后做的事情
downFunction();
}
}
// 标准浏览器添加滚轮事件
elem.onmousewheel = scroll
// 火狐浏览器添加滚轮事件
if (elem.addEventListener) {
elem.addEventListener("DOMMouseScroll", scroll)
}
}
5.拖拽效果
- 实现效果:在页面中拖动盒子 鼠标在哪 盒子就在哪
<body>
<div></div>
<script>
/*
1.给元素添加鼠标按下事件
2.给页面添加移动事件
3.给元素添加鼠标抬起事件
*/
var oDiv = document.getElementsByTagName("div")[0];
// 给元素添加鼠标按下事件
oDiv.onmousedown = function (eve) {
// 给页面添加移动事件
document.documentElement.onmousemove = function (eve) {
var ev = window.event || eve;
oDiv.style.left = ev.clientX + "px";
oDiv.style.top = ev.clientY + "px";
}
// 当鼠标抬起的时候 清空移动事件
oDiv.onmouseup = function () {
document.documentElement.onmousemove = null;
}
}
</script>
</body>
- 问题1:在div内部按下鼠标失效
<body>
<div></div>
<script>
/*
1.给元素添加鼠标按下事件
2.给页面添加移动事件
3.给元素添加鼠标抬起事件
*/
var oDiv = document.getElementsByTagName("div")[0];
// 给元素添加鼠标按下事件
oDiv.onmousedown = function (eve) {
/*
问题1:在div内部按下鼠标失效
解决方法 用鼠标位置-元素在页面中的位置即可
*/
var ev = window.event || eve;
var moveTop = ev.clientY - oDiv.offsetTop;
var moveLeft = ev.clientX -oDiv.offsetLeft;
// 给页面添加移动事件
document.documentElement.onmousemove = function (eve) {
var ev = window.event || eve;
oDiv.style.left = ev.clientX - moveLeft + "px";
oDiv.style.top = ev.clientY -moveTop + "px";
}
// 当鼠标抬起的时候 清空移动事件
oDiv.onmouseup = function () {
document.documentElement.onmousemove = null;
}
}
</script>
</body>
- 问题2:在拖动盒子之前不小心选择了文字,在不取消选中文字的情况下又去拖动盒子 会发现拖动是文字内容
- 原因:文字默认行为的问题
- 解决:阻止默认行为
<script>
/*
1.给元素添加鼠标按下事件
2.给页面添加移动事件
3.给元素添加鼠标抬起事件
*/
var oDiv = document.getElementsByTagName("div")[0];
/*
问题2:在拖动盒子之前不小心选择了文字,在不取消选中文字的情况下又去拖动盒子 会发现拖动是文字内容
原因:文字默认行为的问题
解决:阻止默认行为
*/
// 给元素添加鼠标按下事件
oDiv.onmousedown = function (eve) {
var ev = window.event || eve;
var moveTop = ev.clientY - oDiv.offsetTop;
var moveLeft = ev.clientX - oDiv.offsetLeft;
// 给页面添加移动事件
document.documentElement.onmousemove = function (eve) {
var ev = window.event || eve;
oDiv.style.left = ev.clientX - moveLeft + "px";
oDiv.style.top = ev.clientY - moveTop + "px";
}
// 当鼠标抬起的时候 清空移动事件
oDiv.onmouseup = function () {
document.documentElement.onmousemove = null;
// 全局捕获用不到的时候 一定要释放掉
if (oDiv.releaseCapture) { oDiv.releaseCapture() };
}
// 给div添加全局捕获 优先执行自己的事件 这个可以解决IE阻止默认行为的bug
if (oDiv.setCapture) { oDiv.setCapture() };
// 阻止默认行为 但是IE低版本无法使用return false阻止默认行为
return false;
}
</script>
6.IE的全局捕获
-
什么是IE的全局捕获
- 全局捕获:当在页面中执行事件的时候 添加全局捕获的元素会截取事件 触发自己的东西
-
给元素设置全局捕获:元素.setCapture();
-
元素释放全局捕获:元素.releaseCapture();
<script>
var btn = document.getElementsByTagName("button");
btn[0].onclick = function () {
alert("按钮1");
//释放全局捕获 不用的时候 一定要释放
btn[0].releaseCapture()
}
btn[1].onclick = function () {
alert("按钮2")
}
// 给按钮1添加全局捕获
// 全局捕获:当在页面中执行事件的时候 添加全局捕获的元素会截取事件 触发自己的东西
// 如果该元素添加全局捕获 全局捕获截取的事件 优先级高于默认事件
// 全局捕获 点击页面的任何地方都会触发该事件
btn[0].setCapture();
</script>
7.碰撞检测
- 判断水平方向的危险区域 假设拖拽盒子水平方向的位置值 l
- 危险区域 a < l < b
- 大盒子的offsetLeft - 小盒子的offsetWidth < l < 大盒子的offsetLeft + 大盒子的offsetWidth
- 判断垂直方向的危险区域 假设拖拽盒子垂直方向的位置 t
- 危险区域 x < t < y
- 大盒子的offsetTop - 小盒子的offsetHeight < t < 大盒子的offsetTop + 大盒子的offsetHeight
<div>大盒子危险区域</div>
<div>小盒子</div>
<script>
var oDiv = document.getElementsByTagName("div");
var bigBox = oDiv[0]; //危险区域盒子
var smallBox = oDiv[1];// 拖拽的盒子
//1.当鼠标按下拖拽小盒子
smallBox.onmousedown = function (eve) {
var ev = window.event || eve;
var moveTop = ev.clientY - smallBox.offsetTop;
var moveLeft = ev.clientX - smallBox.offsetLeft
// 页面添加移动
document.documentElement.onmousemove = function (eve) {
var ev = window.event || eve;
//水平方向危险区域
var a = bigBox.offsetLeft - smallBox.offsetWidth;
var b = bigBox.offsetLeft + bigBox.offsetWidth;
//垂直方向的危险区域
var x = bigBox.offsetTop - smallBox.offsetHeight;
var y = bigBox.offsetTop + bigBox.offsetHeight;
var l = ev.clientX - moveLeft; // l和f就是拖拽元素的位置
var t = ev.clientY - moveTop;
// a < l < b 转成代码公式判断 a < l && l<b
// x < t < y 转成代码公式判断 x < t && t<y
if (a < l && l < b && x < t && t < y) {
console.log("危险区");
bigBox.style.backgroundColor = "red";
} else {
console.log("安全区");
bigBox.style.backgroundColor = "#ccc";
}
smallBox.style.left = l + "px";
smallBox.style.top = t + "px";
}
//鼠标抬起 清除页面移动事件
smallBox.onmouseup = function () {
document.documentElement.onmousemove = null;
// 不用全局捕获的时候 一定要释放掉
if (smallBox.releaseCapture) { smallBox.releaseCapture() }
}
// 给IE添加全局捕获 利用全局捕获阻止默认行为
if (smallBox.setCapture) { smallBox.setCapture() };
//阻止默认行为 但是IE低版本无法使用
return false;
}
</script>