八、JavaScript BOM

189 阅读7分钟

BOM

浏览器对象模型(Browser Object Model,简称 BOM)是 JavaScript 的组成部分之一,BOM 赋予了 JavaScript 程序与浏览器交互的能力。

image.png

window对象

window 对象是 BOM 的核心,用来表示当前浏览器窗口,其中提供了一系列用来操作或访问浏览器的方法和属性。另外,JavaScript 中的所有全局对象、函数以及变量也都属于 window 对象,甚至我们前面介绍的 document 对象也属于 window 对象。

注意:如果 HTML 文档中包含框架(<frame> 或 <iframe> 标签),浏览器会为 HTML 文档创建一个 window 对象的同时,为每个框架创建一个额外的 window 对象。

image.png

窗口:简单理解就是window对象中包含各种属性和方法

image.png 全局变量是window的属性

  • 定义的全局变量都是window对象的属性
  • 多个js文件中,全局变量是共享的,共享全局作用域
  • window管理所有的全局变量和全局函数(是js特有的一种机制)

image.png 内置函数普遍是window的方法

  • 内置的函数基本都是window的方法

image.png 示例: image.png

窗口尺寸相关属性

image.png

获取浏览器内容区域宽高:(若有滚动条,则包含滚动条)

innerHeight

innerWidth

获取浏览器窗口外部宽高:返回浏览器窗口的完整宽高,包含工具栏与滚动条

outerHeight

outerWidth

若想获取窗口宽高且不包含滚动条 可使用document.documentElement.clientWidth document.documentElement 表示html根元素

clientWidth

  • 它是DOM的方法不是BOM的
  • clientWidth 属性是一个只读属性,它返回该元素的像素宽度

image.png clientHeight/clientWidth表示元素内部的高度/宽度。包含内边距,但不包含滚动条、边框、外边距。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 2000px;
        }
    </style>
</head>

<body>
    <script>
        console.log('窗口内宽' + innerWidth);
        console.log('窗口内高' + innerHeight);

        console.log('窗口外宽' + outerWidth);
        console.log('窗口外高' + outerHeight);

        console.log('不含滚动条的内宽' + document.documentElement.clientWidth);
        console.log('不含滚动条的内高' + document.documentElement.clientHeight);
    </script>
</body>

</html>

window.resize

  • 当窗口宽高发生变化时,就会触发此事件

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        window.onresize = function () {
            console.log('我的宽变为了' + document.documentElement.clientWidth);
            console.log('我的高变为了' + document.documentElement.clientHeight);
        };
    </script>
</body>

</html>

动画.gif

window.scrollY

  • window.scrollY是只读的

image.png

image.png

解决兼容性问题,可以用以下语句:

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 2000px;
        }
    </style>
</head>

<body>
    <script>
        window.onscroll = function () {
            var scrollTop = window.scrollY || document.documentElement.scrollTop;
            console.log(scrollTop);
        };
    </script>
</body>

</html>

Element.scrollTop

  • 获取滚动条的滚动距离
  • document.documentElement.scrollTop不是只读的,可以用来设置已卷过多少高度
  • 它也是个DOM方法
  • scrollTop 可以被设置为任何整数值

image.png

image.png 注意:当浏览器页面大小不正常,出现缩放或放大,就会出现小数的情况!

image.png

window.onscroll

image.png 可用于HTML的落地页,比如手机的官网,滚到什么位置出现什么图片。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            height: 2000px;
        }
    </style>
</head>

<body>
    <script>
        window.onscroll = function () {
            console.log('页面卷过了' + scrollY);
        };
    </script>
</body>

</html>

练习1

image.png

练习2

image.png

navigator对象

JavaScript navigator 对象中存储了与浏览器相关的信息,例如名称、版本等,我们可以通过 window 对象的 navigator 属性(即 window.navigator)来引用 navigator 对象,并通过它来获取浏览器的基本信息。

navigator 导航器、航行者(在这里跟这个翻译毫无相关)

image.png 由于 window 对象是一个全局对象,因此在使用window.navigator时可以省略 window 前缀,例如window.navigator.appName可以简写为navigator.appName

部分了解即可:

属性描述
appCodeName返回当前浏览器的内部名称(开发代号)
appName返回浏览器的官方名称
appVersion返回浏览器的平台和版本信息
cookieEnabled返回浏览器是否启用 cookie,启用返回 true,禁用返回 false
onLine返回浏览器是否联网,联网则返回 true,断网则返回 false
platform返回浏览器运行的操作系统平台
userAgent返回浏览器的厂商和版本信息,即浏览器运行的操作系统、浏览器的版本、名称

navigator.appName

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 浏览器名称
        console.log(navigator.appName);     // Netscape
    </script>
</body>

</html>

image.png

navigator.appVersion

version 版本

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
         // 浏览器版本
         console.log(navigator.appVersion);
    </script>
</body>

</html>

下面是 Chrome 浏览器的 image.png

navigator.userAgent

