【前端】前端三要素之BOM

写在前面:本文仅包含BOM内容,JavaScript传送门在这里,DOM传送门在这里

本文内容是假期中刷的黑马Pink老师视频(十分感谢Pink老师),原文保存在个人的GitLab中,如果需要写的网页内容信息等可以评论联系我,若是编辑博文中出现了忘记上传的图片或者错位的图片欢迎评论区指正。写作不易,欢迎点赞、收藏+关注。

文章目录

BOM 导论

什么是BOM

BOM(Browser Object Model)浏览器对象模型 ,他提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window

BOM 是由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。

BOM缺乏标准,JavaScript语法的标准化组织室ECMA,DOM的标准化组织是W3C,BOM最初是Netscape(网景公司)浏览器标准的一部分。

DOM 与 BOM 对比

DOM BOM
文档对象模型 浏览器对象模型
DOM就是把「文档 」当做一个「对象」来看待 把「浏览器 」当做是一个「对象」来看待
DOM的顶级对象是document BOM的顶级对象是window
DOM的主要学习是操作页面元素 BOM学习的事浏览器窗口交互的一些对象
DOM是W3C标准 BOM是浏览器厂商在各自浏览器上定义的,兼容性较差

BOM 与 DOM 的关系

一些描述

  1. 我们常用的document.xxx(如document.quertSelector(),举例在下面的代码段) ,完整的写法是 window.documnt.xxx
  2. 如果我们在script中定义了一个全局变量(以num举例,如下代码),那么我们真正的调用方式其实是window.num
  3. window包含一些方法,如我们常用的alert,我们也可以在前面加上window.使用,示例如下
html 复制代码
<body>
    <div>我是Jim.kk</div>
    <script>
        // 1. 方法调用的省略写法
        document.querySelector('div');
        // 2. 方法调用的完整写法
        window.document.querySelector('div');
        
        var num = 10;
        // 3. 全局变量的省略写法
        console.log(num);
        // 4. 全局变量的完整写法
        console.log(window.num);
        
        // BOM的alert方法
        window.alert('我是Jim.kk');
    </script>
</body>

窗口加载事件

使用window.onload来改变script标签的位置

window.onload,是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、css文件等),就调用处理函数。

一般来说,我们需要按照先写标签,然后将script标签写在标签的下面的方式,但是我们可以通过window.onload来改变script标签的位置,因为这个方法会在页面加载完毕之后才执行,所以执行这个方法的时候,页面中的DOM元素已经全部被渲染了,请看下面示例。

html 复制代码
<body>
    <script>
        window.onload = function () {
            var btn = document.querySelector('button');
            btn.addEventListener('click',function () {
                alert('你点我?');
            })
        }
    </script>
    <button>点击</button>
</body>

在以上代码中,我们没有按照之前的标准,将script标签写在button标签下面,但是依旧是可用的。

通过监听事件的方式写多个load

如果页面中存在多个window.onload,会以最后一个为准(最后一个会覆盖前面的事件)

这是传统事件存在的弊端,为了解决这一问题,我们可以使用监听事件替换window.onload,请看下面示例。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面加载事件|侦听</title>
    <script>
        window.addEventListener('load',function () {
            var btn2 = document.querySelector('#btn2');
            btn2.onclick = function () {
                alert('点击了按钮2');
            }
        })
    </script>
</head>
<body>
    <script>
        window.addEventListener('load',function () {
            var btn1 = document.querySelector('#btn1');
            btn1.onclick = function () {
                alert('点击了按钮1');
            }
        })
    </script>
    <button id="btn1">btn1</button>
    <button id="btn2">btn2</button>
</body>
</html>

上面代码中,我们添加了两个window的侦听事件,验证得知两个侦听事件都生效了。

通过DOMContentLoaded事件来获取窗口加载事件

javascript 复制代码
document.addEventListener('DOMContentLoaded',function () {})

DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表、图片、flash等。IE9以上才支持。

若果页面的图片非常多,那么推荐使用这种方式。

html 复制代码
<body>
    <script>
        window.addEventListener('load',function () {
            alert(22);
        })
        document.addEventListener('DOMContentLoaded',function () {
            alert(33);
        })
    </script>
