可能不是史上最全但很实用的BOM API详解-1

简介: 可能不是史上最全但很实用的BOM API详解-1

什么是 BOM?


BOM 是 browser object model 的缩写,中文意思是浏览器对象模型,提供了一系列操作浏览器的 API。与 ECMAScript 和 DOM 共同组成了 JavaScript。

在 Web 早期,BOM 没有标准规范,完全是由不同的浏览器厂商来实现的,所以不同的浏览器之间可能会存在差异。在 HTML5 规范中加入了 BOM 规范,弥补了这个问题。

BOM 能做什么?


打开新的标签页。


<button id="btn">打开百度首页</button>
<script>
  const btn = document.getElementById("btn");
  btn.addEventListener("click", () => window.open("https://www.baidu.com"));
</script>

关闭当前标签页。


<button id="btn">关闭页面</button>
<script>
  const btn = document.getElementById('btn')
  btn.addEventListener('click', () => window.close())
</script>

弹出新的浏览器窗口。

移动窗口。

缩放窗口。

控制用户浏览记录。

获取浏览器详细信息。

获取用户显示器分辨率详细信息。

其他更多功能。


BOM 包含什么?


JavaScript 最初是为 Web 浏览器创建的,但是后来它发展成了多用途和多平台的语言。任何能够提供 JavaScript 运行时的平台都可以称为 JavaScript 主机环境(host)。

目前主流的 JavaScript 平台有 Web 浏览器和可以运行服务端的 Node.js。

任何平台都需要有一个全局对象(Global)/根对象(Root)/宿主对象(Host),用于扩展除了 ECMAScript 语言自身的对象和函数外自己提供的对象和函数。

浏览器环境下的全局对象是 window,它扩展了 DOM 和 BOM。

window 除了具有全局对象含意外,还拥有另一个含意,是“浏览器窗口”。

它的组成如下:

image.png

从图中可以看到,BOM 主要包含了 Navigator、Screen、Location、Frames、History 和 XMLHttpRequest 6 个对象。下面逐个讲述它们的用途。


Navigator


Navigator 对象记录了访问者信息。

获取常用属性的示例代码如下:


<div id="info"></div>
<script>
  const info = document.getElementById("info")
  info.innerHTML += `浏览器应用程序名称: ${navigator.appName} </br>`
  info.innerHTML += `浏览器应用程序代码: ${navigator.appCodeName} </br>`
  info.innerHTML += `浏览器引擎: ${navigator.product} </br>`
  info.innerHTML += `浏览器版本: ${navigator.appVersion} </br>`
  info.innerHTML += `浏览器代理: ${navigator.userAgent} </br>`
  info.innerHTML += `浏览器平台: ${navigator.platform} </br>`
  info.innerHTML += `浏览器语言: ${navigator.language} </br>`
  info.innerHTML += `浏览器是否在线: ${navigator.onLine} </br>`
  info.innerHTML += `是否启用 cookie: ${navigator.cookieEnabled} </br>`
  info.innerHTML += `处理器核心数: ${navigator.hardwareConcurrency} </br>`
</script>

属性


属性 作用
appName 浏览器应用程序名称
appCodeName 浏览器应用程序代码
product 浏览器引擎
appVersion 浏览器版本
userAgent 浏览器代理
platform 浏览器平台
language 浏览器语言
onLine 浏览器是否在线
cookieEnabled 是否启用 cookie
hardwareConcurrency 处理器核心数

Navigator 对象的所有属性都不保证返回值是正确的,因为:

不同浏览器能够使用相同名称 导航数据可被浏览器拥有者更改 某些浏览器会错误标识自身以绕过站点测试 浏览器无法报告发布晚于浏览器的新操作系统

但也不需要过度担心,因为常规用户是不会随意操作这些属性的。

Navigator 上面的属性几乎全部都是只读的。即使你更改了属性的值,也不会有任何作用,当然也不会报错。


navigator.appCodeName = ""
console.log(navigator.appCodeName) // "Mozilla"

