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
- 在 IE 中要使用
事件监听
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
-
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);
}
}