BOM介绍
BOM: window history location navigator 事件
一. 什么是BOM: Browser Object Model
浏览器 对象 模型
1. 什么是: 专门操作浏览器窗口的一套对象和方法的集合。
2. 何时: 2种:
(1). 想获取或操作窗口相关的信息
比如: 想获得窗口大小、想打开一个新窗口、想关闭现有窗口...
(2). 获取浏览器软件的配置信息:
比如: 浏览器的名称和版本号、安装了什么插件...
3. 包括:
window history location document navigate screen event
4. 问题: BOM没有标准!兼容性极差!所以,用的越来越少!
二. window对象:
1. 3个角色:
(1). 代替了ES标准中的global对象,充当全局作用域对象
所有ES标准中规定的,可直接使用的内置对象和函数,都保存在window中
而且我们自己创建的全局变量和函数,默认也是保存在window中
(2). 包含了所有原生的直接可用的js对象和函数:
原生=ES标准+DOM标准+BOM
(3). 代表了当前浏览器窗口:
a. window可获得窗口的大小: 2组
1). 整个窗口的完整大小:
window.outerWidth window.outerHeight
2). 仅文档显示区范围的大小:
window.innerWidth window.innerHeight
b. window还可以打开和关闭浏览器窗口;
1). window.open()
2). window.close()
2. 打开新链接总结: 4种
对应小程序视频: 小程序->在线->DOM->day03 4. 打开新链接4种方式
(1). 在当前窗口打开新链接,可后退
a. html: <a href="url" target="_self">文本</a>
b. js: window.open("url","_self")
(2). 在当前窗口打开新链接,禁止后退
//无法在HTML中实现该功能由于 histor对象没有replace功能 只能通过location 的replace 来代替url达到不可后退的功能
a. js: location.replace("新url")
b. 后退的原理: 见history
c. 阻止后退的原理: 用新的url,去代替history中旧的url。一旦旧的url被代替了,不复存在了!自然就不能后退了!
(3). 在新窗口打开新链接,可同时打开多个
a. html: <a href="url" target="_blank">文本</a>
b. js: window.open("url","_blank")
(4). 在新窗口打开新链接,只能打开一个
a. html: <a href="url" target="自定义窗口名">文本</a>
b. js: window.open("url", "自定义窗口名")
(5). 原理:
a. 其实每个浏览器窗口在内存中都有一个唯一的名字
b. 浏览器规定,相同名称的窗口,只能打开一个。后打开的同名窗口会覆盖先打开的同名窗口
c. 窗口名是由a元素或js语句在打开新窗口时指定的:
<a href="url" target="自定义窗口名">
window.open("url", "自定义窗口名")
d. 结果: a元素或js语句中定义的新窗口名会自动保存在新窗口的name属性中!
e. 正因为如此,将来我们自己起变量名时,不要使用"name"作为变量名!因为"name"在BOM中有特殊意义,作为窗口的名称。
f. 预定义窗口名:
1). _self: 自动获得当前旧窗口自己的名称,作为新窗口的名称。结果,新窗口会覆盖旧窗口,相当于在当前窗口打开新链接。
2)._blank: 不指定新窗口名,但是浏览器也不会让新窗口名空着。浏览器会自动在底层(我们看不见),为每个新窗口随机生成窗口名!结果,因为随机生成的窗口名不重复,所以可以反复打开多个!
(6). 示例: 实现四种打开新链接的方式:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"/> 5 <title>打开新链接方式总结</title> 6 </head> 7 <body> 8 <h3>1. 在当前窗口打开,可后退</h3> 9 <a href="http://tmooc.cn" target="_self">go to tmooc</a><br/> 10 <button id="btn1">go to tmooc</button> 11 12 <h3>2. 在当前窗口打开,禁止后退</h3> 13 <button id="btn2">go to tmooc</button> 14 15 <h3>3. 在新窗口打开,可打开多个</h3> 16 <a href="http://tmooc.cn" target="_blank">go to tmooc</a><br/> 17 <button id="btn3">go to tmooc</button> 18 19 <h3>4. 在新窗口打开,只能打开一个</h3> 20 <a href="http://tmooc.cn" target="tmooc">go to tmooc</a><br/> 21 <button id="btn4">go to tmooc</button> 22 23 <script> 24 var btn1=document.getElementById("btn1"); 25 btn1.onclick=function(){ 26 window.open("http://tmooc.cn","_self") 27 } 28 29 var btn2=document.getElementById("btn2"); 30 btn2.onclick=function(){ 31 location.replace("http://tmooc.cn"); 32 } 33 34 var btn3=document.getElementById("btn3"); 35 btn3.onclick=function(){ 36 window.open("http://tmooc.cn","_blank") 37 } 38 39 var btn4=document.getElementById("btn4"); 40 btn4.onclick=function(){ 41 window.open("http://tmooc.cn","tmooc") 42 } 43 </script> 44 </body> 45 </html>
三. history:
1. 什么是: 内存中专门保存当前窗口打开后,成功访问过的url的历史记录数组
2. 原理:
(1). 只要在当前窗口中成功打开一个新链接,history都会以push方式,将新链接追加到history中保存
(2). 如果又访问了一个新的url地址,同样会被push进history中保存。但是,因为history中之前已经有旧的url地址,所以,新地址追加入history后,就可后退了!
(3). 此时,如果点了一下后退,退到前一个旧的url,就可以点前进了。
3. 常用操作:
(1). 前进一步: history.go(1)
(2). 后退一步: history.go(-1)
有时,如果后退一步不好使,可以后退2步history.go(-2)
(3). 刷新页面: history.go(0)
4. 示例: 在多个页面之间前进后退:
3个页面的代码如下:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>使用 history 对象</title> 5 <meta charset="utf-8" /> 6 </head> 7 <body> 8 <h2>9-1.html</h2> 9 <div> 10 <a href="9-1_history.html">1</a> 11 <a href="9-2_history.html">2</a> 12 <a href="9-3_history.html">3</a> 13 </div><br/> 14 <div> 15 <!--javascript: 让a不再跳转,而是执行一条js语句--> 16 <a href="javascript: history.go(1)">前进一次</a> 17 <a href="javascript: history.go(2)">前进二次</a> 18 </div> 19 </body> 20 </html>
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>使用 history 对象</title> 5 <meta charset="utf-8" /> 6 </head> 7 <body> 8 <h2>9-2.html</h2> 9 <div> 10 <a href="9-1_history.html">1</a> 11 <a href="9-2_history.html">2</a> 12 <a href="9-3_history.html">3</a> 13 </div><br/> 14 <div> 15 <!--javascript: 让a不再跳转,而是执行一条js语句--> 16 <a href="javascript: history.go(-1)">后退一次</a> 17 <a href="javascript: history.go(1)">前进一次</a> 18 </div> 19 </body> 20 </html>
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>使用 history 对象</title> 5 <meta charset="utf-8" /> 6 </head> 7 <body> 8 <h2>9-3.html</h2> 9 <div> 10 <a href="9-1_history.html">1</a> 11 <a href="9-2_history.html">2</a> 12 <a href="9-3_history.html">3</a> 13 </div><br/> 14 <div> 15 <!--javascript: 让a不再跳转,而是执行一条js语句--> 16 <a href="javascript: history.go(-2)">后退二次</a> 17 <a href="javascript: history.go(-1)">后退一次</a> 18 </div> 19 </body> 20 </html>
运行步骤:
1. 先打开第一个HTML
2. 然后依次点击页面中2、3两个链接,先后打开第二个HTML和第三个html
3. 点前进和后退的超链接,实现在三个页面之前来回前进后退。
四. location对象:
1. 什么是: 专门保存当前正在打开的url信息的对象
2. 何时: 2种:
(1). 获得浏览器地址栏中当前url信息
(2). 执行一些页面跳转操作时
3. 属性: location可完整或分段的获得url中的信息
(1). location.href 获得地址栏中完整url信息
(2). location.protocol 协议
(3). location.host 主机名+端口号
(4). location.hostname 主机名
(5). location.port 端口号
(6). location.pathname 相对路径
(7). location.search ?及其之后的查询字符串参数列表
(8). location.hash #及其之后的锚点地址
(9). 示例: 访问location的各个属性值:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>事件处理</title> 5 <meta charset="utf-8" /> 6 7 </head> 8 <body> 9 <form> 10 姓名:<input name="username"/><br> 11 密码:<input type="password" name="pwd"/><br> 12 爱好:<input type="checkbox" name="favs" value="running"/>跑步 13 <input type="checkbox" name="favs" value="swimming"/>游泳 14 <input type="checkbox" name="favs" value="basketball"/>篮球 15 <br> 16 <input type="submit"/> 17 </form> 18 <a href="#top">返回顶部</a> 19 <script> 20 console.log(location.href); //获取url 21 console.log(location.protocol);//获取协议 22 console.log(location.host);//获取主机名字 23 console.log(location.hostname);//获取主机名和端口 24 console.log(location.port);//获取端口 25 console.log(location.pathname);//获取url路径 26 console.log(location.search);//获取url中?后的内容 27 console.log(location.hash); //获取url中#后面的内容 28 </script> 29 </body> 30 </html>
4. 链接跳转的location方法:
(1). 也能实现在当前窗口打开可后退:
location.assign("新url"); 等效于 window.open("新url","_self")
(2). 也能实现刷新页面:
location.reload(); 等效于 history.go(0)
(3). 独立的可以实现在当前页面打开,禁止后退:
location.replace("新url")
五. navigator:
1. 什么是: 专门保存浏览器软件的配置信息的对象
2. 何时: 项目中只要想获得浏览器软件的配置信息时
3. 主要用途:
(1). 获得当前浏览器软件的名称、版本号和内核
navigator.userAgent
(2). 判断当前浏览器是否安装某个插件
a. navigator.plugins 集合中保存了当前浏览器已经安装的所有插件的信息:(得到的是个类数组对象)
b. 如何判断是否安装某个插件?
if(navigator.plugins["完整插件名"]!==undefined){ //强行访问插件名
说明已经安装该插件了
}else{
说明未安装该插件
}
4. 示例: 查看userAgent字符串,并判断浏览器是否安装某些插件
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>navigator对象常用属性</title> 5 <meta charset="utf-8" /> 6 7 </head> 8 <body> 9 <script> 10 console.log(navigator.userAgent); 11 console.log(navigator.plugins); 12 //判断当前浏览器是否安装了Chrome PDF Viewer插件 13 if(navigator.plugins["Chrome PDF Viewer"]!==undefined){ 14 document.write(`<h3>已安装PDF插件,可查看PDF电子书</h3>`) 15 }else{ 16 document.write(`<h3>未安装PDF插件,<a href="#">点此下载安装</a></h3>`) 17 } 18 //判断当前浏览器是否安装了Shockwave Flash插件 19 if(navigator.plugins["Shockwave Flash"]!==undefined){ 20 document.write(`<h3>已安装Flash插件,可播放Flash动画</h3>`) 21 }else{ 22 document.write(`<h3>未安装Flash插件,<a href="#">点此下载安装</a></h3>`) 23 } 24 </script> 25 </body> 26 </html>
六. *****事件*****
1. 什么是事件: 浏览器自动触发的或用户手动触发的页面中内容或状态的改变
2. 什么是事件处理函数: 希望在事件发生时,能自动执行的一个函数
3. 什么是事件绑定: 提前将事件处理函数,保存在元素对象的事件属性上,暂存,暂不执行!
4. 事件绑定的结果: 当浏览器中某个元素上发生了事件时,浏览器就会自动找到这个元素上对应事件属性上提前保存的事件处理函数,自动执行!
5. 如何绑定: 3种:
(1). 在HTML中手工绑定: 2步:
a. 先在<body>之前的<script>中定义事件处理函数:
function 函数名(){ ... }
b. 再在<元素 on事件名="函数名()">
c. 结果: 当这个元素上发生事件时,浏览器会自动执行on事件名属性上提前保存的js函数调用语句,并去内存中找到对应的事件处理函数,自动调用
d. 问题: 因为事件绑定被写在元素的HTML标签中,散落在网页的各个角落,不符合内容与行为分离的原则,极其不便于项目中的维护!
(2). 在js中用赋值方式绑定事件: 2步:
a. 在<body>结尾的<script>中,先查找可能触发事件的元素
b. 再为找到的元素对象上的事件属性赋值一个事件处理函数
元素对象.on事件名=function(){ ... }
c. 结果: 当这个元素上发生事件时,浏览器会自动执行on事件名属性上提前保存的js函数,自动调用。
d. 优点: 因为都集中定义在js中,所以极其便于项目中的维护。
e. 缺点: 因为一个事件属性上只能保存一个事件处理函数。如果希望一个事件能同时保存多个事件处理函数,就会发生覆盖!后赋值的事件处理函数,会覆盖之前赋值的事件处理函数。
(3). 在js中通过添加事件监听对象的方式来绑定事件:
a. 什么是事件监听对象: 是专门保存一个事件相关的事件名+元素对象+事处理函数的特殊对象。
b. 如何: 2步:
1). 还是先找到可能触发事件的元素对象
2). 创建一个事件监听对象,并添加到浏览器的事件监听对象队列中保存。
元素对象.addEventListener("事件名", 事件处理函数);
添加事件监听对象
c. 强调: addEventListener函数中的事件名不带on前缀。
1). 因为DOM标准中规定的事件名本来是没有on的!
比如: click, blur, focus, mouseover ... ...
2). 元素对象身上的on事件属性,为了和元素对象身上的其它普通属性区分,才加上on开头!仅仅是为了醒目!
d. 示例: 使用添加事件监听方式,为一个元素绑定多个事件处理函数
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"/> 5 <title>...</title> 6 <script> 7 </script> 8 </head> 9 10 <body> 11 <button id="btnShoot">shoot</button><br> 12 <button id="btnAward">获得跟踪导弹</button><br> 13 <button id="btnBreak">失去跟踪导弹</button><br> 14 <script> 15 var btnShoot= 16 document.getElementById("btnShoot"); 17 var btnAward= 18 document.getElementById("btnAward"); 19 var btnBreak= 20 document.getElementById("btnBreak"); 21 //开局点btnShoot只能发射一种普通子弹 22 btnShoot.onclick=function(){ 23 console.log("发射普通子弹...") 24 } 25 //当单击btnAward时,希望给btnShoot添加一种新的跟踪导弹函数。希望再点击btnShoot时,能同时发射2种子弹 26 btnAward.onclick=function(){ 27 //错误: 会覆盖旧的事件处理函数 28 // btnShoot.onclick=function(){ 29 // console.log(`发射跟踪导弹=>=>=>`) 30 // } 31 //正确: 32 btnShoot.addEventListener( 33 "click", 34 function(){ 35 console.log(`发射跟踪导弹=>=>=>`) 36 }//但是这样的做法不便于移除事件 移除事件需要得知准确的函数地址而这里创建的匿名函数,所以无法实现移除的效果 37 ) 38 } 39 </script> 40 </body> 41 </html>
e. 原理:
1). addEventListener()其实做了2件事:
i. 先创建一个事件监听对象,保存住这个事件绑定相关的三样东西: 当前元素对象+当前事件名+事件处理函数
ii. 将事件监听对象添加到浏览器中一个巨大的事件监听对象队列中保存
2). 当元素上触发事件时: 2件事:
i. 浏览器会先找到元素对象身上on事件名属性中保存的事件处理函数,优先执行
ii. 浏览器还会继续去事件监听对象的队列中查找是否包含符合条件的事件监听对象。只要找到符合条件的事件监听对象,就会自动取出事件监听对象中保存的事件处理函数,自动执行。
f. 移除事件监听:
1). 元素对象.removeEventListener("事件名", 原事件处理函数对象)
2). 坑: 在移除事件监听对象时,如果事件处理函数只是写的和原事件处理函数完全一样!是无法移除!
3). 原因: function底层等效于new Function()。意味着,如果在添加事件监听时和移除事件监听时,分别写了两次function,就意为着分别创建了两个不同的函数对象。即使函数内容一样,也不是统一函数对象!地址不同!
4). 解决: 项目中,如果一个事件处理函数有可能被移除,则绑定时就不能用匿名函数绑定!应该用有名称的函数来绑定!函数名可以保存住最初的函数对象地址,并在移除事件监听时,反复使用原函数地址。
5). 坑: 一旦采用有名称的函数添加事件监听,则只能添加一个事件监听了。无法添加多个完全相同的事件监听了!——后期我将在jQuery中介绍解决的办法
g. 示例: 移除事件监听对象:
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8" /> 6 <title>...</title> 7 <script> 8 </script> 9 </head> 10 11 <body> 12 <button id="btnShoot">shoot</button><br> 13 <button id="btnAward">获得跟踪导弹</button><br> 14 <button id="btnBreak">失去跟踪导弹</button><br> 15 <script> 16 var btnShoot = 17 document.getElementById("btnShoot"); 18 var btnAward = 19 document.getElementById("btnAward"); 20 var btnBreak = 21 document.getElementById("btnBreak"); 22 //开局点btnShoot只能发射一种普通子弹 23 btnShoot.onclick = function () { 24 console.log("发射普通子弹...") 25 } 26 //当单击btnAward时,希望给btnShoot添加一种新的跟踪导弹函数。希望再点击btnShoot时,能同时发射2种子弹 27 //先定义一个有名字的函数 28 var shoot2 = function () { 29 console.log(`发射跟踪导弹=>=>=>`) 30 } 31 btnAward.onclick = function () { 32 //错误: 会覆盖旧的事件处理函数 33 // btnShoot.onclick=function(){ 34 // console.log(`发射跟踪导弹=>=>=>`) 35 // } 36 //正确: 37 btnShoot.addEventListener( 38 "click", 39 //如果将来有可能移除跟踪导弹, 40 //就不能用匿名函数绑定: 41 //应该用函数名绑定 42 shoot2 43 ) 44 } 45 //当单击btnBreak时,从btnShoot元素上将跟踪导弹移除 46 btnBreak.onclick = function () { 47 btnShoot.removeEventListener( 48 "click", 49 //移除时也必须用原函数名移除 50 shoot2 51 //因为用的是同一个变量,所以变量中保存的函数对象地址一定相同! 52 ) 53 } 54 </script> 55 </body> 56 57 </html>
6. ***事件模型***:
(1). 问题:点在内层子元素上,也会触发外层父元素上的单击事件处理函数
如下面这个 例子:
1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>事件处理</title> 6 <meta charset="utf-8" /> 7 <style> 8 #d1 #d2 #d3 { 9 cursor: pointer 10 } 11 12 #d1 { 13 background-color: green; 14 position: relative; 15 width: 150px; 16 height: 150px; 17 text-align: center; 18 cursor: pointer; 19 } 20 21 #d2 { 22 background-color: blue; 23 position: absolute; 24 top: 25px; 25 left: 155px; 26 width: 100px; 27 height: 100px; 28 } 29 30 #d3 { 31 background-color: red; 32 position: absolute; 33 top: 25px; 34 left: 175px; 35 width: 50px; 36 height: 50px; 37 line-height: 50px; 38 } 39 </style> 40 41 </head> 42 43 <body> 44 <div id="d1"> 45 <div id="d2"> 46 <div id="d3"> 47 </div> 48 </div> 49 </div> 50 <script> 51 var d1=document.getElementById("d1"); 52 var d2=document.getElementById("d2"); 53 var d3=document.getElementById("d3"); 54 d1.onclick=function(){ 55 alert("d1 疼!") 56 } 57 //点击d2会alert两次 自己的 d1的 即使设置样式将d2 或者d3 移动到不重叠也会触发这个效果 58 d2.onclick=function(e){ 59 e.stopPropagation(); 60 alert("d2 疼!") 61 } 62 //点击d3会alert三次 自己的 d2的 d3的 63 d3.onclick=function(e){ 64 e.stopPropagation(); 65 alert("d3 疼!") 66 } 67 </script> 68 </body> 69 70 </html>
(2). 原因: 事件模型:
a. 什么是: 从触发事件开始,到所有事件处理函数执行完,所经历的整个过程。
b. DOM标准规定,事件模型包括3个阶段:
1). 捕获: 由外向内, 从根节点document开始,依次遍历实际触发事件的元素的各级父元素。并记录各级父元素上绑定的事件处理函数。只记录,暂时不执行
2). 目标触发: 浏览器总是预先触发事件点击的元素上的事件处理函数。
实际点击的元素,也成为目标元素(target)
3). 冒泡: 按照捕获阶段记录的反向,由内向外,依次触发各级父元素上绑定的事件处理函数。
如图