其实 navigator 上的大多数属性都是为了兼容老旧的程序,基本上没有什么实际意义。

比如 appName,它的值只有两个,Netscape(网景) 和 Microsoft Internet Explorer(微软 IE)。其中只有低于 11 版本的 IE 浏览器返回 Microsoft Internet Explorer,其他浏览器都是 Netscape。

比较常用的两个属性是 userAgent 和 onLine。


区分移动设备机型:userAgent


userAgent 可以用来识别不同的平台和浏览器。但是由于用户可以修改这个字符串,各类终端设备的不同等原因,用这个属性来识别浏览器不是个好方法,但它可以大致准确的识别出移动设备的机型。如果自己来处理 userAgent 字符串,需要用到大量正则表达式,而且容易出错,总之是一个非常麻烦的过程。比较推荐解析库 ua-parser-js

它只需要两行代码就可以获取到完整的用户代理信息。


var parser = new UAParser();
console.log(parser.getResult());


监听设备在线离线状态:onLine 的用途


window 提供了 online(上线) 和 offline(离线) 两个事件,可以通过监听这两个事件,并配合 onLine 属性进行判断设备是否离线。


window.addEventListener('online',  printNetworkState);
window.addEventListener('offline', printNetworkState);
function printNetworkState() {
  console.log(navigator.onLine ? "您的网络恢复了" : "您的网络断开了");
}

调试网络状态可以在浏览器的控制台中选择 Network 面板,点击 WIFI 图标。

image.png

这样就进入了 Network conditions 面板,点击 Network throttling,可以选择不同的网络状态。

image.png

除了上述的属性外,还有几个属性是在 HTML5 中新添加的,在移动开发中比较有实用价值,比如 getBattery(电池状态)、connection(网络连接状态)和 geolocation(地理位置信息)等。


电池状态:getBattery


该 API 可以获取电池状态,从而做一些你想做的事情,比如在电量较低时减少资源消耗,在电量将要耗尽时存储数据,防止数据丢失等。

getBattery 会返回一个 BatteryManager 对象。


属性


属性 作用
charging 布尔值,表示电池当前是否在充电。
chargingTime Number,表示电池充电前地剩余时间,单位为秒,如果电池已经充满电,则为 0。
dischargingTime Number,表示电池完全放电和系统暂停前剩余时间,单位为秒。
level Number,表示电池充电水平,比例为0.0-1.0之间。

事件


事件 作用
onchargingchange 电池充电状态更新时触发此事件。
onchargingtimechange 电池充电时间更新时触发此事件。
ondischargingtimechange 电池放电时间更新时触发此事件。
onlevelchange 电池电量更新时触发此事件。

示例:


navigator.getBattery().then(function(battery) {
  function updateAllBatteryInfo(){
    updateChargeInfo();
    updateLevelInfo();
    updateChargingInfo();
    updateDischargingInfo();
  }
  updateAllBatteryInfo();
  battery.addEventListener('chargingchange', updateChargeInfo);
  function updateChargeInfo(){
    console.log(`Battery charging? ${battery.charging ? "Yes" : "No"}`);
  }
  battery.addEventListener('levelchange', updateLevelInfo);
  function updateLevelInfo(){
    console.log(`Battery level: ${battery.level * 100}%`);
  }
  battery.addEventListener('chargingtimechange', updateChargingInfo);
  function updateChargingInfo(){
    console.log(`Battery charging time: ${battery.chargingTime} seconds`);
  }
  battery.addEventListener('dischargingtimechange', updateDischargingInfo);
  function updateDischargingInfo(){
    console.log(`Battery discharging time: ${battery.dischargingTime} seconds`);
  }
});

下面是两个在 codepen上面的示例。

充电 Demo 1

充电 Demo 2


网络状态:connection


connection 可以获取系统网络状态,来通过判断网络是蜂窝网还是 WiFi 来提醒用户流量的损耗。还可以通过区分 3G/4G/5G 来提供不同质量的内容。相比于 onLoad 属性,connection 拥有更细粒度的网络状态监控。

