JavaScript 详细学习笔记4
1. 事件高级
1.1 注册事件
给元素添加事件,称为注册事件或者绑定事件
1.1.1 传统注册事件
- 利用on开头的事件 比如onclick
- 特点:注册事件的唯一性–>同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
1.1.2 addEventListener方法监听注册事件
document.addEventListener(event,function,useCapture)
event:描述事件名称的字符串;
function:事件发生后需要执行的操作;
useCapture:可选,布尔值,指定事件是否在捕获阶段还是冒泡阶段执行,true->捕获阶段执行,false->冒泡阶段执行,默认false;
- W3C标准 推荐方式
- addEventListener() 它是一个方法
- IE9以前的IE不支持此方法,可使用attachEvent()代替
- 同一个元素同一事件可以注册多个监听器
- 按照注册顺序依次执行
- eventTarget.addEventListener(type,listener[ , useCapture]):将指定的监听器注册到eventTarget(目标对象)上,就会执行事件处理函数
- type:事件类型字符串,比如 click,mouseover,注意这里不带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是false
1.1.3 attachEvent 事件监听方式
eventTarget.attachEvent(eventNameWithOn,callback):指将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,指定的回调函数将会被执行
- eventNameWithOn:事件类型字符串,比如onclick,onmouseover ,这里要带on
- callback:事件处理函数,当目标函数被触发时,回调函数被调用
<body>
<button>传统注册事件</button>
<button>方法监听事件</button>
<button>ie9 attachEvent</button>
<script>
var btns=document.querySelectorAll('button');
// 传统监听事件
btns[0].onclick=function(){
alert('haha');
}
btns[0].onclick=function(){ // 执行这一个,前面的onclick被这个覆盖
alert('babab');
}
// 方法监听事件 事件侦听注册事件 都可以执行
btns[1].addEventListener('click',function(){
alert('2344')
})
btns[1].addEventListener('click',function(){
alert('25679');
})
// attachEvent 事件监听方式 只能ie9 以前的浏览器才能使用 了解即可
btns[2].attachEvent('onclick',function(){
alert('123');
})
</script>
</body>
1.1.4 注册事件兼容性解决方案
兼容性处理原则:先照顾大多数浏览器,再处理特殊浏览器
function addEventListener(element,eventName,fn){
// 判断当前浏览器是否支持 addEvenListener方法
if(element.addEventListener){
element.addEventListener(eventName,fn); // 第三个参数默认是false
}else if(element.attachEvent){
element.attachEvent('on'+eventName,fn);
}else{
// 相当于 element.οnclick=fn
element['on'+eventName]=fn;
}
}
1.2 删除事件(解绑事件)
- 传统注册事件:eventTarget.οnclick=null;
- 方法监听注册方式:eventTarget.removeEventListener(type,listener[, useCapture])
- ie9以前专用:eventTarget.detachEvent(eventNameWithOn,callback)
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs=document.querySelectorAll('div');
divs[0].onclick=function(){
alert(11);
// 传统方式解绑
divs[0].onclick=null;
}
// 方法监听注册方式解绑
divs[1].addEventListener('click',fn) // 里面的fn不需要调用加小括号
function fn(){
alert(22);
divs[1].removeEventListener('click',fn);
}
// 3. ie9以前专用监听方式 解绑
divs[2].attachEvent('onclick',fn1)
function fn1(){
alert(33);
divs[2].detachEvent('onclick',fn1);
}
// 封装兼容性解决方案
function removeEventListener(element,eventName,fn){
// 判断当前浏览器是否支持 removeEvenListener方法
if(element.removeEventListener){
element.removeEventListener(eventName,fn); // 第三个参数默认是false
}else if(element.detachEvent){
element.detachEvent('on'+eventName,fn);
}else{
// 相当于 element.οnclick=null
element['on'+eventName]=null;
}
}
</script>
</body>
1.3 DOM事件流
事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
DOM事件流分为3个阶段
- 捕获阶段:事件捕获–>网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程
- 当前目标阶段
- 冒泡阶段: 事件冒泡–>IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程
1.3.1 DOM事件流代码验证
注意:
- js代码中只能执行捕获或者冒泡其中的一个阶段
- onclick和attachEvent只能得到冒泡阶段
- eventTarget.removeEventListener(type,listener[, useCapture]),第三个参数如果是true,表示事件捕获阶段调用事件处理程序,如果是false(默认是false),表示在事件冒泡阶段调用事件处理程序
<style>
.father {
overflow: hidden;
width: 200px;
height: 200px;
margin: 200px auto;
background-color: pink;
text-align: center;
}
.son {
width: 100px;
height: 100px;
margin: 50px;
background-color: purple;
line-height: 100px;
color: #fff;
}
</style>
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
var son=document.querySelector('.son');
// 捕获阶段,如果 addEventListener第三个参数是true,那么处于捕获阶段
son.addEventListener('click',function(){
alert(111);
},true);
var father=document.querySelector('.father');
// 捕获阶段,如果 addEventListener第三个参数是true,那么处于捕获阶段
father.addEventListener('click',function(){
alert(222);
},true);
// 先弹出222再弹出111
var son=document.querySelector('.son');
// 冒泡阶段,如果 addEventListener第三个参数是false,那么处于冒泡阶段
son.addEventListener('click',function(){
alert(111);
},false);
var father=document.querySelector('.father');
// 捕获阶段,如果 addEventListener第三个参数是true,那么处于捕获阶段
father.addEventListener('click',function(){
alert(222);
},false);
// 先弹出111再弹出222
document.addEventListener('click',function(){
alert('document');
})
// 弹完前面在弹document
</script>
</body>
1.4 事件对象
1.4.1 什么是事件对象
div.onclick=function(e){
e=e||window.event
console.log(e);
}
div.addEventListener('click',function(event){
console.log(event);
})
-
event就是一个事件对象,写到侦听函数的小括号里面,当形参来看
-
事件对象只有有了对象才会存在,它是系统给我们创建的,不需要我们传递参数
-
事件对象是事件一系列相关数据的集合,跟事件相关的 比如鼠标点击里面就包含了鼠标相关的信息、鼠标坐标
-
事件对象可以自己命名,比如event、evt、e
-
事件对象也有兼容性问题,ie678 通过window.event,兼容性的写法 e=e||window.event
1.4.2 事件对象的常见属性和方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件对象 标准 |
e.srcElement | 返回触发事件对象 非标准 |
e.type | 返回事件的类型 比如click、mouseover 不带on |
e.cancelBubble | 该属性阻止冒泡 非标准 ie6-8使用 |
e.returnValue | 该属性阻止默认事件(默认行为) 非标准 ie6-8使用,比如不让链接跳转 |
e.preventDefault() | 该属性阻止默认事件(默认行为) 标准 ie6-8使用,比如不让链接跳转 |
e.stopPropagation() | 阻止冒泡 标准 |
// e.target与this的区别
<body>
<div>123</div>
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var div=document.querySelector('div');
div.addEventListener('click',function(e){
console.log(e.target); // <div>123</div> 返回触发事件的对象(元素)
console.log(this); // <div>123</div> 返回的是绑定事件的对象(元素)
})
var ul=document.querySelector('ul');
ul.addEventListener('click',function(e){
// 给ul绑定了事件 this指向ul e.target指向li
console.log(this); // <ul>...</ul>
console.log(e.target); // <li>abc</li>
})
// 兼容处理 了解即可
div.onclick=function(e){
e=e||window.event;
var target=e.target||e.srcElement;
console.log(target);
}
// 与this相似的属性 currentTarget ie6-8 不认识
</script>
</body>
// 阻止默认行为
<body>
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" class="sub">
</form>
<script>
// 返回事件类型
var div=document.querySelector('div');
div.addEventListener('click',fn);
function fn(e){
console.log(e.type); // click
}
// 阻止默认事件 让链接不跳转或者提交不提交
var a=document.querySelector('a');
a.addEventListener('click',function(e){
e.preventDefault(); // dom标准写法
})
// 传统的注册方式
a.onclick=function(e){
// 普通浏览器 e.preventDefault(); 方法
e.preventDefault();
// 低版本浏览器 ie6-8 属性
e.returnValue;
// return false 也可以阻止默认行为,没有兼容性问题 return后面的代码不执行,只限于传统的注册
return false;
}
</script>
</body>
1.5 阻止事件冒泡
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点
- 标准写法:利用事件对象里面的stopPropagation()方法
- 非标准写法:IE 6-8 利用事件对象cancelBubble属性
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
var son=document.querySelector('.son');
// 冒泡阶段,如果 addEventListener第三个参数是false,那么处于冒泡阶段
son.addEventListener('click',function(e){
alert('son');
// e.stopPropagation();
// e.cancelBubble=true;
// 兼容性解决方法
if(e&&e.stopPropagation){
e.stopPropagation();
}else{
window.event.cancelBubble=true;
}
},false);
var father=document.querySelector('.father');
// 捕获阶段,如果 addEventListener第三个参数是true,那么处于捕获阶段
father.addEventListener('click',function(){
alert('father');
},false);
document.addEventListener('click',function(){
alert('document');
})
</script>
</body>
1.6 事件委托(代理、委派)
事件委托也称为事件代理,在jQuery里面称为事件委派
事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在父节点上,然后利用冒泡原理影响设置每个节点
事件委托的作用:只操作了一次DOM,提高了程序的性能
<body>
<ul>
<li>知否知否,应是绿肥红瘦</li>
<li>知否知否,应是绿肥红瘦</li>
<li>知否知否,应是绿肥红瘦</li>
<li>知否知否,应是绿肥红瘦</li>
</ul>
<script>
// 事件委托的核心:给父节点添加侦听器,利用事件冒泡影响每一个子节点
var ul=document.querySelector('ul');
var flag=true;
ul.addEventListener('click',function(e){
// alert('知否知否,应是绿肥红瘦');
// e.target可以得到点击的对象
e.target.style.backgroundColor='blue';
})
//利用排他法进行操作
var lis = document.getElementsByTagName('li');
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function() {
for (let j = 0; j < lis.length; j++) {
lis[j].style.backgroundColor ='';
// lis[i].style.backgroundColor = 'pink';
}
lis[i].style.backgroundColor='pink';
}
}
</script>
</body>
1.7 常用的鼠标事件
1.7.1 鼠标事件
-
禁止鼠标右键菜单:contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
-
禁止鼠标选中(selectstart 开始选中)
<body> 我是一段不愿意分享的文字 <script> // 1. 禁用右键菜单 document.addEventListener('contextmenu',function(e){ e.preventDefault(); }) // 2. 禁止鼠标选中 document.addEventListener('selectstart',function(e){ e.preventDefault(); }) </script>
1.7.2 鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息的集合,现阶段主要用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标 IE9+支持 |
e.pageY | 返回鼠标相对于文档页面的Y坐标 IE9+支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
<body>
<script>
// 鼠标对象事件 MouseEvent
document.addEventListener('click',function(e){
// 浏览器可视区的x和y坐标
console.log(e.clientX,e.clientY); // 166 50
// 文档页面的x和y坐标
console.log(e.pageX,e.pageY); // 166 72
// 电脑屏幕的x和y坐标
console.log(e.screenX,e.screenY); // 758 138
})
</script>
</body>
1.8 常用键盘事件
1.8.1 三个键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 |
onkeydown | 某个键盘按键被按下时触发 |
onkeypress | 某个键盘按键被按下时触发,但是它不识别功能键,比如 Ctrl shift 箭头等 |
<body>
<script>
// 1. onkeyup
// document.οnkeyup=function(){
// alert('我弹起了');
// }
document.addEventListener('keyup',function(){
console.log('我弹起了');
})
// 2. onkeydown
document.addEventListener('keydown',function(){
console.log('我按下了down');
})
// 3. onkeypress
document.addEventListener('keypress',function(){
console.log('我按下了press');
})
// 三个事件的执行顺序:keydown-->keypress-->keyup
</script>
</body>
1.8.2 键盘事件对象
键盘事件对象属性 | 说明 |
---|---|
keyCode | 返回该键的ASCII值,能区分大小写 |
<body>
<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
document.addEventListener('keyup',function(e){
console.log(e.keyCode);
// 1. 我们的keyup与keydown事件不区分字母大小写
// 2. keypress事件区分字母大小写
// 3. 可以利用keyCode返回的ASCII码值来判断用户按下了哪个键
if(e.keyCode===65){
alert('你按下了a键');
}else{
alert('你没有按下a键');
}
})
</script>
</body>
2. BOM 浏览器对象模型
2.1 BOM概述
- BOM 即浏览器对象模型,,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window
- BOM是由一系列相关的对象构成,并且每个对象都提供了很多方法和属性
- BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C,BOM最初是Netscape浏览器标准的一部分
- BOM是浏览器厂商在各自浏览器上定义的,兼容性较差
- BOM包含DOM
- window对象是浏览器的顶级对象,具有双重角色:是js访问浏览器窗口的一个接口;是一个全局对象,定义在全局作用域中的变量,函数都会变成window对象的属性和方法。(window下的一个特殊属性window.name)
2.2 window 常见事件
2.2.1 窗口加载事件
-
window.load窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等),就调用的处理函数(使用这个之后,js文件可以放在任何位置,但这个只能写一次,如果有多个,就以最后一个为准)
-
DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表、图片和flash等 ie9以上支持
<body>
<!-- 窗口加载事件 -->
<script>
// window.οnlοad=function(){
// var input=document.querySelector('button');
// input.addEventListener('click',function(){
// alert('点击了');
// })
// }
window.addEventListener('load',function(){
var input=document.querySelector('button');
input.addEventListener('click',function(){
alert('点击了');
})
})
document.addEventListener('DOMContentLoaded',function(){
alert(33);
})
//load事件等页面内容全部加载完毕才会执行,DOMContentLoaded是DOM加载完毕,就可以执行
</script>
<button>点击</button>
</body>
2.2.2 调整窗口大小事件
window.onresize:是调整窗口大小加载事件,当触发时就调用的处理函数
注意:
- 只要窗口大小发生变化,就会触发这个事件
- 利用这种事件完成响应式布局,window.innerWidth当前屏幕的宽度
<style>
div{
width: 200px;
height: 200px;
background-color: pink;
}
</style>
<body>
<script>
window.addEventListener('load',function(){
var div=document.querySelector('div');
window.addEventListener('resize',function(){
console.log('变化了');
if(window.innerWidth<=800){
div.style.display='none';
}else{
div.style.display='block';
console.log(111);
}
})
})
</script>
<div></div>
</body>
2.3 定时器
2.3.1 常见定时器设置
- window.setTimeout(调用函数,[延迟的毫秒数]):设置一个定时器,该定时器到期后执行调用函数
- window.setInterval(回调函数,[延迟的毫秒数]):重复调用一个函数,每隔这个时间,就去调用一次回调函数
- window.clearTimeout(timeoutID):停止定时器
<body>
<button>点击停止定时器setTimeout</button>
<button>点击停止定时器setInterval</button>
<script>
var btn=document.querySelectorAll('button');
// 1. setTimeout window可以省略 延时时间单位是毫秒,可省略,默认是0 调用函数可直接写函数,还可写函数名,也可写 '函数名()'
setTimeout(function(){
console.log('时间到了');
},2000);
function callback(){
console.log('爆炸了');
}
// 页面中可能有很多的定时器,我们经常给定时器加标识符(名字)
var time1=setTimeout(callback,5000);
var time2=setTimeout(callback,2000);
// 停止定时器
btn[0].addEventListener('click',function(){
clearTimeout(time1);
})
// 2. setInterval 时间到了,会间隔同样的时间不断调用这个函数
var time3=setInterval(function(){
console.log('继续输出');
},1000);
// 停止定时器
btn[1].addEventListener('click',function(){
clearInterval(time3);
})
</script>
</body>
2.3.2 this指向问题
- 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
- 方法调用中谁调用this指向谁
- 构造函数中this 指向构造函数的实例
2.4 JS 执行队列
JS 原来是单线程:JavaScript语言的一大特点是单线程,也就是说,同一时间只能做一件事
2.4.1 同步和异步
- 同步:前一个任务结束之后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的
- 异步:在做一件事可以处理其他事情,可同时处理多个任务
- 同步任务:都在主线程上执行,形成一个执行栈
- 异步任务:js的异步是通过回调函数实现的,有以下三种类型:
- 普通事件:如click、resize等
- 资源加载:如load、error等
- 定时器、包括setTimeout、setInterval等
2.4.2 js执行机制
- 先执行执行栈中的同步任务
- 异步任务(回到函数)放入任务队列中
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
由于主线程不断地重复获得任务,执行任务、在获取任务、再执行,所以这种机制被称为事件循环(event loop)
2.5 location 对象
window对象给我们提供了一个location属性用于获取或设置窗体的URL,并且可以用于解析URL,因为这个属性返回的是一个对象,所以这个属性也称为location对象。
URL: 统一资源定位符是互联网上标准资源的地址,互联网上的每个文件都有唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL的一般语法格式:
protocol://host[:port]/path/[?query]#fragment (protocol:通信协议,常用的http,ftp,maito;host:主机(域名);port:端口号;path:路径;query:参数;fragment:片段 #后面内容,常见于链接 锚点 )
比如:http://www.itcast.cn/index.html?name=andy&age=18#link
2.5.1 location 属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置整个URL |
location.host | 返回主机(域名) www.itheima.com |
location.port | 返回端口号 如果未写返回空字符串 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段 #后面的内容,常见于链接、锚点 |
2.5.2 location 方法
location对象方法 | 返回值 |
---|---|
location.assign() | 跟href一样,可以跳转页面(也称为重定位页面) |
location.replace() | 替换当前页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮,或者F5,如果参数为true,则强制刷新ctrl+F5 |
<body>
<!-- 常见方法 -->
<button>点击</button>
<script>
var btn=document.querySelector('button');
btn.addEventListener('click',function(){
// assign可后退
// location.assign('http://www.baidu.com');
// replace不记录浏览历史,不支持后退功能
// location.replace('http://www.baidu.com');
location.reload(true);
})
</script>
</body>
2.6 navigator 对象
navigator对象包含有关浏览器的信息,它有很多属性,最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的信息。
// 判断用户哪个终端打开页面,实现跳转
<script>
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.location.href = ""; //手机
}
</script>
2.7 history 对象
window对象给我们提供了一个history对象,与浏览器历史记录进行交互,该对象包含用户(在浏览器窗口中)访问过的URL
history对象方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能 参数如果是1,前进一个页面,如果是-1,后退一个页面 |
<body>
<a href="../js深入学习2/12-获取URL参数/index.html">点击我去往下一个页面</a>
<button>前进</button>
<script>
var btn=document.querySelector('button');
btn.addEventListener('click',function(){
// history.forward();
history.go(1);
})
</script>
</body>