agent 代理人

navigator.userAgent属性返回浏览器的 User Agent 字符串,表示用户设备信息,包含了浏览器的厂商、版本、操作系统等信息。

下面是 Chrome 浏览器的userAgent

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 浏览器内核信息与版本
        console.log(navigator.userAgent);
    </script>
</body>

</html>

image.png 下面是 Firefox 浏览器的userAgent

image.png 通过userAgent属性识别浏览器,不是一个好办法。因为必须考虑所有的情况(不同的浏览器,不同的版本),非常麻烦,而且用户可以改变这个字符串。这个字符串的格式并无统一规定,也无法保证未来的适用性,各种上网设备层出不穷,难以穷尽。所以,现在一般不再通过它识别浏览器了,而是使用“功能识别”方法,即逐一测试当前浏览器是否支持要用到的 JavaScript 功能。

不过,通过userAgent可以大致准确地识别手机浏览器,方法就是测试是否包含mobi字符串。

var ua = navigator.userAgent.toLowerCase();

if (/mobi/.test(ua)) {
  // 手机浏览器
} else {
  // 非手机浏览器
}

如果想要识别所有移动设备的浏览器,可以测试更多的特征字符串。

/mobi|android|touch|mini/.test(ua)

navigator.platform

platform 计算机平台

Navigator.platform属性返回用户的操作系统信息,比如MacIntelWin32Linux x86_64等 。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 浏览器名称
        // console.log(navigator.appName);     // Netscape

        // 操作系统
        console.log(navigator.platform);
    </script>
</body>

</html>

image.png

navigator应用

识别用户浏览器品牌

当用户点击页面上的“点击获取浏览器信息”按钮时,页面会弹出窗口告知当前使用的浏览器是什么浏览器。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="button" value="点击获取浏览器信息" id="browser">

    <script>
        const browser = document.getElementById('browser');
        const info = navigator.userAgent;
        browser.addEventListener('click', () => {
            if (info.indexOf('Chrome') != -1) {
                alert('谷歌浏览器');
            } else if (info.indexOf('Firefox') != -1) {
                alert('火狐浏览器');
            } else if (info.indexOf('Edg') != -1) {
                alert('Edge');
            } else if (info.indexOf('Opera') != -1) {
                alert('Opera');
            } else if (info.indexOf('Safari') != -1) {
                alert('Safari');
            }
        }, false);
    </script>
</body>

</html>

image.png

history对象

JavaScript history 对象中包含了用户在浏览器中访问过的历史记录,其中包括通过浏览器浏览过的页面,以及当前页面中通过<iframe>加载的页面。我们可以通过 window 对象中的 history 属性来获取 history 对象,由于 window 对象是一个全局对象,因此在使用window.history时可以省略 window 前缀,例如window.history.go()可以简写为history.go()

image.png 下表中列举了 JavaScript history 对象中常用的方法及其描述:

方法说明
back()参照当前页面,返回历史记录中的上一条记录(即返回上一页),您也可以通过点击浏览器工具栏中的按钮来实现同样的效果。
forward()参照当前页面,前往历史记录中的下一条记录(即前进到下一页),您也可以通过点击浏览器工具栏中的按钮来实现同样的效果。
go()参照当前页面,根据给定参数,打开指定的历史记录,例如 -1 表示返回上一页,1 表示返回下一页。

这三个方法用于在历史之中移动。

  • History.back():移动到上一个网址,等同于点击浏览器的后退键。对于第一个访问的网址,该方法无效果。
  • History.forward():移动到下一个网址,等同于点击浏览器的前进键。对于最后一个访问的网址,该方法无效果。
  • History.go():接受一个整数作为参数,以当前网址为基准,移动到参数指定的网址,比如go(1)相当于forward()go(-1)相当于back()。如果参数超过实际存在的网址范围,该方法无效果;如果不指定参数,默认参数为0,相当于刷新当前页面。
history.back();
history.forward();
history.go(-2);

history.go(0)相当于刷新当前页面。

history.go(0); // 刷新当前页面

注意,移动到以前访问过的页面时,页面通常是从浏览器缓存之中加载,而不是重新要求服务器发送新的网页。

location对象

JavaScript location 对象中包含了有关当前页面链接(URL)的信息,例如当前页面的完整 URL、端口号等,我们可以通过 window 对象中的 location 属性来获取 location 对象。由于 window 对象是一个全局对象,因此在使用window.location时可以省略 window 前缀,例如window.location.href可以简写为location.href

image.png

window.location.href

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>点击跳转网页</title>
</head>

<body>
    <button>点击跳至百度</button>
    <script>
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function () {
            window.location = 'https://www.baidu.com';
        };
    </script>
</body>

</html>

window.location.reload( );

image.png

  • 重新加载当前页面
  • 参数加个true可以强制刷新
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>重新加载</title>
</head>
<body>
    <button>点击刷新</button>

    <script>
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function () {
            window.location.reload(true);
        }; 
    </script>
