JS基础 - BOM

78 阅读8分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

浏览器对象模型(Browser Object Model 简称BOM) 由浏览器提供的用于处理文档(document)之外的所有内容的其他对象

比如navigator、location、history等对象

浏览器本身作为一个应用程序需要对其本身进行操作,所以通常浏览器会有对应的对象模型(BOM,Browser Object Model)

可以将BOM看成是连接JavaScript脚本与浏览器窗口的桥梁

BOM组成

对象说明
window包括全局属性、方法,控制浏览器窗口相关的属性、方法
location浏览器连接到的对象的位置(URL)
history操作浏览器的历史
navigator用户代理(浏览器)的状态和标识
screen屏幕窗口信息

window

window对象有双重角色,它既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象

  1. 全局对象
// 在ECMA规范中,所有的JS宿主环境都需要存在一个全局对象
// 在浏览器中是window对象
// 在node中是global对象
// 在worker中是self对象
// 所以为了统一这些对象的名称,规范中定义了全局对象名称为globalThis
// 即 window === globalThis -> true
console.log(window === globalThis)

在浏览器中,全局对象所对应的那个对象就是window对象

  • 在window对象上的所有属性都可以被访问
  • 使用var定义的变量会被添加到window对象中
  • window默认给我们提供了全局的函数和类:setTimeout、Math、Date、Object等
  1. 浏览器窗口对象

window同时兼顾了作为浏览器窗口对象的功能, 作为浏览器窗口时,提供了对浏览器操作的相关的API

属性

属性名属性值
outerWidth浏览器的宽度
outerHeight浏览器的高度
screenX浏览器左边距离显示器左边的距离
screenY浏览器顶部距离显示器顶部的距离
scrollX浏览器水平滚动条滚到的距离
scrollY浏览器垂直滚动条滚到的距离

事件

事件说明
focus浏览器获取焦点
blur浏览器失去焦点
open打开一个新网页
close关闭使用open方法开启的新网页
hashChangeurl的hash值发生了改变
load页面所有内容加载完毕
DOMContentLoaded页面DOM加载完毕,外部资源没有加载完毕

window也是继承自EventTarget的

所以window对象也包含从EventTarget继承过来的方法,addEventListener、removeEventListener、dispatchEvent方法

// 打开一个新的窗口 默认打开方式为_blank
window.open('https://www.google.com')

// 第一个参数为新窗口的URL地址
// 第二个参数为新窗口的打开方式
// 默认的打开方式是_blank (这和a元素默认使用_self打开是不同的)

// 注意: 如果第二个窗口的打开方式是_self的时候
// 是在当前窗口开启一个新页面,但当前窗口并不是使用window.open打开的窗口
// 所以在当前窗口使用window.close()方法是无法关闭窗口的

// 方法的返回值是新窗口所对应的window对象
const newWindow = window.open('https://www.google.com', '_blank')

// 关闭使用window.open方法开启的新窗口
window.close()
newWindow.close()

我们可以使用postMessage方法来在跨域的窗口中进行安全的数据通信

发送数据的窗口地址 --- http://localhost:8080

<!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>
    <iframe
      id="foo"
      src="http://127.0.0.1:5501/demo.html"
      frameborder="0"
    ></iframe>

    <button id="btn">click me</button>

    <script>
      // 通过iframe的contentWindow属性,我们可以获取到iframe所嵌入的那个窗体对象
      const iFrame = document.getElementById('foo').contentWindow
      const btnEl = document.getElementById('btn')

      btnEl.addEventListener('click', () => {
        // 通过获取的窗体对象向另一个页面发送数据
        // 参数1 - 需要发生的数据
        // 参数2 - 发送给那个页面
        //   --- 对应的页面 需要和窗体对象处于同源环境下
        iFrame.postMessage(
          {
            name: 'Klaus'
          },
          'http://127.0.0.1:5501/demo.html'
        )
      })
    </script>
  </body>
</html>

接收数据的页面地址 - http://127.0.0.1:5501/index.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>
</head>
<body>
  <h2></h2>

  <script>
    // 监听message事件,当另一个页面通过postMessage方法向该页面发送信息的时候, 该事件会被对应触发
    window.addEventListener('message', e => {
      // e.origin存储的是数据发送源所对应的域名, 可以用来进行安全性校验
      if (e.origin === 'http://localhost:8080') {
        // 数据源所发送过来的信息会被存储咋e.data中
        document.querySelector('h2').textContent = e.data.name ?? 'Hello World'
      }
    })
  </script>
</body>
</html>

location

location对象用于表示window上当前链接到的URL信息

LCkOuy.png

LCkZBr.png

在早期的URL中,可能存在username,password等相关信息

但是在现代浏览器中,这些信息已经被很多浏览器所禁用

属性说明示例
href当前window对应的超链接URL, 整个URLhttp://127.0.0.1:5501/index.html?name=klaus&age=23#foo
protocol当前的协议
带最后的 : 后缀
http:
host主机地址
host = hostname + port
127.0.0.1:5501
hostname主机地址(不带端口)127.0.0.1
port端口
不带 :前缀
5501
origin源地址
origin = protocol + host
origin = protocol + hostname + port
origin属性是唯一一个只读属性
http://127.0.0.1:5501
pathname路径
带 / 前缀
/demo/index.html
search查询字符串
带 ?前缀
?name=klaus&age=23
hash哈希值(又名片段值)
带 # 前缀
#hash
方法说明
assign跳转到一个新URL地址
会在浏览记录中进行记录
只能在当前页面中进行打开
replace跳转到一个新URL地址
不会在浏览记录中进行记录
只能在当前页面中进行打开
reload重新加载页面
Firefox支持传入一个Boolean类型的参数用于判断是否强制刷新,但这并不属于ECMA标准中