</body>

以上代码一定是先弹出33再弹出22的,因为DOMContentLoaded事件只需要DOM元素加载完毕就可以执行,但是load需要加载完成图片等各种信息之后才执行。

窗口大小变化事件

javascript 复制代码
window.onresize = functoin(){}
window.addEventListener('resize',function () {} )

只要窗口大小发生变化,就会触发里面的处理函数。

html 复制代码
<body>
    <button>当宽度小于900px的时候,我就消失啦</button>
    <script>
        window.addEventListener('resize',function () {
            // console.log('变化了');
            // console.log('内高:'+window.innerHeight+'\t内宽' + window.innerWidth);
            var btn = document.querySelector('button');
            if ( window.innerWidth < 900 ) {
                btn.style.display = 'none';
            } else {
                btn.style.display = 'block';
            }
        })
    </script>
</body>

以上代码的执行效果:当我们改变浏览器框的大小的时候,当宽度小于900px,这个button按钮就会消失。

这种效果常用在一些页面元素渲染上,比如原本有四个列的某种元素,但是当页面较窄的时候,我们会隐藏其中某个列,以保证页面的正常显示。

回调函数

setTimeout()这个函数我们称为回调函数 callback

普通函数是按照顺序直接调用的,但是回调函数不按顺序来,比如定时器函数需要等待时间,等其它事情干完或者到了调用条件才会调用这个函数。

之前学习的onclick函数或者element.addEventListener('xxx',fun)里面的函数也是回调函数。

setTimeout 定时器

setTimeout() 定时器

window.setTimeout(调用函数,[延迟的毫秒数]);

  1. window在调用的时候可以省略
  2. 单位是毫秒,省略是0秒,也就是立马执行
  3. 这个调用函数可以直接写函数,还可以写函数名(不需要带括号)

当延迟的毫秒数到了,就去执行函数。

定时器函数的使用

通过匿名函数调用
html 复制代码
<body>
    <script>
        // 单位是毫秒,省略是0秒,也就是立马执行
        setTimeout(function () {
            alert('我是Jim.kk');
        },2000);
    </script>
</body>

以上代码在页面加载出来两秒后会跳出弹窗提示。

通过函数名调用
html 复制代码
<body>
    <script>
        function fun() {
            alert('我是Jim.kk');
        }
        setTimeout(fun,2000);
    </script>
</body>
通过函数名字符串调用 | 不推荐

函数名字符串必须要加括号

^以下代码与上面两个代码段执行无异,不多赘述^

html 复制代码
<body>
    <script>
        function fun2() {
            alert('我是Jim.kk');
        }
        setTimeout('fun2()',2000);
    </script>
</body>
区分不同的定时器

^以下代码会在页面加载出来后的两秒在控制台输出一句话,页面加载好的5秒后又会输出一句话。^

html 复制代码
<body>
    <script>
        function fun3() {
            console.log('我是Jim.kk');
        }
        var timer1 = setTimeout(fun3,2000);
        var timer2 = setTimeout(fun3,5000);

    </script>
</body>

清除定时器

使用clearTimeout(定时器名称)函数可以清除定时器,请看如下代码

注意,括号内是定时器的名称,不是字符串

html 复制代码
<body>
    <button>点我清除定时器</button>
    <script>
        var btn = document.querySelector('button');
        var timer1 = setTimeout(function () {
            alert('我是Jim.kk');
        },5000);
        btn.onclick = function () {
            clearTimeout(timer1);
        }
    </script>
</body>

^以上代码在弹窗出现之前若是点击了按钮,弹窗则永远也不会跳出来。^

setInterval() 定时器

  1. window.setInterval(回调函数,[间隔毫秒数])
  2. setTimeout()不同的是,setTimeout只会执行一次,但是setInterval会循环执行

setInterval() 的使用

html 复制代码
<body>
    <script>
        setInterval(function () {
            console.log('我是Jim.kk');
        },1000)
    </script>
</body>

以上代码每过一秒就会输出一次我是Jim.kk;

清除定时器 setInterval()

