Window对象
BOM的核心是window对象,表示浏览器的实例,window对象在浏览器中有两重身份,一个是ECMAScript中的Global对象,另一个就是浏览器窗口的JavaScript接口,这就意味着网页中定义的所有对象、变量、和函数都以window作为其Global对象,都可以访问它上面的全局方法。
Global作用域
因为window对象被复用为ECMAScript的Global对象,所以通过var声明的所有全局变量和函数都会变成window对象的属性和方法。
注意:访问未声明的变量会抛出错误,但是可以在window对象上查询是否存在可能未声明的变量。 JavaScript中有很多对象都暴露在全局作用域中,比如location和navigator,因而他们也是window对象的属性。
窗口关系
top对象始终指向最外(上)层窗口,即浏览器窗口本身。而parent对象始终指向当前窗口的父窗口,如果当前窗口是最上层窗口,则parent等于top。最上层的window如果不是通过window.open打开的,那么其name属性就不会包含值。
还有一个self对象,它是终极window属性,始终会指向window。
窗口位置与像素比
window对象的位置可以通过它暴露的api方法去移动。现代的浏览器都提供了screenLeft和screenTop属性,用于表示窗口相对于屏幕左侧和顶部的位置,返回的单位是css像素。
可以使用moveTo和moveBy方法移动窗口,这两个方法都接受两个参数,其中moveTo接受要移动的新位置的绝对坐标x和y,而moveBy则接受相对当前位置在两个方向上移动的像素数。
像素比: css像素是web开发中使用的统一像素单位,这个单位的背后其实是一个角度:0.0213度,换句话说,如果屏幕距离人眼是一臂长,则以这个角度计算的css像素大小约是1/96英寸。从这个解释大家就应该知道,css的像素是一个逻辑单位,或者可以试着理解为一个长度单位,不管是什么分辨率的设备,1/96英寸的长度就是一个css像素。但是实际上这一个css像素可能会由好几个物理像素组成。
window.devicePixelRatio表示物理像素与逻辑像素之间的缩放系数。
导航与打开新窗口
window.open()方法可以用于导航到指定URL,也可以用来打开新浏览器窗口,这个方法接收4个参数,要加载的URL,目标窗口,特性字符串,和表示新窗口在浏览器历史记录中是否代替当前加载页面的布尔值。通常,调用这个方法时只传前3个参数,最后一个参数只有在不打开新窗口时才会使用。
如果window.open()的第二个参数是一个已经存在的窗口或者窗格的名字,则会在对应的窗口或窗格中打开URL。
弹出窗口: 如果window.open()的第二个参数不是已有窗口,则会打开一个新窗口或者标签页。第三个参数,即特性字符串,可以配置即将要打开的新窗口的特性,如果没传第三个参数,默认使用浏览器的默认配置。特性字符创是一个逗号分隔的设置字符串,如下:
window.open('url', 'name',"height=300,width=300,top=10,left=10,resizable=yes")
window.open()方法返回一个对新建窗口的引用,这个对象跟普通的window对象没有什么区别,只是为了控制新窗口提供了方便。
let oneWindow = window.open('url', 'name');
oneWindow.resizeTo(500, 500);
oneWindow.moveTo(100, 100);
注意:window.close()方法只能用来关闭通过window.open()打开的窗口。
新建窗口的window对象有一个属性opener,指向打开它的窗口。
let oneWindow = window.open('url', 'name');
alert(oneWindow.opener === window); // true
虽然新建窗口中有指向打开它的窗口的指针,但反之不然,窗口不会记录自己打开的窗口,需要开发者自己记录。 把opener设置为null,表示新打开的标签页不需要与打开它的标签页通信,因此新的标签页可以在独立进程中运行,这个连接一旦切断,就无法恢复了。
安全限制和弹窗屏蔽程序
弹出窗口有段时间被在线广告用滥了,因此为了限制弹窗广告,浏览器开始对不合理的弹窗施加限制,现在只有用户触发了某个事件,才会创建弹窗,在网页加载过程中调用window.open()则打不开。
如果想知道弹窗是否被浏览器拦截了,可以看window.open()方法的返回值:
//在浏览器扩展或者其他程序屏蔽弹窗时,window.open()方法通常会抛出错误,因此要准确检测弹窗是否被屏蔽,最好用try/catch包装一下。
let blocked = false;
try {
let oneWindow = window.open('url', 'name');
if (oneWindow === null) {
blocked = true;
}
} catch (ex) {
blocked = true;
}
if (blocked) {
alert('弹窗被屏蔽了');
}
location对象
location是最有用的BOM对象之一,提供了当前窗口中加载文档的信息,以及通常的导航功能。该对象独特的是它既是window的属性又是document的属性。window.location和document.location实际上指向的是同一个对象。location对象不仅保存着当前加载文档的信息,也保存着把URL解析为离散片段后能通过属性访问的信息。
| 属性 | 值 |
|---|---|
| location.hash | 哈希值 |
| location.host | 服务器名和端口号 |
| location.hostname | 服务器名 |
| location.href | 当前加载页面的完整URL |
| location.protocal | 页面使用的协议 |
查询字符串
location的多数信息都可以通过上面的属性获取,但是在URL中的查询字符串并不容易使用。为了更好的使用查询字符串的值,我们可以自己定义一个方法,也可以使用URLSearchParams类。
let getQueryStringArgs = function() {
let qs = (location.search.length > 0) ? location.search.substring(1) : '';
let args = {};
for (let item of qs.split('&').map(kv => kv.split('='))) {
let name = decodeURIComponent(item[0]);
value = decodeURIComponent(item[1]);
if (names.length) {
args[name] = value;
}
}
return args;
}
// URLSearchParams 提供了一组标准的API方法,通过他们可以检查和修改查询字符串。给URLSearchParams构造函数可以传如
//一个字符串,就可以创建一个实例。这个实例上暴露了get,set,delete方法,可以对查询字符串执行相应操作。
let qs = "?a=2&b=3";
let search = new URLSearchParams(qs);
console.log(search.get('a'));
console.log(search.has('a'));
for(let item of search) {
console.log(item);
}
操作地址
可以通过修改location对象修改浏览器的地址,常用的方法有assign方法,使用该方法会立即启动导航到新URL的操作,同时还会在浏览器历史记录中增加一条记录。如果给location.href或window.location设置一个URL,也会以同一个值调用assign方法。下面的两行代码都会执行与显示调用assign一样的操作。
location.assign('http://www.com');
window.location = 'http://www.com';
location.href = 'http://www.com';
注意:修改location对象的属性也会修改当前加载的页面。其中,hash,search,hostname,pathname,port属性被设置为新值之后都会修改当前URL。除了hash之外,只要修改location的一个属性,就会导致页面重新加载新的URL。修改hash的值会在浏览器历史中增加一条新纪录,同样上面其他的值也会增加对应的历史记录。如果不希望增加历史记录,可以调用replace方法,它接受一个URL参数。此外,能修改地址的还有一个reload方法,他能重新加载当前显示的页面。调用reload而不传参数,页面会以最有效的方式重新加载,也就是说可能会从缓存中加载,如果想要强制从服务器重新加载,可以给这个方法传一个true参数。
location.reload(); // 重新加载,可能会从缓存加载
location.reload(true); // 重新从服务器加载
注意: 脚本中位于reload()方法调用之后的代码可能执行也可能不执行,这取决于网络延迟和系统资源等因素。因此,最好把reload()放到最后一行代码处。
navigator对象
navigator是由Netscape Navigator2最早引入浏览器的,现在已经成为客户端标识浏览器的标准,只要浏览器启用JavaScript,navigator对象就一定存在,与其他BOM对象一样,每个浏览器都支持自己的属性。下面是一些常见的navigator对象的属性:
| 属性/方法 | 描述 |
|---|---|
| appName | 浏览器全名 |
| cookieEnabled | 返回布尔值,表示是否启用了cookie |
| deviceMemory | 返回单位为GB的设备内存容量 |
| onLine | 返回布尔值,表示浏览器是否联网 |
| userAgent | 返回浏览器的用户代理字符串 |
| vibrate() | 触发设备振动 |
检测插件
检测浏览器是否安装了某个插件是开发中常见的需求,处IE10及更低版本外的浏览器,都可以通过plugins数组来确定。这个数组中的每一项都包含如下属性。name插件名称,description插件介绍,filename插件的文件名,length由当前插件处理的MIME类型数量。
通常name属性包含识别插件所需的必要信息,尽管不是特别准确。
let hasPlugin = function (name) {
name = name.toLowerCase();
for(let plugin of window.navigator.plugins) {
if (plugins.name.toLowerCase().indexOf(name) > -1) {
return true;
}
}
return false;
}
alert(hasPlugin("Flash"));
// 旧版本的插件检测
//IE10及更低版本中检测插件问题比较多,需要使用专有的ActiveXObject,并尝试实例化特定的插件。IE中的插件是实现为
//COM对象的,由唯一的字符串标识。因此,要检测某个插件就必须知道其COM标识符,例如Flash的标识符是"ShockwaveFlash.ShockwaveFlah"。
function hasIEplugin(name) {
try {
new ActiveXObject(name);
return true;
} catch (ex) {
return false;
}
}
alert(hasIEplugin("ShockwaveFlash.ShockwaveFlah"));
history对象
history对象表示当前窗口首次使用以来用户的导航历史记录。因为history是window的属性,所以每个window都有自己的history对象。出于安全考虑,这个对象并不会暴露用户访问过的URL,但是可以通过浏览器的前进后退按钮访问相应的URL。
导航
go()方法可以在用户历史记录中沿任何方向导航,可以前进也能后退。这个方法只接受一个参数,这个参数可以是一个整数,表示前进或者后退多少步。负值代表后退,正直代表前进。
go()方法的参数也可以是一个字符串,这种情况下浏览器会导航到历史中包含该字符串的第一个位置。最接近的位置可能涉及后退,也可能涉及前进。如果历史记录中没有匹配的项,则这个方法什么也不做。
go有两个简写方法,分别是back(),forward()。顾名思义,这两个方法模拟了浏览器的后退按钮和前进按钮。history.back(),history.forward()。
history对象还有一个length属性,表示历史记录中有多个条目。通过判断history.length是否等于1可以确定用户浏览器的起点是不是你的页面。