URLSearchParams

URLSearchParams 定义了一些实用的方法来处理 URL 的查询字符串

可以将一个字符串转化成URLSearchParams类型, 也可以将一个URLSearchParams类型转成字符串

const queryStr = '?name=Klaus&age=23'

// 将 查询字符串 转换为URLSearchParams对应的实例对象
// 参数为对应的查询参数字符串 (对于#,?, /, : 这些前缀和后缀,在设置的时候,可以省略不携带)
const searchParams = new URLSearchParams(queryStr)

// 将URLSearchParams对应的实例对象 转换为 字符串形式的查询参数
// 转换后的结果不带?前缀
console.log(searchParams.toString()) // => name=Klaus&age=23
属性说明
get获取搜索参数的值
如果获取的值不存在 则返回null
如果存在多个结果,则返回第一个结果
set设置一个搜索参数和值
无则添加,有则覆盖
append追加一个搜索参数和值
无则添加,有则新加一个,不会覆盖原本的值
getAll获取搜索参数的值
如果存在多个结果,则返回这些结果组成的数组
如果只存在一个结果,则返回这个结果所组成的数组
has判断是否有某个搜索参数

URL编码

在一个url中只能使用英文字母、阿拉伯数字和某些标点符号, 所以如果URL中有汉字,就必须编码后使用

浏览器默认情况下,会对URL中的特殊字符进行编码,但是在不同的操作系统、不同的浏览器、不同的网页字符集,

其采用的编码方式是完全不同的,所以这将导致完全不同的编码结果

因此浏览器提供了对URL的编码和解码方法来对url中的特殊字符进行编码和解码

也就是在传输之前手动进行编码和解码,而不是交给浏览器在进行编解码,保证服务器和浏览器得到的数据格式是一致的

encodeURIComponent / decodeURIComponent

使用encodeURIComponent进行编码的URL地址,必须通过decodeURIComponent方法进行解码

encodeURIComponent和decodeURIComponent方法所采用的编码为utf-8编码

// 一个中文 对应 三位编码
// 即 上 ->  %E4%B8%8A
//    海 ->  %E6%B5%B7
//    市 ->  %E5%B8%82

// 编码
const code = encodeURIComponent('上海市')  // => %E4%B8%8A%E6%B5%B7%E5%B8%82

// 解码
console.log(decodeURIComponent(code)) // => 上海市

encodeURI / decodeURI

使用encodeURI进行编码的URL地址,必须通过decodeURI方法进行解码

encodeURI和decodeURI方法所采用的编码为utf-8编码

const url = 'http://www.example.com/demo/some other thing'

// encodeURI 对于特殊字符的判断范围为整个URL中的特殊字符
// 所以encodeURI认为 : / ? # 等不是特殊字符 因为他们在URL中有特殊意义
// 所以encodeURI方法  不会对这些字符进行编码
console.log(encodeURI(url))
// => http://www.example.com/demo/some%20other%20thing

// encodeURIComponent 对于特殊字符的判断范围为 查询字符串中的特殊字符
// 所以 encodeURIComponent 对于URL中特殊字符的判断 比encodeURI的更大
// encodeURIComponent 会认为: / ? # 等都属于特殊字符,因为他们在查找字符串中没有特殊意义
// 所以encodeURI方法  会对这些字符进行编码
console.log(encodeURIComponent(url)) 
// => http%3A%2F%2Fwww.example.com%2Fdemo%2Fsome%20other%20thing

// 所以如果需要对整个URL进行编码的时候,推荐使用 encodeURI
// 而如果只需要对查询字符串进行编码的时候,推荐使用 encodeURIComponent

history

history对象允许我们访问浏览器曾经的会话历史记录

history和hash目前是vue、react等框架实现路由的底层原理

使用history和hash都可以实现 `在页面不发生刷新的情况下,在形式上对URL进行修改

属性说明
length会话中的记录条数(可以回退数 + 当前页 + 可以前进数)
state当前保留的状态值,由另一个页面通过pushState或replaceState方法进行传入
方法说明
pushState打开一个指定的地址
replaceState打开一个新的地址,并且使用replace
back返回上一页,等价于history.go(-1)
forward前进下一页,等价于history.go(1)
go加载历史中的某一页
参数表示的是页面个数
大于0 表示前进
小于0 表示倒退
等于0 表示页面刷新
// 参数1 - 需要传递给另一个页面的数据状态
// 参数2 - 另一个页面的标题,大多数浏览器不支持,未来可能支持,推荐使用空字符串进行占位
// 参数3 - 另一个页面的地址 -- 必须是一个同源地址
history.pushState({
  name: 'Klaus'
}, '', '/demo.html')

navigator

navigator 对象表示用户代理的状态和标识等信息

// 获取当前用户代理信息 -- 在浏览器中就是浏览器基本信息
console.log(navigator.userAgent)

screen

screen主要记录的是浏览器窗口外面的客户端显示器的信息, 也就是用于获取用户显示器相关信息

属性说明
width屏幕的逻辑像素宽度
height屏幕的逻辑像素高度