^以下代码点击开始后开始循环(1秒1次)输出当前时间戳,点击停止后停止输出。^

html 复制代码
<body>
  <button id="begin">开始</button>
  <button id="stop">停止</button>
  <script>
    var begin = document.querySelector('#begin');
    var stop = document.querySelector('#stop');
    var timer = null;
    begin.addEventListener('click',function () {
      setInterval(function () {
        console.log(+new Date());
      },1000);
    })
    stop.addEventListener('click',function () {
      clearInterval(timer);
    })
  </script>
</body>

this指向问题

总结起来一句话,谁调用,就指向谁。

  1. 全局作用下指向window
  2. 全局作用域的方法中指向window(因为是window调用的方法)
  3. 在定时器中指向window(因为定时器也是window调用的)
  4. 在对象中指向这个对象
  5. 在事件中指向被触发事件(如被点击)的元素(如按钮)
  6. 如果在按钮点击事件中调用计时器,计时器中指向的还是window
  7. 构造函数,指向的是实例对象
  1. 全局作用域下指向window
html 复制代码
<body>
    <script>
        console.log(this); // window
    </script>
</body>
  1. 全局作用域的方法中指向window
html 复制代码
<body>
    <script>
        function fun(){
            console.log(this);
        }
        fun(); // window
        window.fun(); // 这行代码与上一行等效
    </script>
</body>
  1. 在定时器中指向window
html 复制代码
<body>
    <script>
        setTimeout(function () {
            console.log(this); // window
        },1000);
    </script>
</body>
  1. 在对象中指向这个对象
html 复制代码
<body>
    <script>
        var o = {
            sayHi: function () {
                console.log(this); // o对象
            }
        }
        o.sayHi(); // o 对象
    </script>
</body>
  1. 在事件中指向被触发事件(如被点击)的元素(如按钮)
html 复制代码
<body>
    <button>点我</button>
    <script>
        var btn = document.querySelector('button');
        btn.onclick = function () {
            console.log(this); // <button>点我</button>
        }
    </script>
</body>
  1. 如果在按钮点击事件中调用计时器,计时器中指向的还是window
html 复制代码
<body>
    <button>点我</button>
    <script>
        var btn = document.querySelector('button');
        btn.onclick = function () {
            setTimeout(function () {
                console.log(this); // 指向 window
            },1000)
        }
    </script>
</body>
  1. 构造函数,指向的是实例对象
html 复制代码
<body>
    <script>
        function Fun() {
            console.log(this); // 指向的是fun实例对象
        }
        
        var fun = new Fun();
    </script>
</body>

location对象

location相关属性与方法

window对象给我们提供了一个location属性用于获取或设置窗体的URL ,并且可以用于解析URL 。因为这个属性返回的是一个对象,所以我们将这个属性称为location对象