示例:


const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
function printConnectionStatus(e) {
  console.log(e.target);
}
connection.addEventListener('change', printConnectionStatus);

e.target 是当前的网络状态对象, 它包含如下几个属性。

属性 类型 作用
downlink number 网络下行速度,单位 M/s
effectiveType string 网络类型,常见的值有 4g/3g/2g 等。
onchange null 有值代表网络状态变化,默认为 null
rtt number 往返时间(round-trip time)的缩写,单位是毫秒,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认,不包含数据传输时间)总共经历的时间。
saveData boolean 打开/请求数据保护模式

地理位置:geolocation


这个 API 只能在 https 协议下才可以使用,它可以获取地理位置。

但这个 API 的位置偏移较为严重,容易产生定位不精准的问题。

示例:


const options = {
  enableHighAccuracy: true,// 高精确度
  timeout: 5 * 1000,// 等待响应的最长时间 单位:毫秒
  maximumAge: 0// 应用程序愿意接受的缓存位置的最长时间
}
if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(console.log, console.log, options)
} else {
  console.log('Geolocation is not supported in your browser')
}

在任意一个 https 协议的网页控制台中运行上面这段脚本,会在左上角弹出一个地址授权提示框。

image.png

点击允许就完成了授权,这时右侧就会出现一个地址的图标。

image.png

如果浏览器自身没有访问位置的权限,需要在操作系统设置中对其授权,比如在 Mac 系统下。

image.png

完成授权后可以获得一个 GeolocationPosition 对象,这个对象的 coords 属性记录了当前位置信息。

最重要的是经纬度,比如我的:

makefile

复制代码

latitude: 22.3193039longitude: 114.16936109999999

现在可以在高德开放平台使用坐标拾取器查询具体的位置了。

输入经纬度,格式是经度加英文逗号加维度。

image.png

像高德地图、百度地图、腾讯地图这类地图厂商的 H5 SDK 都是使用这个 API 来完成的。


摄像头和麦克风:WebRTC


上述的几个 API 都是实验性的,通常多用于移动端。

除此之外,还有 WebRTC 技术中需要用到的摄像头/麦克风等功能也属于 Navigator 的范畴。

WebRTC 是 Web Real-Time Communication 的缩写,直译为 Web 实时沟通,通常用于视频聊天、语音聊天之类的场景。

但 WebRTC 的内容相对较多,不在这节课中详述,下面是一个 Demo,有兴趣可以自行学习。

WebRTC Demo


Screen


screen 表示当前窗口所在的屏幕,提供了显示设备的信息。

相比较 Navigator 而言,Screen 则简单很多。

它提供了如下属性:

属性 作用
height Number,屏幕高度,单位像素。通常是常量,缩放网页不会发生变化。但调整屏幕分辨率会影响它。
width 屏幕宽度,其他特性同 height。
availHeight Number,屏幕可用高度,单位像素。即屏幕总高度减掉系统的任务栏或者其它系统组件的高度。
availWidth 屏幕宽度,其他特性同 availHeight。
pixelDepth 屏幕色彩位数,比如 24 表示 24 位色彩。
colorDepth 表示颜色深度。和 pixelDepth 的区别是 colorDepth 表示应用程序的颜色深度,pixelDepth 表示屏幕的颜色深度。绝大多数情况下是一样的。
orientation 表示屏幕方向,是个对象。
orientation.angle Number,屏幕旋转角度。
orientation.type String,屏幕方向,landscape-primary 横放、landscape-secondary 颠倒的横放、portrait-primary 竖放。

Screen 最常见的用途是根据用户设备的不同,提供不同的资源。

比如根据不同分辨率提供两套 html:


if (screen.width > 1920 && screen.height > 1080) {
  location.replace('max.html')
} else if (screen.width < 1280 && screen.height < 720) {
  location.replace('min.html')
}

Location


记录当前 URL 信息,并提供了一系列对当前 URL 的操作方法。


属性