</body>
</html>

window.location.search

  • GET请求查询参数

image.png 返回一个 URL 中的查询部分,即 URL 中?及其之后的一系列查询参数。

在访问一个网站的时候,网址上可以用一个问号的形式来带一些参数给服务器的脚本程序,此时:a=1&b=2 中间有个&符号,表示我们要传两个参数,传给服务器,服务器就会收到这两个参数

BOM特效开发

返回顶部效果制作

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 3000px;
        }

        #backToTop {
            width: 50px;
            height: 50px;
            position: fixed;
            right: 100px;
            bottom: 100px;
            background-color: #F1F3F4;
            font-size: 18px;
            text-align: center;
            padding: 8px;
            cursor: pointer;
        }

        #backToTop:hover {
            background-color: #E9EBEC;
        }
    </style>
</head>

<body>
    <div id="backToTop">
        返回顶部
    </div>

    <script>
        // 点击返回顶部效果
        const backToTop = document.getElementById('backToTop');
        let timer;
        backToTop.addEventListener('click', () => {
            clearInterval(timer);  // 为防止疯狂点击出现的bug 设表先关
            timer = setInterval(() => {
                document.documentElement.scrollTop -= 200;
                if (document.documentElement.scrollTop <= 0) {
                    clearInterval(timer);
                }
            }, 20);
        }, false);
    </script>
</body>

</html>

动画.gif

楼层导航效果

image.png 我们先来了解一下offsetTop属性,它可以获取 div 元素的顶部偏移量

image.png 使用这个属性的时候,所有的祖先元素不要有定位,有定位就不好用了

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
            list-style: none;
        }

        .lead {
            position: fixed;
            right: 100px;
            top: 50%;
            width: 50px;
            height: 83px;
            margin-top: -40px;
            background-color: rgba(0, 0, 0, .2);
            color: #5A88FD;
            text-align: center;
            cursor: pointer;
        }

        .lead li.current {
            background-color: rgba(0, 0, 0, .2);
            color: #FC6B58;
        }
    </style>
</head>

<body>
    <!-- 右侧导航 -->
    <div class="lead">
        <ul id="list">
            <li class="current" data-n="娱乐">娱乐</li>
            <li data-n="视频">视频</li>
            <li data-n="音乐">音乐</li>
            <li data-n="新闻">新闻</li>
        </ul>
    </div>

    <!-- 内容区域 -->
    <div class="wrapper">
        <div class="contents" style="height: 500px; font-size: 30px;" data-n="娱乐">娱乐</div>
        <div class="contents" style="height: 800px; font-size: 30px;" data-n="视频">视频</div>
        <div class="contents" style="height: 500px; font-size: 30px;" data-n="音乐">音乐</div>
        <div class="contents" style="height: 900px; font-size: 30px;" data-n="新闻">新闻</div>
    </div>

    <script>
        const list = document.getElementById('list');   // ul元素
        const contents = document.getElementsByClassName('contents');
        const rightOptions = document.querySelectorAll('#list li');     // 所有的li元素

        // 点击跳转
        list.addEventListener('click', (e) => {
            if (e.target.tagName.toLowerCase() == 'li') {
                const n = e.target.getAttribute('data-n');  // 点击谁获取谁的data-n属性
                const contentsHeight = document.querySelector('.contents[data-n=' + n + ']').offsetTop;  // 选中data-n等于被点击项的data-n的DOM元素,并获取它到顶部的距离
                document.documentElement.scrollTop = contentsHeight;    // 进行跳转翻动屏幕
            }
        }, false);

        // 为当前的楼层保持有current css属性
        let offsetTopArr = [];      // 将每个内容的scrollTop值推入数组中,为显示楼层数
        for (var i = 0; i < contents.length; i++) {
            offsetTopArr.push(contents[i].offsetTop);
        }
        offsetTopArr.push(Infinity);    // 推入Infinity为后面的比较使用
        let nowFloor = -1;  // 节流,表示当前楼层,设置成负1,为了一上来就触发

        window.addEventListener('scroll', () => {
            let scrollTop = document.documentElement.scrollTop;     // 获取当前的滚动值
            for (var i = 0; i < offsetTopArr.length; i++) {
                if (scrollTop >= offsetTopArr[i] && scrollTop < offsetTopArr[i + 1]) {
                    // console.log(i);     // 当前所在楼层数
                    break;
                }
            }

            if (nowFloor != i) {
                nowFloor = i;
                // console.log(i);
                for (var j = 0; j < rightOptions.length; j++) {
                    if (j == i) {
                        rightOptions[j].className = 'current';
                    } else {
                        rightOptions[j].className = '';
                    }
                }
            }

        }, false);
    </script>

</body>

</html>

动画.gif

舞台再大,你不上台,永远是个观众。平台再好,你不参与,永远是局外人。能力再大,你不行动,只能看别人成功!没有人会关心你付 出过多少努力,撑得累不累,摔得痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷。