BOM

161 阅读11分钟

BOM是使用JS开发Web应用程序的核心。

Window对象

BOM的核心是window对象,表示浏览器的实例。

window对象在浏览器中有两重身份,一个是ECMAScript中的Global对象,另一个是浏览器窗口的JS接口。

这意味着网页中定义的所有对象、变量和函数都以window作为其Global对象,都可以访问其上定义的parInt()等全局方法

因为window对象的属性在全局作用域中有效,所以很多浏览器API及相关构造函数都以window对象属性的形式暴露出来。

另外,由于实现不同,某些window对象的属性在不同浏览器间可能差异很大

Global作用域

因为window对象被复用为ECMAScript的Global对象,所以通过var声明的所有全局变量和函数都会变成window对象的属性和方法

var age = 2;
console.log(window.age); // 2

访问未声明的变量会抛出错误,但是可以在window对象上查询是否存在可能未声明的变量。

浏览器窗口

窗口关系

  • top对象 始终指向最外层窗口,即浏览器窗口本身。

    最外层的window如果不是通过window.open()打开的,那么其name属性就不会包含值

  • parent对象 始终指向当前窗口的父窗口

  • self对象 是终极window属性,始终指向window

    实际上,selfwindow就是同一个对象。之所以还要暴露self,就是为了和topparent保持一致

window对象的位置可以通过不同的属性和方法来确定

  • screenLeft 表示窗口相对于屏幕左侧的位置

  • screenTop 表示窗口相对于屏幕顶部的位置

  • moveTo() 接收要移动到的新位置的绝对坐标值

  • moveBy() 接收相对当前位置在两个方向上移动的像素数

像素比

window.devicePixelRatio表示物理像素与逻辑像素之间的缩放系数

设置窗口大小

outerWidthouterHeight返回浏览器窗口自身的大小

innerWidthinnerHeight返回浏览器窗口中页面视口的大小(不包含浏览器边框和工具栏)

document.documentElement.clientWidthdocument.documentElement.clientHeight返回页面视口的宽度和高度

因为桌面浏览器的差异,所以需要先确定用户是不是在使用移动设备,然后再决定使用哪个属性

可以使用resizeTo(width, height)resizeBy(distanceWidth, distanceHeight)方法调整窗口大小。

缩放窗口的方法只能应用到最上层的window对象

视口位置

可以使用scroll()scrollTo()scrollBy()方法滚动页面。这三个方法都接收表示相对视口距离的xy坐标,这两个参数在前两个方法中表示要滚动到的坐标,在最后一个方法中表示滚动的距离

还可以通过behavior属性告诉浏览器是否平滑滚动

// 正常滚动
window.scrollTo({
    left: 100,
    top: 100,
    behavior: 'auto'
});
// 平滑滚动
window.scrollTo({
    left: 100,
    top: 100,
    behavior: 'smooth'
})

导航与打开新窗口

  • window.open(url, 目标窗口,特性字符串,是否替换当前页面)

    用于导航到指定URL,也可以用于打开新浏览器窗口

    window.open('http://www.baidu.com', 'topFrame');
    // 如果第二个参数是一个已经存在的窗口或frame的名字,则会在对应的窗口或frame中打开url,否则会打开一个新窗口并将其命名为“topFrame”
    // 第二个参数也可以是一个特殊的窗口名,比如_self、_parent、_top或_blank
    
    // 等同于
    <a href="http://www.baidu.com" target="topFrame" />
    

    特性字符串是一个逗号分隔的设置字符串,用于指定新窗口包含的特性

    • fullscreen 表示新窗口是否最大化,仅限IE支持;取值:“yes”或“no

    • height 新窗口高度,不能小于100

    • width 新窗口的宽度,不能小于100

    • left 新窗口的x轴坐标,不能是负值

    • top 新窗口的y轴坐标,不能是负值

    • location 表示是否显示地址栏。

    • Menubar 是否显示菜单栏

    • resizable 是否可以拖动改变新窗口大小

    • scrollbars 是否可以在内容过长时滚动

    • status 表示是否显示状态栏

    • toolvar 表示是否显示工具栏

    window.open('http:www.baidu.com', 'bd', 'height=200,width=200,resizable=yes');
    // 打开一个200*200的新窗口,可缩放
    
    bd.moveTo(100, 100); // 移动窗口
    
    bd.close();
    
    console.log(bd.closed); // true
    

    关闭窗口以后,窗口的引用虽然还在,但只能用于检查其close属性了。

    窗口不会跟踪记录自己打开的新窗口,因此开发者需要自己记录。

    在某些浏览器中,每个标签页会进行在独立的进程中。如果一个标签页打开了另一个,而window对象需要跟另一个标签页通信,那么标签便不能运行在独立的进程中。

    在这些浏览器中,可以将新打开的标签页的opener属性设置为null,表示新打开的标签页可以运行在独立的进程中,即新打开的标签页不需要与打开它的标签页通信。这个链接一旦切断,就无法恢复了。

    let a = window.open('http://www.baidu.com', 'x');
    
    a.opener = null;
    