属性 作用
href 整个 URL。
protocol 当前 URL 的协议,包括冒号(:)。
host 主机。如果端口不是协议默认的80433,则还会包括冒号(:)和端口。
hostname 主机名,不包括端口。
port 端口号。
pathname URL 的路径部分,从根路径/开始。
search 查询字符串部分,从问号?开始。
hash 片段字符串部分,从#开始。
username 域名前面的用户名。
password 域名前面的密码。
origin URL 的协议、主机名和端口。

这些属性中只有 origin 为只读属性,其它属性均为可写。

当你一旦修改了 location 的属性,页面会立即发生变化。比如你修改了 href,页面会立即触发跳转。


跳转锚点


最常用的用法是通过设置 hash,让页面自动滚动到对应的锚点位置。

只要设置过 id 的元素,都可以称为锚点(anchor)。

示例(2 秒后自动跳转到锚点 d3 的位置):


<div id="d1">1</div>
<div id="d2">2</div>
<div id="d3">3</div>
<div id="d4">4</div>
<div id="d5">5</div>
<div id="d6">6</div>
<style>
  [id^="d"] {
    height: 400px;
    text-align: center;
    line-height: 400px;
    font-size: 24px;
    font-weight: 600;
    color: #fff;
  }
  #d1 {
    background: #d9e3f0;
  }
  #d2 {
    background: #f47373;
  }
  #d3 {
    background: #697689;
  }
  #d4 {
    background: #37d67a;
  }
  #d5 {
    background: #2ccce4;
  }
  #d6 {
    background: #555555;
  }
</style>
<script>
  setTimeout(() => {
    location.href = "#d3";
  }, 2000);
</script>

方法

跳转页面 assign


location.assign('http://www.baidu.com')

如果参数不是一个合法的 URL,不会跳转页面,而是会抛出异常。


替换当前页面 replace


location.replace('http://www.baidu.com')

replace 和 assign 的区别在于,replace 不会存储上一个页面浏览历史,而是用新的 URL 替换掉老的 URL,也就是说意味着页面无法再回退。


重新加载页面 reload


location.reload()

reload 的作用等价于点击浏览器的刷新按钮。

image.png

reload 可以传递一个 boolean 类型的参数。

当设置为 true 时会强制从服务器重新请求资源。如果设置为 false,会使用浏览器缓存。默认为 false。


转换为字符串 toString


等同于 location.href。


URL 和 URLSearchParams 对象


一个 URL 可以包含如下几个部分。

image.png

  • href:完整的 URL。
  • protocol:协议,以 : 结尾。常见的有 http 和 https。
  • hostname:域名,和协议以 // 分割,和端口以 : 分割。
  • port:端口,通常会省略掉,默认为 80。
  • pathname:路径,表示网站中的某个资源。
  • search:查询参数,以 ? 开头,彼此之间以 & 拼接。
  • hash:锚点,以 # 开头。

BOM 提供了 URL 和 URL SearchParams 对象来帮助我们更容易地操作 URL。

虽然大多数情况下我们只需要使用字符串类型的 URL 就足够了,但在某些时候 URL 对象非常有用。


创建 URL 对象


需要使用 new 关键字创建,它有两个参数,第一个是 url,或者是一个路径,必选;第二个是基础路径,可选。

比如百度的URL:


new URL('https://www.baidu.com')

加上 base 的情况:


new URL('/s?ie=UTF-8&wd=url', 'https://www.baidu.com')

url 对象可以在很多情况下替换 url 字符串,因为它会进行隐式转换。

比如:


location.href = new URL('/s?ie=UTF-8&wd=url', 'https://www.baidu.com')

解析 URL 字符串


如果你拥有一个 url 字符串,也可以通过 URL 对它进行解析。


const urlStr = "https://www.baidu.com/s?ie=UTF-8&wd=url"
const url = new URL(urlStr)
console.log(url.protocol)// https:
console.log(url.host)// "www.baidu.com"
console.log(url.search)// "?ie=UTF-8&wd=url"

