BOM编程艺术 什么是BOMBOM的全称为 Browser Object Model,被译为浏览器对象模型
BOM提供了独立于HTML页面内容,而与浏览器相关的一系列对象。主要被用于管理浏览器窗口及与测览器窗口之间通信等功能。
BOM由一系列对象构成,这些对象可以简单理解为是由各个览器所提供的,例如 Window对象等。
Window对象window对象是BOM中最核心的对象
全局作用域在浏览器环境中运行javascript
逻辑时,在全局作用域中定义的对象、变量和函数都是Window对象的属性和方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var test = 666 console .log('test:' , test)console .log('windows.test:' , window .test)function t ( ) { console .log('this is function' ) } t() window .t()delete window .testconsole .log('删除windwos.test后test的值:' , test)console .log('删除windwos.test后windows.test的值:' , window .test)delete testconsole .log('删除test后test的值:' , test)console .log('删除test后windows.test的值:' , window .test)
根据以上测试结果,可以很清楚的发现:删除是不起作用的。
https://antmoe.gitee.io/project/2020/05/12/01_window对象.html
浏览器窗口的宽度和高度
https://antmoe.gitee.io/project/2020/05/12/02_图片跟随窗口变化.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > body { margin: 0; padding: 0; } img { width: 100%; } </style > </head > <body > <img id ="img" src ="https://ae01.alicdn.com/kf/H1d2dc39c58a84dc0960d4173b1bbc4643.jpg" alt ="" > <script > var img = document .getElementById('img' ) window .addEventListener('resize' , function ( ) { console .log(window .innerWidth, window .innerHeight) img.style.width = window .innerWidth + 'px' img.style.height = window .innerHeight + 'px' }) </script > </body > </html >
window.innerWidth等属性得值均为数字类型,作为宽度需加单位。例如window.innerWidth + 'px'
Windows对象与self属性Window对象的self属性返回当前浏览器窗口的只读属性。换句话讲,Self属性返回的是 Window对象的引用。
1 2 3 4 5 if (window .top != window .self) { console .log('这个窗口不是最顶层窗口' ) } else { console .log('这个窗口是最顶层窗口' ) }
open和closeopen[url]
参数参数打开地址。
close()
关闭当前页签
https://antmoe.gitee.io/project/2020/05/12/03_打开与关闭浏览器窗口.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <button id ="btn" > 按钮</button > <button id ="close" > 关闭</button > <script > var btn = document .getElementById('btn' ) var closebtn = document .getElementById('close' ) btn.addEventListener('click' , function ( ) { window .open('https://baidu.com' ) }) closebtn.addEventListener('click' , function ( ) { window .close() }) </script > </body > </html >
Navigator对象Navigator对象包含了一些有美浏览器状态的信息。可以通过window.navigator
属性得到 Navigator对象。
https://antmoe.gitee.io/project/2020/05/12/04_navigator.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <script > console .log('浏览器的代码名:' , navigator.appCodeName) console .log('浏览器的名称:' , navigator.appName) console .log('浏览器的平台和版本信息:' , navigator.appVersion) console .log('运行浏览器的操作系统平台:' , navigator.platform) console .log('运行浏览器的userAgent:' , navigator.userAgent) var ua = navigator.userAgent if (/windows/i .test(ua)) { console .log('当前是Windows系统' ) } else if (/mac/i .test(ua)) { console .log('当前是mac操作系统' ) } else if (/android/i .test(ua)) { console .log('当前是android操作系统' ) } else if (/iphone/i .test(ua)) { console .log('当前是iphone操作系统' ) } </script > </body > </html >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var ua = navigator.userAgentvar regex = /Chrome|Edge|Firefox/i var info = ua.match(regex)console .log(info)switch (info[0 ]) { case 'Chrome' : console .log('Chrome' ) break case 'Edge' : console .log('Edge' ) break case 'Firefox' : console .log('Firefox' ) break case 'msie' : console .log('msie' ) break default : console .log('你的浏览器是自创的吧?' ) }
1 2 3 4 5 6 7 8 var ua = navigator.userAgentif (/Chrome/i .test(ua) && /Edg/i .test(ua)) { console .log('Edge' ) } else if (/Firefox/i .test(i)) { console .log('Firefox' ) } else if (/Chrome/i .test(ua)) { console .log('Chrome' ) }
https://antmoe.gitee.io/project/2020/05/13/1.html
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <script > var ua = navigator.userAgent if (/Chrome/i .test(ua) && /Edg/i .test(ua)) { console .log('Edge' ) } else if (/Firefox/i .test(i)) { console .log('Firefox' ) } else if (/Chrome/i .test(ua)) { console .log('Chrome' ) } var regex = /Chrome|Edge|Firefox/i var info = ua.match(regex) switch (info[0 ]) { case 'Chrome' : console .log('Chrome' ) break case 'Edge' : console .log('Edge' ) break case 'Firefox' : console .log('Firefox' ) break case 'msie' : console .log('msie' ) break default : console .log('你的浏览器是自创的吧?' ) } </script > </body > </html >
History对象History对象包含用户在测览器中访问过的URL(网址)。
Location对象Location对象包含了浏览器的地址栏中的信息,该对象主要用于获取和设置地址。 Location对象很特别,因为该对象既是 Window对象的属性,又是 Document对象的属性。
属性/方法名称 描述 host
返回服务器名称和端口号 hostname
返回服务器名称 href
返回当前加载页面的完整URL pathname
返回当前URL中的目录和文件名 port
返回当前URL中的端口号 protocol
返回页面使用的网络协议 assign()
载入一个新的文档,作用和直接修改 Location相同 reload()
重新载入当前文档,作用和刷新按钮一样。参数为true时,则会强制清空缓存刷新页面 replace()
用新的文档替换当前文档(不会生成历史记录,不能使用回退按钮回退)
获取和设置地址
https://antmoe.gitee.io/project/2020/05/12/05_获取和设置地址.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <button id ="btn" > 按钮</button > <script > var btn = document .getElementById('btn' ) btn.addEventListener('click' , function ( ) { console .log('Location对象为:' , window .location) window .location = 'https://www.baidu.com' }) </script > </body > </html >
定时器定时器的具体方法由 Window对象提供,共有以下两种定时器
延迟执行:指的是指定程序代码在指定时间后被执行,而不是立即被执行 周期执行:指的是指定程序代码在指定时间为间隔,重复被执行。 目前,HTML页面中多数动态效果,以及动画效果等均由定时器内容完成。
延迟执行语法:var timeoutID=scope.setTimeout(function/code[,delay])
1 2 3 4 5 6 7 8 9 10 11 12 13 setTimeout (function ( ) { console .log('默认立即制行' ) }) setTimeout (function ( ) { console .log('延迟3秒执行' ) }, 3000 ) console .log('测试是否被延迟制行影响' )var t = setTimeout (function ( ) { console .log('test' ) }, 3000 ) clearTimeout (t)
以上代码的测试如图所示,可以看到延迟制行会打乱代码执行的顺序。即*延迟10秒执行*语句并不会导致下边的语句不执行。
https://antmoe.gitee.io/project/2020/05/13/01_延迟制行.html
周期执行语法:var timeoutID =scope.setInterval(function/code[,delay])
1 2 3 4 5 6 7 8 9 10 11 12 setInterval (function ( ) { console .log('默认立即制行' ) }) setInterval (function ( ) { console .log('延迟每3秒执行' ) }, 3000 ) console .log('测试是否被延迟制行影响' )var t = setInterval (function ( ) { console .log('test' ) }, 3000 ) clearInterval (t)
可以看到,几乎与延迟执行相同。执行顺序不会受到延迟的影响。清除定时器同样导致定时消失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function fun ( ) { console .log('这是递归写法' ) setTimeout (fun, 1000 ) } fun() (function ( ) { console .log('这是匿名函数写法' ) setTimeout (arguments .callee, 1000 ) })() (function fun1 ( ) { console .log('这是匿名写名字写法' ) setTimeout (fun1, 1000 ) })()
https://antmoe.gitee.io/project/2020/05/13/02_周期执行.html
动画方法requestAnimationFrame()window.requestAnimationFrame()
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
语法:window.requestAnimationFrame(callback);
callback
下一次重绘之前更新动画帧所调用的函数(即上面所说的回调函数)。该回调函数会被传入DOMHighResTimeStamp
参数,该参数与performance.now()
的返回值相同,它表示requestAnimationFrame()
开始去执行回调函数的时刻。
返回值
一个 long
整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame()
以取消回调函数。
1 2 3 4 5 6 7 8 9 10 11 console .log('this is a message ' )requestAnimationFrame(function ( ) { console .log('this is animation...' ) }) console .log('this is a message2 ' )
类似于延迟执行,执行一次就不会在执行了。
1 var requestAnimationFrame = webkitRequestAnimationFrame || mozRequestAnimationFrame || requestAnimationFrame
https://antmoe.gitee.io/project/2020/05/13/03_HTML5的动画方法.html
小案例以下两个案例需要注意的点就是周期函数的返回值需要在全局作用域声明。在时间内部进行赋值。
动态时间显示
整体来说,这是一个非常简单的小案例。其基本逻辑用一个周期定时器包裹起来即可。
https://antmoe.gitee.io/project/2020/05/13/04_动态时间显示.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > 动态显示时间</title > </head > <body > <button id ="start" > 开始显示</button > <button id ="stop" > 停止显示</button > <h2 id ="showtime" > </h2 > <script > var startBtn = document .getElementById('start' ) var stopBtn = document .getElementById('stop' ) var showtime = document .getElementById('showtime' ) var t; startBtn.addEventListener('click' , function ( ) { startBtn.setAttribute('disabled' , 'disabled' ) t = setInterval (function ( ) { var date = new Date () var hour = date.getHours() var minute = date.getMinutes() var second = date.getSeconds() var time = hour + ':' + minute + ':' + second showtime.textContent = time }) }) stopBtn.addEventListener('click' , function ( ) { startBtn.removeAttribute('disabled' ) clearInterval (t) }) </script > </body > </html >
方块移动
这个案例也很简单,同样是使用周期定时器。
https://antmoe.gitee.io/project/2020/05/13/05_方块自动移动.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > body { margin: 0; } #box { width: 50px; height: 50px; background-color: coral; position: absolute; top: 200px; left: 100px; } </style > </head > <body > <div id ="box" > </div > <script > var box = document .getElementById('box' ) var t var flag = false box.addEventListener('click' , function ( ) { if (!flag) { t = setInterval (function ( ) { var style = window .getComputedStyle(box) var left = parseFloat (style.left) left++ box.style.left = left + 'px' }, 10) flag = true } else { clearInterval (t) flag = false } }) </script > </body > </html >
小球自动向下移动在线地址:https://antmoe.gitee.io/project/2020/05/16/1_小球自动向下移动.html
创建DIV 通过不断改变其top属性,实现不断向下移动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > 小球自动向下移动</title > <style > body { margin: 0; } .box { width: 50px; height: 50px; background-color: coral; border-radius: 50%; position: relative; left: 400px; top: -50px; } </style > </head > <body > <script > var body = document .body function createBox ( ) { var WIDTH = window .innerWidth var div = document .createElement('div' ) div.setAttribute('class' , 'box' ) var random = Math .random() * (WIDTH - 50 ); div.style.left = random + 'px' body.appendChild(div) } function moveDown ( ) { var boxs = document .getElementsByClassName('box' ) for (var i = 0 ; i < boxs.length; i++) { var box = boxs[i] var style = window .getComputedStyle(box) var boxTop = parseFloat (style.top) boxTop++ box.style.top = boxTop + 'px' } } for (var i = 0 ; i < 10 ; i++) { createBox() } setInterval (function ( ) { moveDown() }, 100) </script > </body > </html >
菜单自动隐藏在线地址:https://antmoe.gitee.io/project/2020/05/16/2_菜单自动隐藏.html
与上一个类似,通过不断改变高度,实现不断变小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > body { margin: 0; } #menu { width: 100px; height: 300px; border: 1px solid black; position: absolute; left: 400px; top: 100px; } </style > </head > <body > <div id ="menu" > </div > <script > var menu = document .getElementById('menu' ) var flag = false var t = setInterval (function ( ) { var style = window .getComputedStyle(menu) var height = parseFloat (style.height) if (height <= 0 ) { menu.style.display = 'none' clearInterval (t) } else { height-- menu.style.height = height + 'px' } }, 100) </script > </body > </html >
键盘控制方块移动在线地址:https://antmoe.gitee.io/project/2020/05/16/3_键盘控制方块移动.html
常规的获取HTML元素
常规的监听键盘事件(keydown
)
水平移动
设置一个标志位,用于判断是向左还是向右。另外需要记录计时器的返回值。用于清除计时器。
垂直移动
与水平方向同理
空格停止(清除移动)
将记录的定时器编号清除即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > <style > body { margin: 0; } #box { width: 50px; height: 50px; background-color: coral; position: absolute; top: 200px; left: 100px; } </style > </head > <body > <div id ="box" > </div > <script > var html = document .documentElement var body = document .body var box = document .getElementById('box' ) var boxStyle = window .getComputedStyle(box) var leavel_flag, vertical_flag, vertical, level document .addEventListener('keydown' , function (e ) { var boxTop = parseFloat (boxStyle.top) var boxLeft = parseFloat (boxStyle.left) var key = e.code switch (key) { case 'ArrowUp' : vertical_flag = true vertical = vertical_move() break case 'ArrowDown' : vertical_flag = false vertical = vertical_move() break case 'ArrowLeft' : leavel_flag = false level = level_move() break case 'ArrowRight' : leavel_flag = true level = level_move() break case 'Space' : cancel() break } }) function cancel ( ) { if (vertical) { clearTimeout (vertical) } if (level) { clearTimeout (level) } } function level_move ( ) { cancel() if (leavel_flag) { return setInterval (function ( ) { box.style.left = (++boxLeft) + 'px' }, 50) } else { return setInterval (function ( ) { box.style.left = (--boxLeft) + 'px'