1、事件模型(DOM事件流)
1.1 事件:
1.1.1 事件是HTML和Javascript交互的驱动器, 事件是文档或者浏览器窗口中发生的, 特定的交互瞬间。
1.1.2 事件是用户或浏览器自身执行的某种动作, 如 click, load 和 mouseover 都是事件的名字。
1.1.3 事件是 javaScript 和 DOM 之间交互的桥梁。
2、事件流:
2.1 事件流, 即是一个事件发生的流程或者说流转, 从开始到结束, 都发生了什么
2.2 事件发生时会在元素节点之间按照特定的顺序传播, 这个传播过程, 我们就称之为DOM事件流.
2.3 事件流有三个阶段:
// 1. 捕获阶段 Capture Phase; 从上到下, 层层传递, 直到目标接收
// 2. 目标阶段 Target Phase; 确认目标, 进行处理
// 3. 冒泡阶段 Bubbling Phase; 处理结束, 往上传递.
// 4. 先捕获阶段=>目标阶段=>冒泡阶段
3、 注意:
1. 监听绑定方式addEventListener()方法中第三个参数可以控制是在冒泡阶段触发还是在捕获阶段触发
2. JS代码建议执行捕获或者冒泡两个阶段中的其中一个阶段
3. 传统绑定事件方式跟attachEvent绑定事件的方式只能得到"冒泡阶段"
4. addEventListener(type,listener,[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序; 如果是false(默认不写就是false),表示事件冒泡阶段调用事件处理程序.
5. 实际开发中我们很少使用事件捕获,我们更关注事件冒泡.
6. 另外需要注意, 不是所有事件都会冒泡的, 有些事件是没有冒泡的,比如onmouseenter,onmouseleave
7. 事件冒泡有时候会带来麻烦,有时候又会帮助我们很巧妙的做某些事件,我们会学习事件委托,事件委托(事件代理)的原理就是事件冒泡
8. 冒泡阶段触发,需要HTML标签是"嵌套关系(父子关系)", 而且需要都绑定事件, 接着,触发子元素事件(子元素事件不触发也可以)的时候, 会逐级向上传播, 把父辈元素相同的事件也会触发
4、 事件对象
4.1 什么是事件对象:
// 事件发生后(JS事件被触发以后),跟事件相关的一系列信息数据的集合都放到一个对象里面,这个对象就是事件对象。
4.2 这个事件对象中会保存什么信息, 比如:
// 1. 谁绑定了这个事件。
// 2. 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
// 3. 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
4.3 事件对象的使用:
事件触发发生时就会产生事件对象,并且系统会以实参的形式传给事件处理函数。
所以,在事件处理函数中声明1个形参(形参名字可以自定义,但是一般我们会使用event,evt,e这三个名字)用来接收事件对象。
// 传统绑定方式:
dom对象.onclick = function(event){
// 这个event 就是事件对象
};
// 注意: 传统绑定方式,在绑定的时候,没有兼容性问题;但是获取事件对象的时候,有兼容性问题, IE9之间的浏览器需要使用window.event获取事件对象, IE9之间的浏览器无法使用形参的方式获取事件对象
4.4 事件对象的属性和方法:
// 事件对象属性方法 说明
// ❤e.target 返回触发事件的对象 标准
// e.srcElement 返回触发事件的对象 非标准 ie6~8使用
// e.type 返回事件的类型字符串 比如 "click", "mouseover" 是不带on的
// ❤e.stopPropagation() 该方法阻止冒泡 标准
// e.cancelBubble = true 该属性阻止冒泡 非标准 ie6~8使用
// ❤e.preventDefault() 该方法阻止默认事件(默认行为) 标准 比如不让链接跳转
// e.returnValue = false 该属性阻止默认事件(默认行为) 非标准 ie6~8使用 比如不让链接跳转
// 传统绑定方式获取事件对象兼容写法
e = e || window.event;
console.log("兼容获取事件对象e=>", e);
// 传统绑定方式, 兼容性获取事件对象
e = e || window.event;
console.log("e事件对象=>", e);
console.log("e.target=>", e.target);
console.log("e.srcElement=>", e.srcElement);
console.log("e.type=>", e.type);
console.log("");
// 阻止事件冒泡兼容写法
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
// 默认行为的意思就是浏览器对于某些标签本身会有一些行为,比如a标签, 设置了href属性以后,点击a标签会跳转
// 阻止默认行为
if (e.preventDefault) {
// IE9以及IE9以上浏览器阻止默认行为
e.preventDefault();
} else {
// IE9以下浏览器阻止默认行为
e.returnValue = false;
}
5、事件委托:
// 事件委托(事件代理):本身要给子元素绑定的事件, 不给子元素绑定, 而是给父辈元素绑定
// 事件委托的原理: 冒泡
// 事件委托的作用: 可以给动态新增的元素绑定事件
// 给ul绑定鼠标点击事件:
objUl.onclick = function (e) {
console.log("this=>", this);
console.log("e.target=>", e.target);
// nodeName获取节点名称
console.log("e.target.nodeName=>", e.target.nodeName);
// tagName获取标签名称
console.log("e.target.tagName=>", e.target.tagName);
e.target.style.color = "red";
}
6、onchange事件:
注意: option没有设置value的时候,默认会使用option的标签内容作为value值
onchange事件
// 概念: onchange事件当用户更改、和 元素的值并提交这个更改时,onchange 事件在这些元素上触发。和 oninput 事件不一样,onchange 事件并不是每次元素的 value 改变时都会触发。
// 下拉框的onchange需要给select标签绑定
7、oninput事件
oninput 事件在用户输入时触发
该事件在 或 元素的值发生改变时触发。
提示: 该事件类似于 onchange 事件。不同之处在于 oninput 事件在元素值发生变化是立即触发,
oninput跟onchange事件的区别:
1. onchange 在元素失去焦点时触发
2. 在按快捷键ctrl+v粘贴的时候,onkeyup这个事件会触发两次, 但是oninput只触发一次;
3. 鼠标右键粘贴,只能
触发oninput事件以及onchange事件,不能触发onkeyup事件
// 下拉框的oninput需要给select标签绑定
8、事件高级:
8.1 传统注册方式(传统绑定方式)
1 语法:
// dom对象.on事件类型 = 匿名函数 或者 有名函数名
2 特点:
// 1. 同一个DOM对象绑定同一个类型事件多次, 后面绑定的事件驱动函数会覆盖前面绑定的
// 2. 没有兼容性问题
// 3. 事件驱动函数里面this指向绑定事件的那个DOM对象
8.2 事件监听方式
1 语法:
// dom对象.addEventListener("不带on的事件类型" , 匿名函数 或者 有名函数名 );
2 特点:
// 1. 同一个DOM对象绑定同一个类型事件多次, 会绑定顺序叠加触发事件驱动函数
// 2. 有兼容性问题, IE9以及IE9以后的主流浏览器才可以使用该addEventListener监听方式
// 3. 在事件驱动函数中,this指向绑定这个事件的DOM对象
8.3 IE9之前事件监听方式
// 语法:
// dom对象.attachEvent("带on的事件类型", 匿名函数 或者 有名函数名 )
// 特点:
// 1. 同一个DOM对象绑定同一个事件多次, 按绑定顺序的倒序叠加执行事件驱动程序
// 2. 有兼容问题,需要低版本的IE浏览器才可以使用该绑定方式(IE 5 6 7 8 9 10)
// 3. 事件驱动程序中this指向window对象
9、删除事件:
9.1 解绑传统绑定的事件语法:
// dom对象.on事件类型 = null;
9.2 解绑addEventListener绑定的事件语法:
// dom对象.removeEventListener("不带on事件类型", 有名函数名 )
9.3 解绑attachEvent绑定的事件语法:
// dom对象.detachEvent("带on事件类型", 有名函数名 )
10、常用键盘事件:
10.1 键盘事件 触发条件
// onkeyup 某个键盘按键被松开时触发
// onkeydown 某个键盘按键被按下时触发
// onkeypress 某个键盘按键被按下时触发 但是它不识别功能键 比如 ctrl shift 箭头等
10.2 注意:
// 1. onkeypress和前面两个onkeyup跟onkeydown的区别是 onkeypress不识别功能键,比如箭头,ctrl,shift 等
// 2. 三个事件的执行顺序是: keydown => keypress => keyup
10.3 键盘事件对象
// 键盘事件对象属性 说明
// e.keyCode 返回该键的ASCII值 e.keyCode只有keypress事件可以区分大小写字母
// e.key 返回用户按下的物理按键的键名
11、常用鼠标事件:
11.1 鼠标事件 触发条件
// click 鼠标点击左键触发
// dblclick 鼠标双击左键触发
// mouseover 鼠标移上触发
// mouseout 鼠标移出触发
// mouseenter 鼠标进入触发
// mouseleave 鼠标离开触发
// mousemove 鼠标移动触发
// mouseup 鼠标弹起触发
// mousedown 鼠标按下触发
// focus 获取鼠标焦点触发
// blur 失去鼠标焦点触发
11.2 鼠标事件对象常用属性:
// event 事件对象是事件相关的一系列信息的集合.
// 现阶段我们主要用鼠标事件对象MouseEvent 和 键盘事件对象KeyBoardEvent
11.3 鼠标事件对象 说明:
// ❤e.clientX 返回鼠标相对于浏览器窗口可视区(不包括滚动条距离)的X坐标
// ❤e.clientY 返回鼠标相对于浏览器窗口可视区(不包括滚动条距离)的Y坐标
// ❤e.pageX 返回鼠标相对于文档页面(包括滚动条距离)的X坐标 IE9+支持
// ❤e.pageY 返回鼠标相对于文档页面(包括滚动条距离)的Y坐标 IE9+支持
// ❤e.offsetX 返回鼠标指针相对于目标节点内边(元素内)位置的X坐标
// ❤e.offsetY 返回鼠标指针相对于目标节点内边(元素内)位置的Y坐标
// e.screenX 返回鼠标相对于电脑屏幕的X坐标
// e.screenY 返回鼠标相对于电脑屏幕的Y坐标
11.4 注意:
// e.pageX/e.pageY 鼠标在页面中的位置 有兼容性问题 从IE9以后才支持
// 扩展:IE无法兼容pageX/pageY解决参考: https://www.cnblogs.com/mushuizzz/p/11847172.html
11.5 mouseenter和mouseover的区别:
// 注意: onmouseover和onmouseout会事件冒泡
// 注意: onmouseenter和onmouseleave不会事件冒泡
12、js三大家族属性:
js三大家族包括offset,client,scroll
三大系列属性,这三个系列属性可以获取宽度高度以及相应的距离
❤❤❤注意: 三大系列属性返回值都是'数值',不带单位, 只能"获取",不能"设置"
12.1 client
// dom对象.clientTop = 上边框的大小
// dom对象.clientLeft = 左边框的大小
// dom对象.clientWidth = width+左padding+右padding
// dom对象.clientHeight = height+上padding+下padding
12.2 offset
// dom对象.offsetWidth 返回自身包括padding、边框、内容区的总宽度 , 返回数值不带单位 其实就是盒子的真实宽度
// dom对象.offsetHeight 返回自身包括padding、边框、内容区的总高度 , 返回数值不带单位 其实就是盒子的真实高度
// dom对象.offsetParent 返回作为该元素带有"非静态定位最近"的父辈元素 如果父辈元素都没有非静态定位则返回"body"元素
// dom对象.offsetLeft 返回元素相对带有"非静态定位最近"的父辈元素左方的偏移量 如果父辈都没有定位则返回相对"body"的"左"方偏移量
// dom对象.offsetTop 返回元素相对带有"非静态定位最近"的父辈元素上方的偏移量 如果父辈都没有定位则返回相对"body"的"上方"偏移量
12.3 scroll
// dom对象.scrollWidth 返回自身实际的宽度,不含边框,返回数值不带单位
// dom对象.scrollHeight 返回自身实际的高度,不含边框,返回数值不带单位
// dom对象.scrollLeft 返回被卷去的左侧距离,返回数值不带单位
// dom对象.scrollTop 返回被卷去的上侧距离,返回数值不带单位
// scroll事件可以给元素绑定,可以给页面绑定 ,当元素滚动的时候,就可以触发scroll事件
// 给页面绑定scroll事件, 可以给document对象, window对象或者body绑定页面滚动事件
❤❤❤一般给window对象绑定
// 注意: 给html对象绑定scroll事件无效
// ❤❤❤window.pageYOffset window.pageXOffset
eg: 封装一个兼容写法 获取页面滚动的距离
function getScroll() {
return {
x: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
y: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
}
}
12.4 补充:
// 滚动窗口至文档中的特定位置:
// 语法一: window.scroll(x-coord,y-coord )
// 语法二: window.scroll(options)
// options 是一个包含三个属性的对象:
// top 等同于 y-coord
// left 等同于 x-coord
// behavior 类型String,表示滚动行为,支持参数 smooth(平滑滚动),instant(瞬间滚动),默认值auto
// 注意:里面的x和y不需要带px单位 直接写数字即可
// 另外,还有一个window.scrollTo函数,实际上和 window.scroll是一样的
// 如果只有一个参数的时候,这个参数需要是一个对象
// window.scroll(水平滚动条位置, 垂直滚动条位置);
// window.scrollTo()的用法跟window.scroll()方法是一样的
// 通过 dom对象.style.css属性名 的方法获取的样式只能是行内式样式属性值 内嵌式和外链式样式都无法获取
// 获取计算以后样式属性值 window.getComputedStyle( element, [pseudoElt] ) 该方法返回一个对象
// 参数说明
// 1. element 用于获取计算样式的Element, 就是DOM对象
// 2. pseudoElt 可选 指定一个要匹配的伪元素的字符串。必须对普通元素省略(或null)
13、延时器和定时器
13.1 延时器:
1 延迟多久以后, "仅执行一次"指定的代码块
// 全局的 setTimeout() 方法设置一个定时器,该定时器在定时器到期后执行一个函数或指定的一段代码
2 开启延时器语法
// window.setTimeout( function, delay )
// 返回值timeoutID是一个正整数,表示延时器的编号。这个值可以传递给clearTimeout()来取消该延时器。
3 参数说明
// 1. function 是你想要在到期时间 (delay毫秒) 之后执行的函数。
// 2. delay 延迟的毫秒数, 取值数值 ,单位是毫秒 一秒等于 1000 毫秒
4 清除延时器语法
// clearTimeout( timeoutID ) 方法取消了先前通过调用setTimeout()建立的定时器。
// 参数说明: timeoutID 您要取消定时器的标识符。该 ID 由相应的setTimeout()调用返回。
13.2 定时器:
1 每隔指定时间, 就执行一次指定的代码块 不断重复执行
// setInterval() 方法重复调用一个函数或执行一个代码片段,在每次调用之间具有固定的时间间隔。
2 开启定时器语法
// window.setInterval(function, delay);
// 返回值一个 interval ID,该 ID 唯一地标识时间间隔,因此你可以稍后通过调用 clearInterval() 来移除定时器。
3 清除定时器语法
// window.clearInterval(intervalID);
14、window对象
window对象是浏览器的顶级对象,它具有双重角色.
14.1 介绍:
// 1. 它是JS访问浏览器窗口的一个接口.
// 2. 它是一个全局对象. 定义在全局作用域中的变量、函数会变成window对象的属性和方法
// 3. 在调用的时候可以省略window, 比如我们前面学习alert(),prompt()都属于window对象的方法
// 4. 注意:window对象下有一个特殊属性window.name, window.name的属性值是一个字符串
// 5. window.top属性也是window对象中一个内置属性, 它的属性值是指向回window对象自身 top属性值修改不了
14.2 注意:
// 避免使用name和top作为变量名
// name变量名的时候, name的值一定会被改成字符串类型
// top变量名的值会一直指向window对象自身 修改不了
14.3 window对象的属性
// 属性 功能:
// ❤❤❤window.innerWidth 获取浏览器内部的宽度(不包含浏览器的左右两边边框)
// ❤❤❤window.innerHeight 获取浏览器内部的高度(不包含浏览器的菜单栏和地址栏以及上下的边框)
// window.outerWidth 获取整个浏览器的宽度
// window.outerHeight 获取整个浏览器的高度
// 确认框
// window.confirm("提示信息");
14.4 window对象的常见事件
// 1. 页面(窗口)加载事件(两种)
// ❤❤❤1.1 window对象的load事件
// window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。
// window.onload() 通常用于元素,在页面完全载入后(包括DOM结构, 图片、css文件等等)执行脚本代码。
// 1.2 document对象的DOMContentLoaded事件
当初始HTML文档已完全加载和解析时,将触发DOMContentLoaded事件,而不需要等待样式表,图像和子框架页面加载(事件可以用来检测HTML页面是否完全加载完毕(fully-loaded))
// 小结:
// 1. DOMContentLoaded事件绑定的时候, 需要使用事件监听方式绑定
// 2. load事件需要等待HTML结构,CSS样式,图像等都加载完毕以后,再调用load的事件函数
// 3. DOMContentLoaded仅需要等待HTML结构加载完毕即可调用
// 2. 调整窗口大小事件
window对象的resize事件:当浏览器可视区域大小发生变化的时候,就会调用resize事件
// 封装一个获取计算以后样式属性值的方法
function getStyle(dom, attr) {
return window.getComputedStyle(dom)[attr];
}
// 版本一:
封装缓动框架(任意一个数值属性)
* 封装元素js缓慢动画框架
* 参数1 {object} dom 要做动画的dom对象
* 参数2 {string} attr 要做动画的CSS属性名
* 参数3 {number} target 要做动画的CSS属性名的目标值
function animate(dom, attr, target) {
// 清除之前的定时器
clearInterval(dom.intervalId);
// 开启定时器
dom.intervalId = setInterval(function () {
// 获取当前dom的attr对应的属性值
var curVal = parseFloat(getStyle(dom, attr));
// 判断是否达到目标值target
if (curVal === target) {
// 清除定时器
clearInterval(dom.intervalId);
// 使用return关键字,终止函数体的执行
return;
}
// 缓慢动画的意思就是速度由快变慢, 运动速度越来越慢
// 缓慢动画公式: 速度 = ( 目标值 - 当前值 ) / 10;
var speed = (target - curVal) / 10;
// 因为速度有可能得到小数, 小数会导致我们无法达到目标值, 所以需要对速度进行取整
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 设置dom对象对应的attr属性值
dom.style[attr] = curVal + speed + "px";
}, 15);
}
// 给按钮绑定鼠标点击事件
btns[0].onclick = function () {
animate(objDiv, "width", 500);
btns[1].onclick = function () {
animate(objP, "left", 50);
}
// 版本二:
封装缓动框架(多个数值属性)
* 封装元素js缓慢动画框架
* 参数1 {object} dom 要做动画的dom对象
* 参数2 {object} obj 要做动画的一对或者多对CSS属性名和目标值 组成的对象
function animate(dom, obj) {
// 清除之前的定时器
clearInterval(dom.intervalId);
// 开启定时器
dom.intervalId = setInterval(function () {
// for...in遍历obj对象 attr就是css属性名
for (var attr in obj) {
// 获取目标值
var target = obj[attr];
// 获取当前dom的attr对应的属性值
var curVal = parseFloat(getStyle(dom, attr));
// 判断是否达到目标值target
if (curVal === target) {
// 清除定时器
clearInterval(dom.intervalId);
// 使用return关键字,终止函数体的执行
return;
}
var speed = (target - curVal) / 10;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 设置dom对象对应的attr属性值
dom.style[attr] = curVal + speed + "px";
}
}, 15);
}
// 给按钮绑定鼠标点击事件
btns[0].onclick = function () {
animate(objDiv, {
"width": 500,
"height": 300
});
}
btns[1].onclick = function () {
animate(objP, {
"height": 300,
});
}
或者
*/
function animate(dom, obj) {
// 清除之前的定时器
clearInterval(dom.intervalId);
// 开启定时器
dom.intervalId = setInterval(function () {
// 在定时器内部定义一个变量, 保存是否所有CSS属性都达到了目标值
var flag = true; // 假设所有属性已经达到了目标
// for...in遍历obj对象 attr就是css属性名
for (var attr in obj) {
// 获取目标值
var target = obj[attr];
// 获取当前dom的attr对应的属性值
var curVal = parseFloat(getStyle(dom, attr));
// 判断是否达到目标值
if (curVal != target) { // 如果没有达到
// 修改flag变量的值
flag = false;
}
var speed = (target - curVal) / 10;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 设置dom对象对应的attr属性值
dom.style[attr] = curVal + speed + "px";
}
// for...in结束,就表示所有属性都遍历完毕了
if (flag) { // 判断flag的值
// 清除定时器
clearInterval(dom.intervalId);
}
}, 15);
}
// 给按钮绑定鼠标点击事件
btns[0].onclick = function () {
animate(objDiv, {
"width": 500,
"height": 300,
"font-size": 50
});
}
// 给按钮绑定鼠标点击事件
btns[1].onclick = function () {
animate(objP, {
"height": 300,
});
}
// 版本三: 封装缓动框架(添加回调函数)
* 封装元素js缓慢动画框架
* 参数1 {object} dom 要做动画的dom对象
* 参数2 {object} obj 要做动画的一对或者多对CSS属性名和目标值 组成的对象
* 参数3 可选参数 {function} callback 动画完成以后,要调用的函数 回调函数就是满足一定条件才调用的函数
function animate(dom, obj, callback) {
// 清除之前的定时器
clearInterval(dom.intervalId);
// 开启定时器
dom.intervalId = setInterval(function () {
// 在定时器内部定义一个变量, 保存是否所有CSS属性都达到了目标值
var flag = true; // 假设所有属性已经达到了目标
// for...in遍历obj对象 attr就是css属性名
for (var attr in obj) {
// opacity属性特殊处理
if (attr == "opacity") {
// 获取目标值
var target = obj[attr] * 100;
// 获取当前dom的attr对应的属性值
var curVal = parseFloat(getStyle(dom, attr)) * 100;
// 判断是否达到目标值
if (curVal != target) { // 如果没有达到
// 修改flag变量的值
flag = false;
}
// 缓慢动画的意思就是速度由快变慢, 运动速度越来越慢
// 缓慢动画公式: 速度 = ( 目标值 - 当前值 ) / 10;
var speed = (target - curVal) / 10;
// 因为速度有可能得到小数, 小数会导致我们无法达到目标值, 所以需要对速度进行取整
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 设置dom对象对应的attr属性值
dom.style[attr] = (curVal + speed) / 100;
} else if (attr == "z-index" || attr == "zIndex") {
// z-index或者zIndex属性特殊处理
dom.style[attr] = obj[attr];
} else {
// 获取目标值
var target = obj[attr];
// 获取当前dom的attr对应的属性值
var curVal = parseFloat(getStyle(dom, attr));
// 判断是否达到目标值
if (curVal != target) { // 如果没有达到
// 修改flag变量的值
flag = false;
}
// 缓慢动画的意思就是速度由快变慢, 运动速度越来越慢
// 缓慢动画公式: 速度 = ( 目标值 - 当前值 ) / 10;
var speed = (target - curVal) / 10;
// 因为速度有可能得到小数, 小数会导致我们无法达到目标值, 所以需要对速度进行取整
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 设置dom对象对应的attr属性值
dom.style[attr] = curVal + speed + "px";
}
}
// for...in结束,就表示所有属性都遍历完毕了
if (flag) { // 判断flag的值
// 清除定时器
clearInterval(dom.intervalId);
// 动画完成了,所以我们可以调用回调函数, 前提是存在回调函数
if (callback !== undefined && typeof callback === "function") {
callback();
}
}
}, 15);
}
// 给按钮绑定鼠标点击事件
btns[0].onclick = function () {
animate(objDiv, {
"width": 500
}, function () {
animate(objDiv, {
"height": 300
}, function () {
animate(objDiv, {
"font-size": 50
});
})
});
}
// 给按钮绑定鼠标点击事件
btns[1].onclick = function () {
animate(objP, {
"height": 300,
});
}