location对象属性 返回值
location.href 获取或者设置整个URL
location.host 返回主机(域名)
location.port 返回端口号,如果未写返回空字符串
location.pathname 返回路径
location.search 返回参数
location.hash 返回片段#后面内容,常见于链接、锚点
location方法 行为描述
location.assign() 记录历史并跳转
location.replace() 不记录历史并跳转
location.reload() 重载页面,如果页面里参数是true,则强制刷新,强制刷新不会保留缓存(Ctrl+F5

可以直接在控制台输入location点回车,查看当前的location。

下面实现一个点击按钮后五秒钟倒计时跳转百度的示例

html 复制代码
<body>
    <button>点我跳转</button>
    <div></div>
    <script>
        var btn = document.querySelector('button');
        var div = document.querySelector('div');
        btn.onclick = function () {
            var timer = 5;
            div.innerText = '将在' + timer +'秒后跳转至百度';
            setInterval(function (){
                timer -- ;
                if(timer === 0){
                    location.href = 'https://baidu.com';
                } else {
                    div.innerText = '将在' + timer +'秒后跳转至百度';
                }
            },1000);
        }
    </script>
</body>

以上代码在点击按钮后,会开始执行计时器,然后div中每次显示倒计时的时间,等时间到了,就会跳转到百度。

navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值。

输出用户当前使用的客户端

javascript 复制代码
alert(navigator.userAgent);

历史记录

forward() 前进 与 back() 后退

可以在括号中写上数字,控制前进后退的步数
要有历史记录(或者前进记录)的情况下才可以调用

以下写两个页面演示一下,命名如下:

  1. index页:``
  2. home页:_BOM_06.6-home.html
html 复制代码
<body>
    <a href="_BOM_07.2-home.html">前往Home页</a>
    <button>点我下一步</button>
    <script>
        var btn = document.querySelector('button');
        btn.onclick = function (){
            history.forward();
        }
    </script>
</body>
html 复制代码
<body>
    <a href="_BOM_07.1-index.html">前往首页</a>
    <button>点我返回</button>
    <script>
        var btn = document.querySelector('button');
        btn.onclick = function (){
            history.back();
        }
    </script>
</body>

这样的话两个页面分别就有两个标签,在首页点击a标签之后进入到home页面,这时候就产生了历史记录,可以点击返回按钮返回,返回之后又可以点击下一步再次进入到首页。

可以在括号中写上数字,控制前进后退的步数

页面偏移量 offsetLeft 与 offsetTop

style的区别

  1. offset系列的返回值都是没有单位的,是一个纯数字,style可以
  2. offset不可以被赋值,style可以
  3. offset返回的宽度等信息包含paddingborderwidth的宽度和高度,style不包含

offsetLeftoffsetTop

  1. 返回的都是距离可视窗口(页面部分)左上角的定位
  2. 返回值是一个数字
  3. 不可以进行赋值

offsetWidthoffsetHeight

  1. 返回的是宽度和高度
  2. 包含paddingborderwidth的宽度和高度
  3. 如果元素的宽度是xx%,那么当浏览器大小发生变化时,该值也会动态发生变化
  4. 返回值是一个数字

offsetParent

  1. 返回的是父元素
  2. 如果父亲不带有定位,那么则会逐级向上找,直到找到带定位的元素(这是与fatherNode的区别)

以下代码的页面显示效果与控制台输出效果如下图所示:

html 复制代码
<head>
    <meta charset="UTF-8">
    <title>页面偏移量</title>
    <style>
        body {
            width: 100%;
            height: 100%;
            margin: 0;
        }
        #father {
            position: relative;
            margin-top: 400px;
            margin-left: 800px;
            background: antiquewhite;
            width: 200px;
            height: 200px;
            border: .1px solid red;
        }
        #son {
            background: aqua;
            width: 100px;
            height: 100px;
            margin: 50px;
        }
    </style>
</head>
<body>
    <div id="father">
        <div id="son"></div>
    </div>
    <script>
        var father = document.querySelector('#father');
        var son = document.querySelector('#son');
        console.log(father.offsetLeft); // 800
        console.log(father.offsetTop);  // 400

        // 页面的宽度包含padding、border、width
        // 如果高度或者宽度是100%,那么当浏览器窗口大小变化的时候,这个值也会动态变化
        console.log(father.offsetWidth); // 200
        console.log(father.offsetHeight);  // 200

        // 如果father带有定位(position: relative;),那么将会显示father,如果直接的father不带有定位,则逐级向上寻找,直到找到带定位的
        console.log(son.offsetParent);
    </script>
</body>

client 系列

与offset最大的区别就是不包含边框

client系列属性 说明
element.clientTop 返回元素上边框的大小
element.clientLeft 返回元素左边框大小
element.clientWidth 返回自身包含padding、内容区的宽度,不包含边框,返回一个数值
element.clientHeight 返回自身包含padding、内容区的高度,不包含边框,返回一个数值
html 复制代码
<head>
    <meta charset="UTF-8">
    <title>client | 系列页面偏移量</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background: pink;
            border: 3px solid red;
            margin: 200px auto;
        }
    </style>

</head>
<body>
    <div></div>
    <script>
        var div = document.querySelector('div');
        console.log(div.clientHeight);  // 200
        console.log(div.clientWidth);   // 200
        console.log(div.clientTop);     // 3
        console.log(div.clientLeft);    // 3
    </script>