7. 事件对象:
(1). 什么是事件对象: 当事件发生时,浏览器自动创建的,保存事件相关信息的对象。
(2). 何时: 2种:
a. 想获取事件相关的信息时
b. 想改变事件默认的行为时
(3). 如何使用: 事件对象不用自己创建,就可直接使用: 2步:
a. 在事件处理函数上,添加形参变量e
元素.onclick=function(e){
b. 在事件处理函数内,形参变量e,就能自动接到浏览器创建并传来的事件对象。
e自动接到事件对象
}
c. 原理: 当事件发生时,浏览器注定会自动创建一个事件对象,并自动传递给事件处理函数的第一个形参变量e。——信任!
8. 事件对象可以:
(1). 停止冒泡: e.stopPropagation() 意为:停止 蔓延
示例: 点内层元素,只内层元素触发函数,其它元素不触发函数
如图:

1 <!DOCTYPE HTML> 2 <html> 3 4 <head> 5 <title>事件处理</title> 6 <meta charset="utf-8" /> 7 <style> 8 #d1 #d2 #d3 { 9 cursor: pointer 10 } 11 12 #d1 { 13 background-color: green; 14 position: relative; 15 width: 150px; 16 height: 150px; 17 text-align: center; 18 cursor: pointer; 19 } 20 21 #d2 { 22 background-color: blue; 23 position: absolute; 24 top: 25px; 25 left: 155px; 26 width: 100px; 27 height: 100px; 28 } 29 30 #d3 { 31 background-color: red; 32 position: absolute; 33 top: 25px; 34 left: 175px; 35 width: 50px; 36 height: 50px; 37 line-height: 50px; 38 } 39 </style> 40 41 </head> 42 43 <body> 44 <div id="d1"> 45 <div id="d2"> 46 <div id="d3"> 47 </div> 48 </div> 49 </div> 50 <script> 51 var d1=document.getElementById("d1"); 52 var d2=document.getElementById("d2"); 53 var d3=document.getElementById("d3"); 54 d1.onclick=function(){ 55 alert("d1 疼!") 56 } 57 d2.onclick=function(e){ 58 e.stopPropagation(); 59 alert("d2 疼!") 60 } 61 d3.onclick=function(e){ 62 e.stopPropagation(); 63 alert("d3 疼!") 64 } 65 </script> 66 </body> 67 68 </html>
(2). ***利用冒泡/事件委托***:
a. 优化: 尽量减少事件绑定的次数!
1). 问题: 因为每次触发事件时,浏览器都是通过遍历事件监听队列的方式来查找符合要求的事件监听对象。
2). 所以,队列中事件监听对象的个数,应该越少越好!因为个数越少,遍历查找就快,事件响应的速度就快!
b. 如何: 利用冒泡/事件委托 3步
1). 如果多个子元素都要绑定相同的事件时,其实只要在父元素上集中绑定一个事件处理函数,所有子元素注定都能通过冒泡机制共用父元素上的事件处理函数。
i. 问题: this不能用了!
ii. 原因: 因为如果利用事件委托,事件是绑定在父元素上,不是绑定在子元素上了!而且执行时,是在父元素上执行的!所以事件委托中的this,不再执行子元素,而是统一指向父元素了!——不是我们想要的了!
2). 项目中,只要使用事件委托,都要用e.target代替this!
i. 什么是e.target: 事件对象中,始终保存最初点击的目标元素的特殊属性。
ii. 和this相比:
this,会随冒泡而改变,可能指向父元素了
e.target,一旦保存住最初的实际点击的目标元素,就不会随冒泡而改变,
iii. 强调: 如果想用e.target,事件处理函数必须添加形参变量e
iv. 问题: 父元素div,是块元素,所以子元素之外的剩余空间也都属于父元素范围。所以,点在子元素周围的空白范围内,也会触发事件!——不是我们想要的!
3). 在事件处理函数内,在正式执行事件处理逻辑之前,必须先判断当前点击的目标元素是不是我们想要的!只有当前点击的目标元素是我们想要的时,我们才执行事件处理逻辑。否则,就什么也不干!
c. 示例: 使用事件委托事件简单的计算器效果:
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>取消与利用冒泡</title> 5 <meta charset="utf-8"/> 6 </head> 7 <body> 8 <div id="keys"> 9 <button>1</button> 10 <button>2</button> 11 <button>3</button> 12 <button>4</button><br> 13 <button>C</button> 14 <button>+</button> 15 <button>-</button> 16 <button>=</button> 17 </div> 18 <textarea id="sc" style="resize:none;width:200px; height:50px;" readonly></textarea> 19 <script> 20 //DOM 4步 21 //1. 查找触发事件的元素 22 //本例中:因为多个平级的button,都要单击,所以应该用事件委托优化。只在父元素div上集中绑定一个事件处理函数,所有子元素通过冒泡机制,共用父元素上绑定的事件处理函数 23 var div=document.getElementById("keys"); 24 //2. 绑定事件处理函数 25 div.onclick=function(e){ 26 // alert("疼!"); 27 //点哪个按钮,哪个按钮变小花 28 //错误: this->父元素div 29 // this.innerHTML="❀"; 30 //正确: e.target->实际点的是哪个元素,就指谁 31 //判断: 本例中,只有button元素才能出发后续操作! 32 //补充: 每个元素对象身上都有一个nodeName属性,专门记录着这个元素的标签名 33 //但是,nodeName记录的标签名是全大写的!所以比较时,也要用全大写的字母与其比较! 34 if(e.target.nodeName=="BUTTON"){ 35 // e.target.innerHTML="❀"; 36 //先获得充当显示屏的id为sc的文本域元素 37 var sc=document.getElementById("sc"); 38 //先判断当前点击的按钮的内容 39 //复习第一阶段分支结构 40 switch(e.target.innerHTML){ 41 case "C"://如果点在C按钮上 42 //就清空显示屏的内容 43 sc.value=""; 44 break; 45 case "="://否则如果点在=按钮上 46 //就获得显示屏中的表达式,计算结果 47 var str=sc.value; 48 //先尝试计算显示屏中的内容 49 //复习第一个阶段 50 try{ 51 //将显示屏的内容交给eval做计算,将结果再替换回显示屏中 52 sc.value=eval(str); 53 }catch(err){//万一执行失败 54 //将错误提示显示在显示屏上 55 sc.value=err; 56 } 57 break; 58 //否则如果点在其它普通的按钮上 59 default: 60 //就把当前按钮的内容追加到显示屏上 61 sc.value+=e.target.innerHTML; 62 } 63 } 64 } 65 </script> 66 </body> 67 </html>
(3). 阻止默认行为:
a. 问题: HTML中个别元素身上带有一些默认的行为,有些默认行为是有害的!使我们不希望的!
b. 比如: <a href="#">xxx</a>,会自动在地址栏中url结尾添加#
巧了,将来vue框架的客户端路由导航也是用#作为标志。
如果让a擅自修改url结尾的#xxx,一定会和vue和路由导航冲突!
c. 解决:
1). 如果是a元素: <a href="javascript:;">xxx</a> 就不会有任何多余的操作
i. javascript 意为让a不要跳转,而是执行一条js语句
ii. ; 是一条什么也不干的空语句!
iii. javascript:; 意为让a,什么也不干!
2). 如果是除了a以外的元素,也想去掉比想要的默认行为:
元素.onclick=function(e){
e.preventDefault();
阻止 默认行为
然后再写我们自己的逻辑
}
d. 示例: 使用两种方法阻止a元素执行默认行为
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 </head> 9 <body> 10 <a href="javascript:;">click me1</a> 11 <a id="a2" href="#">click me2</a> 12 <script> 13 var a2=document.getElementById("a2"); 14 a2.onclick=function(e){ 15 e.preventDefault();//可以阻止a向url结尾添加# 16 // 阻止 默认行为 17 //添加自己想要的运行逻辑 18 alert("疼!"); 19 } 20 </script> 21 </body> 22 </html>
(4). 获得鼠标位置: 每单击一次页面,都能获得3组坐标位置:
a. 相对于屏幕左上角的x,y坐标: e.screenX, e.screenY
b. 相对于文档显示区左上角的x,y坐标: e.clientX, e.clientY
c. 相对于当前点击的元素左上角的偏移量: e.offsetX, e.offsetY
如图:

d. 示例: 点击页面中某个位置,显示三组坐标:
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>在当前显示区范围内实现点不到的小方块</title> 6 <style> 7 div{ 8 position:fixed; 9 top:100px; 10 left:150px; 11 width:100px; 12 height:100px; 13 background-image:url(images/xiaoxin.gif); 14 background-size:100%; 15 } 16 </style> 17 18 </head> 19 <body> 20 <div id="pop"></div> 21 <script> 22 var pop=document.getElementById("pop"); 23 pop.onclick=function(e){ 24 console.log(e.screenX, e.screenY);//获取相对于屏幕的坐标 25 console.log(e.clientX, e.clientY);//获取相对于浏览器文档内容的坐标 26 console.log(e.offsetX, e.offsetY);//获取相对于其父元素的坐标 27 } 28 </script> 29 </body> 30 </html>
对于BOM 和DOM 的小知识总结:
DOM
. 修改属性: 3种
a. 字符串类型的HTML标准属性: 2种:
1). 旧核心DOM: 4个函数
i. 元素.getAttribute("属性名");
ii. 元素.setAttribute("属性名", "属性值")
iii. var bool=元素.hasAttribute("属性名")
iv. 元素.removeAttribute("属性名")
优点: 万能, 缺点: 繁琐
2). 新HTML DOM:
i. 元素.属性名
ii. 元素.属性名="属性值"
iii. 元素.属性名!==""
iv. 元素.属性名=""
优点: 简单, 缺点: 不万能
b. bool类型的HTML标准属性:
1). 不能用旧核心DOM4个函数修改
2). 只能用HTML DOM的"元素.属性名"方式获取或修改,且值为bool类型
c. 自定义扩展属性:
1). 何时: 2种
i. 代替id、class、元素等选择器作为查找触发事件的元素的条件
ii. 在客户端元素上临时缓存业务数据
2) HTML中: <元素 data-自定义属性名="属性值">
3). js中: 2种: (不能用.访问)
i. 核心DOM:
var 属性值=元素.getAttribute("data-自定义属性名")
元素.setAttribute("data-自定义属性名","属性值")
ii. HTML5标准: 元素.dataset.自定义属性名
(3). 修改样式:
a. 修改元素的内联样式:
元素.style.css属性="属性值"
b. 获取元素的完整样式:
var style=getComputedStyle(元素对象);
style.css属性
计算后的样式都是只读的
c. 批量修改元素的样式时,都用class:
元素.className="class名"
总结: 不要背英文名字!反而应该记中文能做哪些事儿!
3. 添加/删除元素:
(1). 只添加一个新元素: 3步
a. 创建一个新元素:
var 新元素=document.createElement("标签名")
b. 为元素设置关键属性:
新元素.属性名="属性值";
c. 将新元素添加到DOM树: 3种:
1). 末尾追加:
父元素.appendChild(新元素)
2). 在某个元素前插入:
父元素.insertBefore(新元素, 现有元素)
3). 替换某个元素:
父元素.replaceChild(新元素, 现有元素)
(2). 优化: 尽量减少操作DOM树的次数,2种:
a. 如果同时添加父元素和子元素,应该先将子元素添加到父元素,最后再将父元素一次性添加到DOM树
b. 如果父元素已经在页面上,要添加多个平级子元素。应该利用文档片段对象
1). 创建文档片段对象:
var frag=document.createDocumentFragment()
2). 将子元素添加到文档片段对象中:
frag.appendChild(子元素)
3). 最后将文档片段对象一次性添加到DOM树上父元素下
父元素.appendChild(frag);
(3). 删除元素: 父元素.removeChild(子元素)
BOM
1. window:
(1). 获得窗口大小:
a. 获得完整窗口大小:
window.outerWidth和window.outerHeight
b. 获得文档显示区大小:
window.innerWidth和window.innerHeight
(2). 打开和关闭窗口:
window.open()和window.close()
2. 打开新链接4种方式:
(1). 在当前窗口打开,可后退
a. html: <a href="url" target="_self">
b. js: window.open("url", "_self");
(2). 在当前窗口打开,禁止后退
a. js: location.replace("新url")
(3). 在新窗口打开,可同时打开多个
a. html: <a href="url" target="_blank">
b. js: window.open("url", "_blank");
(4). 在新窗口打开,只能打开一个
a. html: <a href="url" target="自定义窗口名">
b. js: window.open("url", "自定义窗口名")
3. history:
(1). 前进: history.go(n)
(2). 后退: history.go(-n)
(3). 刷新: history.go(0)
4. location:
(1). 属性: 分段获得url中各个部分:
a. location.href 完整url
b. location.protocol 协议
c. location.host 主机名+端口号
d. location.hostname 主机名
e. location.port 端口号
f. location.pathname 相对路径
g. location.search ?及其之后的查询字符串参数列表
h. location.hash #锚点地址
(2). 方法:
a. 在当前窗口打开,可后退:
location.assign("新url") 或 location.href="新url"
b. 在当前窗口打开,禁止后退:
location.replace("新url")
c. 刷新: location.reload();
5. navigator
(1). 查看浏览器的名称和版本号: navigator.userAgent
(2). 查看浏览器中安装的插件列表: navigator.plugins
总结: 事件:
1. 绑定事件: js中:
(1). 一个事件只绑定一个处理函数
元素.on事件名=function(){ ... }
(2). 一个事件绑定多个处理函数
元素.addEventListener("事件名", 事件处理函数)
(3). 移除一个事件监听:
元素.removeEventListener("事件名", 原事件处理函数对象)
2. 事件模型: 捕获,目标触发,冒泡
3. 事件对象:
(1). 获得事件对象:
元素.on事件名=function(e){ ... }
(2). 阻止冒泡: e.stopPropagation()
(3). 当多个子元素都要绑定相同事件时,利用冒泡/事件委托3步:
a. 事件只在父元素上绑定一次
b. e.target代替this
c. 判断e.target的任意特征是否是我们想要的元素
(4). 阻止元素默认行为:
e.preventDefault()
(5). 获取鼠标位置:
a. 相对于屏幕左上角的x,y坐标:
e.screenX, e.screenY
b. 相对于文档显示区左上角的x,y用坐标:
e.clientX, e.clientY
c. 相对于事件所在元素左上角的x,y坐标:
e.offsetX e.offsetY
(6). 窗口滚动事件:
a. 当滚动条滚动时自动触发: window.onscroll=function(){ ... }
b. 获取滚动条滚动过的距离:
var scrollTop=document.body.scrollTop||document.documentElement.scrollTop;
c. 控制滚动条滚动到指定位置: window.scrollTo(0, 要滚动到的位置)

浙公网安备 33010602011771号