安全限制

弹出窗口有段时间被在线广告用滥了。很多在线广告会把弹出窗口伪装成系统对话框,诱导用户点击。为了让用户能够区分清楚,浏览器开始对弹窗施加限制

此外,浏览器会在用户操作下才允许创建弹窗。在网页加载过程中调用window.open()没有效果,而且还可能导致向用户显示错误。

所有现代浏览器都内置了屏蔽弹窗的程序,因此大多数意料之外的弹窗都会被屏蔽。在浏览器屏蔽弹窗时,可能会发生一些事。所以需要使用弹窗时,最好检测弹窗是否被屏蔽

try{
    let win = window.open('http://www.baidu.com', '_blank');
    if(win === null) {
        alert('弹窗被禁用了');
    }
}

系统对话框

使用alert()confirm()prompt()方法,可以让浏览器调用系统对话框向用户显示消息。

这些对话框与浏览器中显示的网页无关,而且也不包含HTML。

这些对话框都是同步的模态对话框,即在他们显示的时候,代码会停止执行,在他们消失后,代码才会恢复执行。

location对象

location提供了当前窗口中加载文档的信息,以及通常的导航功能。

这个对象独特的地方在于,它既是window的属性,也是document的属性。也就是说,window.locationdocument.location指向同一个对象。

location对象不仅保存着当前加载文档的信息,也保存着把URL解析为离散片段后能够通过属性访问的信息。

假设浏览器当前加载的URL是https://user:password@www.aa.com:8080/path?q=j#contentslocation对象的内容如下:

  • .hash#contents” URL散列值(#号后跟零或多个字符),如果没有则为空字符串

  • .host "www.aa.com:8080" 服务器名及端口号

  • .hostname "www.aa.com" 服务器名

  • .port "80" 请求的端口,如果没有端口,则返回空字符串

  • .href "https://user:password@www.aa.com:8080/path?q=j#contents" 当前加载页面的完整URL

  • .pathname "/path" URL中的路径和(或)文件名

  • .protocol "http:" 页面使用的协议,“http”或“https

  • .search "?q=j" URL的查询字符串,以问号开头

    通常是被编码后的格式,所以一般解析时,使用decodeURIComponent()解码

    URLSearchParams提供了一组标准API方法,通过它们可以检查和修改查询字符串

    let qs = "?q=j&num=10";
    
    let searchParams = new URLSearchParams(qs);
    
    console.log(searchParams.toString()); // "q=j&num=10"
    searchParams.has('num'); // true
    searchParams.get('num'); // 10
    searchParams.set('page', '3');
    searchParams.delete('q');
    
    for(const param of searchParams) {
        console.log(param);
    }
    // ['num', '10']
    // ['page', '3']
    
  • .username "user" 域名前指定的用户名

  • .password "password" 域名前指定的密码

  • .origin "http://www.aa.com" URL的源地址(只读)

操作地址

可以通过修改location对象修改浏览器的地址。

  • .assign()

    立即启动导航到新的URL的操作,同时在浏览器历史记录中增加一条记录。

    location.assign('http://www.baidu.com');
    
    // 执行下面两行代码与显示调用assign()效果一样
    window.location = 'http://www.baidu.com';
    location.href = 'http:www.baidu.com'; // 最常见
    

    修改location对象的属性(hashsearchhostnamepathnameport)也会修改当前加载的页面,浏览器历史记录中也会增加相应的记录

    // 例如修改 search
    location.search = "?q=a"

    hash之外,只要修改location的一个属性,就会导致页面重新加载新URL。不过修改hash的值也会在浏览器历史中增加一条新纪录

  • replace(URL)

    重新加载接收的URL,替换当前记录

    调用replace()之后,用户不能回到前一页

  • reload()

    重新加载当前显示的页面

    调用此方法而不传参数,页面会以最有效的方式重新加载。即,如果页面自上次请求以来没有修改过,浏览器可能会从缓存中加载页面。

    如果想强制从服务器重新加载,可以传truereload

    location.reload(true);
    

    脚本中位于reload()调用之后的代码可能执行也可能不执行,这取决于网络延迟和系统资源等因素