编码


在 URL 中,很多特殊的字符串是不合法的,比如中文和空格等。

合法符号如下:

  • URL 元字符:分号(;),逗号(,),斜杠(/),问号(?),冒号(:),at(@),&,等号(=),加号(+),美元符号($),井号(#
  • 语义字符:a-zA-Z0-9,连词号(-),下划线(_),点(.),感叹号(!),波浪线(~),星号(*),单引号('),圆括号(()

除了这两类,其它所有字符都是不合法的。如果你要在字符串中包含不合法字符,都必须转义,规则是根据操作系统的默认编码,将每个字节转为百分号(%)加上两个大写的十六进制字母。而一个中文是三个字节,所以会被转换为 6 个转义字符。

RFC3986 中规定了哪些字符应该被转义。

比如你在地址栏输入:


https://www.baidu.com/s?wd=前端

当你拷贝下来之后会发现变成了下面这个格式:www.baidu.com/s?wd=%E5%89…

URL 中前端两个字被转义成了 E5 89 8D 和 E7 AB AF 这 6 个 UTF8 字节码。


字符转义函数


上面这种情况是浏览器自动帮我们做了转义,但如果我们在 JS 中有一个字符串,是未转义的,那么就需要我们自己来转义。

比如你有一个 url 字符串。


const urlStr = "https://www.baidu.com/s?ws=前端"

你想跳转到对应的网页。


location.href = urlStr

发现会失败,原因就是前端两个汉字没有经过转义。

JavaScript 提供四个 URL 的编码/解码方法。


encodeURI


encodeURI 方法用于编码整个 URL。它的参数是一个字符串,代表整个 URL。它会将元字符和语义字符之外的字符,都进行转义。


encodeURI(urlStr)
// "https://www.baidu.com/s?ws=%E5%89%8D%E7%AB%AF"

encodeURIComponent


encodeURIComponent 方法用于转码 URL 的组成部分,会转码除了语义字符之外的所有字符,即元字符也会被转码。所以,**它不能用于转码整个 URL。**它接受一个参数,就是 URL 的片段。


encodeURIComponent('前端')
// "%E5%89%8D%E7%AB%AF"

如果你将整个 URL 进行转义,是不可以的。


encodeURIComponent(urlStr)
// "https%3A%2F%2Fwww.baidu.com%2Fs%3Fws%3D%E5%89%8D%E7%AB%AF"

上面代码中,encodeURIComponent 会连 URL 元字符一起转义,所以如果转码整个 URL 就会出现问题。


decodeURI


decodeURI 方法用于整个 URL 的解码。它是 encodeURI 方法的逆运算。它接受一个参数,就是转码后的 URL。


const urlEncode = encodeURI(urlStr)
// "https://www.baidu.com/s?ws=%E5%89%8D%E7%AB%AF"
const urlDecode = decodeURI(urlEncode)
// "https://www.baidu.com/s?ws=前端"

decodeURIComponent


decodeURIComponent 用于对 URL 片段进行解码。它是 encodeURIComponent 方法的逆运算。它接受一个参数,就是转码后的 URL 片段。


decodeURIComponent('%E5%89%8D%E7%AB%AF')
// "前端"

URLSearchParams对象


search 字符串是一段并不是很好处理的文本。

比如我有一个如下 URL:


https://www.baidu.com/s?wd=url&ie=utf-8

它的查询参数部分如下:


wd=url&ie=utf-8

这段查询参数,我们如果需要替换 ie 的值或者 wd 的值都需要正则匹配或者使用类似的麻烦技术。(在我接触 URLSearchParams 之前就是用这种方式处理的。)

如果我们能够将这段文本通过类似对象的方式操作是最方便的。URLSearchParams 就提供了这种方式。


let url = new URL('https://www.baidu.com/s?wd=url&ie=utf-8');
url.searchParams.set('wd', 'searchparams');
console.log(url);

除了 set 方法之外,URLSearchParams 还提供了更多的方法,你可以逐一尝试。

方法 作用
append 添加新的查询参数
delete 删除查询参数
get 获取某个查询参数
getAll 获取所有查询参数。因为 wd=url&wd=uri 是合法的,所以它会返回一个数组。
has 检查某个查询参数是否存在。
set 修改某个查询参数。
sort 对参数进行排序,很少会用到。

encode 函数与 URL/URLSearchParams


encode 函数和 URL/URLSearchParams 对象之间的区别就是,encode 函数基于 RFC2396,这是一个过时的 URL 规范。而 URL 和 URLSearchParams 是基于最新的 RFC3986

在处理 IPV6 时,encode 就会出现问题。不过这种情况很少见,绝大多数情况下,encode 函数都可以正常运行。



相关文章
|
11月前
|
存储 Web App开发 缓存
BOM的概念和常用API
BOM的概念和常用API
104 0
|
3月前
|
JavaScript 前端开发 API
探索前端BOM API:解锁浏览器的潜力
探索前端BOM API:解锁浏览器的潜力
83 0
|
8月前
|
JavaScript 前端开发 API
探索前端BOM API:解锁浏览器的潜力
探索前端BOM API:解锁浏览器的潜力
61 1
|
缓存 JavaScript 前端开发
web前端面试高频考点——JavaScript-Web-API 篇(一)DOM、BOM、事件
web前端面试高频考点——JavaScript-Web-API 篇(一)DOM、BOM、事件
105 0
|
XML 缓存 开发框架
提升对前端的认知,不得不了解Web API的DOM和BOM
在现代的开发中,vue和react都是很流行的开发框架,框架虽好用,但是框架的原理还是基于 DOM 操作去实现。如果一个前端工程师只会框架,不会 DOM ,那基本上是很容易被淘汰的。因为框架的存活时间我们谁也说不准,且技术更新迭代也特别快,说不定三五年就会被淘汰了都有可能。所以,扎实的学会 js 的基础原理,不要被框架和一些外部事件所迷惑,对自己会有一个更好的竞争力提升。 本文将讲解 JS 中 Web API 的 DOM 和 BOM 操作。
提升对前端的认知,不得不了解Web API的DOM和BOM
|
XML JSON JavaScript
【前端第十课】Modules使用的方法;BOM相关api;DOM相关api;相关代码规范的内容
【前端第十课】Modules使用的方法;BOM相关api;DOM相关api;相关代码规范的内容
|
5天前
|
机器人 API Python
智能对话机器人(通义版)会话接口API使用Quick Start
本文主要演示了如何使用python脚本快速调用智能对话机器人API接口,在参数获取的部分给出了具体的获取位置截图,这部分容易出错,第一次使用务必仔细参考接入参数获取的位置。
|
3天前
|
XML JSON API
RESTful API设计最佳实践:构建高效、可扩展的接口
【8月更文挑战第17天】RESTful API设计是一个涉及多方面因素的复杂过程。通过遵循上述最佳实践,开发者可以构建出更加高效、可扩展、易于维护的API。然而,值得注意的是,最佳实践并非一成不变,随着技术的发展和业务需求的变化,可能需要不断调整和优化API设计。因此,保持对新技术和最佳实践的关注,是成为一名优秀API设计师的关键。
|
4天前
|
监控 API 数据安全/隐私保护
​邮件API触发式接口分析?邮件API接口好评榜
邮件API在企业通信和营销中至关重要,通过自动化邮件发送流程提升效率与客户满意度。本文解析邮件API触发式接口,即基于特定事件(如用户注册、购买产品)自动发送邮件的技术,能显著加快企业响应速度并增强用户体验。推荐市场上的优秀邮件API产品,包括SendGrid、Mailgun、Amazon SES、Postmark及新兴的AOKSend,它们各具特色,如高发送率、详细分析工具、灵活配置、强大的日志功能及用户友好的API接口,帮助企业根据不同需求选择最合适的邮件API解决方案。
|
11天前
|
存储 算法 Oracle
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
39 8