</body>

注意:无法获取下边框与右边框大小

scroll系列

scroll 属性

scroll 系列与offset系列和client系列最大的区别在于,如果元素内部的内容溢出了(如文字长度溢出或者内部div高度比当前元素高),那么scroll显示的实际的高度和宽度。

scorll系列属性 说明 备注
element.scrollTop 返回被卷去的上侧距离 返回值不带参数
element.scrollLeft 返回被卷去的左侧距离 返回值不带参数
element.scrollWidth 返回自身实际的宽度,不含边框 返回值不带参数
element.scrollHeight 返回自身实际的高度,不含边框 返回值不带参数

横向超出一样的道理

scroll 方法

javascript 复制代码
div.addEventListener('scroll',function (){
    console.log(div.scrollTop)
})

当滚动条发生变化时触发
注意:当调用对象是document的时候,要使用window.pageYOffset,如果要计算左侧则是window.pageXOffset

简单解释一下:我们上面说的scroll系列应对的是页面内的元素,比如页面内有一个小div内部又套了一个div,这时候要使用scroll系列,但是操作document的时候,操作的是整个页面,我们要使用windows.pageX/YOffset

移动端事件

触屏touch事件 说明
touchstart 手指触摸到一个DOM元素时触发
touchmove 手指在一个DOM元素上滑动时触发
touchend 手指离开一个DOM元素时触发

示例:写一个DIV,在移动端分别进行手指触摸、手指移动和手指离开操作

html 复制代码
<head>
    <meta charset="UTF-8">
    <title>移动端touchstart事件</title>
    <style>
        div {
            width: 300px;
            height: 300px;
            background: pink;
        }
    </style>
</head>
<body>
    <div></div>
    <script>
        var div = document.querySelector('div');
        div.addEventListener('touchstart',function (e) {
            console.log('手指摸上去了');
        })

        div.addEventListener('touchmove',function (e) {
            console.log('手指正在移动');
        })

        div.addEventListener('touchend',function (e) {
            console.log('手指离开了');
        })
    </script>
</body>

以上代码的测试结果如下图所示:

^如果要自己测试,记得F12并按照红色箭头方向打开移动端模式。^

触摸时间对象

  1. touchs:正在触摸屏幕的所有手机的列表(是一个列表,由于可以多指触摸,所以是一个列表)
  2. targetTouches:正在触摸当前DOM元素伤的手指列表
  3. changedTouches:手指状态发生了改变的列表,从无到有,从有到无的变化

本地存储

  1. sessionStorage:生命周期为关闭浏览器窗口,同页面下数据可以共享(关闭页面或新建页面后失效),以键值对存储,存储空间约5M
  2. sessionStorage:多页面(同一浏览器内)共享(重启浏览器依旧生效),不同页面的数据可以共享,以键值对存储,存储空间约20M

sessionStorage

sessionStorage方法 说明 备注
setItem('key',value) 存储一个数据 存储空间约5M
getItem('key') 使用key获取一个数据
removeItem('key') 删除一个数据
clear() 清空所有数据

localStorage

localStorage方法 说明 备注
setItem('key',value) 存储一个数据 存储空间约20M
getItem('key') 使用key获取一个数据
removeItem('key') 删除一个数据
clear() 清空所有数据
相关推荐
陈王卜2 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
景天科技苑10 分钟前
【vue3+vite】新一代vue脚手架工具vite,助力前端开发更快捷更高效
前端·javascript·vue.js·vite·vue项目·脚手架工具
小行星12521 分钟前
前端预览pdf文件流
前端·javascript·vue.js
小行星12528 分钟前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
Lysun00137 分钟前
[less] Operation on an invalid type
前端·vue·less·sass·scss
J总裁的小芒果1 小时前
Vue3 el-table 默认选中 传入的数组
前端·javascript·elementui·typescript
Lei_zhen961 小时前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron
咖喱鱼蛋1 小时前
Electron一些概念理解
前端·javascript·electron
yqcoder1 小时前
Vue3 + Vite + Electron + TS 项目构建
前端·javascript·vue.js
鑫宝Code1 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架