navigator对象

只要浏览器启用JS,navigator对象就一定存在。但与其他BOM对象一样,每个浏览器都支持自己的属性

navigator对象的属性通常用于确定浏览器的类型

常用属性和方法:

  • appName 浏览器全名

  • appVersion 浏览器版本(通常与实际的浏览器版本不一致)

  • cookieEnabled 返回布尔值,表示是否启用了cookie

  • deviceMemory 返回单位为GB的设备内存容量

  • doNotTrack 返回用户的“不跟踪”(do-not-track)设置

  • geolocation 返回暴露Geolocation APIGeolocation对象

  • getUserMedia() 返回与可用媒体设备硬件关联的流

  • mediaDevices 返回可用的媒体设备

  • maxTouchPoints 返回设备触摸屏支持的最大触电数

  • onLine 返回布尔值,表示浏览器是否联网

  • platform 返回浏览器运行的系统平台

  • plugins 返回浏览器安装的插件数组。在IE中,这个数组包含页面中所有<embed>元素

    • refresh(needRefresh: boolean) 用于刷新plugins属性以反映新安装的插件

      如果传入true,则所有包含插件的页面都会重新加载。否则,只有plugins会更新,但页面不会重新加载

    plugin属性:

    • name 插件名称

    • description 插件介绍

    • filename 插件的文件名

    • length 由当前插件处理的MIME类型数量

    通常name属性包含识别插件所需的必要信息,尽管不是特别准确

  • userAgent 返回浏览器的用户代理字符串,可用于判断浏览器

    用户代理检测被认为是不可靠的,只应该在没有其他选项时再考虑

  • oscpu 通常对应用户代理字符串中操作系统/系统架构相关信息

  • vendor 通常包含浏览器开发商信息

  • registerProtocolHandler(协议,URL,appName) 在HTML5中定义,此方法可以把一个网站注册为处理某种特定类型信息应用程序。

    随着在线RSS阅读器和电子邮件客户端的流行,可以借助这个方法将Web应用程序注册为像桌面软件一样的默认应用程序

    // 把一个Web应用程序注册为默认邮件客户端
    
    navigator.registerProtocolHandler(
        'mailto',
        'http://www.somemaolclient.com?cmd=%s',
        'Some Mail Client'
    );
    
    // 此例为“mailto”协议注册了一个处理程序,这样邮件地址就可以通过指定的Web应用程序打开。
    
    // 第二个参数是负责处理请求的URL,%s表示原始的请求
    
    // 协议可以是“mailto”或“ftp”
    

history对象

history对象表示当前窗口首次使用以来用户的导航历史记录。

因为historywindow的属性,所以每个window都有自己的history对象。

处于安全考虑,这个对象不会暴露用户访问过的URL,但可以通过它在不知道实际URL的情况下前进和后退

history对象通常被用于创建“后退”和“前进”按钮,以及确定页面是不是用户历史记录中的第一条记录

  • .length 表示历史记录中有多个条目

  • .state 获取当前的状态对象

  • .go(num) 可以在用户历史记录中沿任何方向导航,负值表示后退,正值表示前进

  • .back() 后退

  • .forward() 前进

  • .pushState(state对象,title, url)

    往历史记录中推入一个新的状态信息,浏览器地址栏也会改变以反映新的相对URL

    为防止滥用,这个状态的对象大小是有限制的,通常在500KB - 1MB

    let stateObject = { foo: 'bar' };
    history.pushState(stateObject, 'My title', 'baz.html');
    
  • replaceState(stateObject, title) 用新的状态覆盖当前状态

    history.replaceState({newFoo: 'newBar'}, 'New title');
    

使用HTML5状态管理时,要确保通过pushState()创建的每个“假”URL背后都对应这服务器上一个真实的物理URL。否则,单击“刷新”按钮会导致404错误。

所有单页应用程序框架都必须通过服务器或客户端的某些配置解决这个问题

screen对象

这个对象中保存的纯粹是客户端能力信息,也就是浏览器窗口外面的客户端显示器的信息。常用属性:

  • width 屏幕像素宽度

  • height 屏幕像素高度

  • left 当前屏幕左边的像素距离

  • top 当前屏幕顶端的像素距离

  • orientation 返回 Screen Orientation API中屏幕的朝向