本节内容
- 理解BOM的核心---------window对象
- 控制窗口以及弹窗
虽然ECMAScript把浏览器对象模型(BOM,Browser Object Model)描述为JavaScript的核心。但是实际上BOM是使用JavaScript开发Web应用程序的核心。BOM提供了与网页无关的浏览器的功能对象。多年来。BOM是在缺乏规范的背景下发展起来的。因此即充满乐趣又问题多多。毕竟,浏览器开发商都按照自己的意愿来为他添砖加瓦。最终,浏览器之间共通的部分成为了事实的依据。为Web开发提供了浏览器间互相操作的基础。HTML5规范中又一部分涵盖了BOM的主要内容。因为W3C希望将JavaScript在浏览器最基础的部分标准化。
window对象
BOM的核心是window对象。表示浏览器的实例。window对象在浏览器中有两重身份。一个是ECMAScript中的Global对象。另一个就是浏览器窗口的JavaScript接口。这就意味着网页中定义的所有对象。变量以及函数都是以window作为Global对象。都可以访问其定义上的parseInt()等全局方法。
注意 因为window对象的属性在全局作用域中有效。所以很多浏览器的API以及相关的构造函数都以window对象属性的形式暴露出来。 另外,由于实现不同。某些window对象的属性在不同的浏览器之间可能差异就很大。
1. 🚄 Global作用域
因为window对象被复用为ECMAScript的Global对象。所以通过var声明的所有全局变量和函数都会变成window对象的属性和方法。比如:
var age=29
var sayAge=()=>alert(this.age)
alert(window.age) //29
sayAge() //29
window.sayAge() //29
这里,变量age和函数sayAge()被定义在全局作用域中。它们自动成为了window对象的成员。因此,变量age可以通过访问window.age来访问。而函数sayAge()也可以通过window.sayAge()来访问。因为sayAge()存在于全局作用域。this.age映射到windwo.age,所以就可以显示正确的结果。
如果在这里使用let或者const来替代var。就不会把变量添加到全局对象。
let age=29
const sayAge=()=>alert(this.age)
alert(window.age) //undefined
sayAge() //undefined //undefined
window.sayAge() // TypeError : window.sayAge is not a function
另外,访问未声明的变量会抛出错误。但是可以在window对象上查询是否可能未声明的变量。比如:
// 这会导致抛出错误,因为oldValue没有声明
var newValue=oldValue
// 这里不回抛出错误,因为这里是属性查询.
// newValue会被重置未undefined
var newValue=window.oldValue
记住,JavaScript中有很多对象都暴露在全局作用域中。比如location和navigator,因此他们都是window对象的属性。
2. 🚅 窗口关系
top对象始终指向最上层(最外层)窗口,即浏览器窗口本身。而parent对象则始终指向当前窗口的父窗口。如果当前窗口是最上层窗口,则parent等于top(都等于window)。最上层的window如果不是通过window.open打开的。那么其name属性就不回包含值。
还有一个self对象,它是终极window属性。始终会指向window。实际上,self和window就是同一个对象,之所以还要暴露self,就是为了和top,parent保持一致。
这些属性都是window对象的属性。因此访问windoe.parent、window.top和window.self都可以。这意味着可以把访问多个窗口的window对象串联起来。比如window.parent.parent.
3.🚈 窗口关系与像素比
window对象的位置可以通过不同的属性和方法来确定。现代浏览器提供了screenLeft和screenTop属性。用于表示窗口相对于屏幕左侧和顶部的位置。返回值的单位是css像素。
可以使用moveTo()和moveBy方式移动窗口。这两个方法都接受两个参数,其中moveTo接受要移动到新位置的绝对坐标x和y。而moveBy()则接受相对当前位置在两个方向上移动的像素。
比如
// 窗口移动到左上角
window.moveTo(0,0)
// 窗口向下移动100像素
window.moveBy(0,100)
// 窗口移动到指定位置
window.moveTo(200,300)
// 窗口向左移动
window.moveBy(-50,0)
依据浏览器而定,以上方法可能会部分或者全部禁用。
4. 🚞 像素比
CSS像素是Web开发中使用的统一像素单位。这个单位的背后其实是一个角度。0.0213deg.如果屏幕距离人眼的距离是一臂长。则以这个角度计算的CSS先像素大小是为u了在不同设备上统一标准。比如,低分辨率平板设备上12像素的文字应该与高清4K屏幕下12像素有这样一样的大小。这就带来了一个问题。不同像素密度的屏幕下就会有不同的缩放系数。以便把物体像素(屏幕的实际分辨率)转换为CSS像素(浏览器报告的虚拟分辨率)
举个例子手机屏幕的物理分辨率可能是19201080.但是因为其像素比可能非常小,所以浏览器就需要将其分辨率调整到比较低的逻辑分辨率。比如640320.这个物理像素与CSS像素之间的转换比率。 由于window.devicePixelRatio属性提供。对于分辨率从19201080转换为640320的设备。window。devicePixelRatio就是3.这样一来。12像素(CSS像素)的文字实际上就会用36像素的物理像素来显示。
window.devicePixelRadio实际上与每英寸像素数(DPI,dots per inch)是对应的。DPI表示单位像素密度。而window.devicePixelRatio表示物理像素之间的缩放系数。
5. 🚇窗口大小
在不同的浏览器中确定浏览器窗口大小没有想象中那么容易。所有现代浏览器都支持4个属性: innerWidth、innerHeight、outerWidth和outerHeght。outerHeight和outerWidth返回浏览器窗口自身的大小。(不管是在外层window上使用还是在窗格frame中使用)。innerWidth和innerHeight返回浏览器窗口中页面视口的大小。(不包含浏览器边框和工具栏)
document.element.clientWidth和document.element.clientHeight返回浏览器视口的高度和宽度。
浏览器窗口自身的精确尺寸不好确定。但是可以确定页面视口的大小。如下所示:
let pageWidth=window.innerWidth,
pageHeight=window.innerHeight
if(typeof pageWidth!="number"){
if(document.compatMode=='CSS1Compat'){
pageWidth=document.documentElement.clientWidth
pageHeight=document.documentElement.clientHeight
}else{
pageWidth=document.body.clientWidth
pageHeight=document.body.clientHeight
}
}
这里先将pageWidth和pageHeight的值分别设置为widnow.innerWidth和window.innerHeight。 然后,检查pageWidth是不是一个数值。如果不是则通过document.compatMode来检查页面是否处于标准模式。如果是,就是用documentElement的width和height,否则就使用body的width和height。
在移动设备上。window.innerWidth和window.innerHeight返回视口大小,也就是屏幕上可视区域的大小。Mobile Internet Explorer支持这些属性。但是在document.documentElement.clientWidth和height中提供了相同的信息。在放大和缩小页面时。这些值也会发生变化。
在其他移动浏览器中。document.documentElement.clientWidth和height返回的布局视口大小。即渲染页面的实际大小。布局视口是相对于可见视口的概念。可见视口只能显示整个页面的一小部分。Mobile Internet Explorer把布局视口的信息保存在document.body.clientWidth和document.body.clientHeight中.在放大和缩小页面时。这些值也会相应变化。
因为桌面浏览器的差异。所以需要先确定用户是不是在使用移动设备。然后再决定使用哪个属性。
注意,手机视口的概念比较复杂。有各种各样的问题。如果你在做移动开发。推荐阅读Perter-Paul发表在QuirksMode网站上的文章 "A Tale of Viewports--Part [Two](A tale of two viewports — part one (quirksmode.org))"
6. 🚟 视口位置
浏览器窗口尺寸通常无法显示完整的整个页面。为此用户可以通过滚动在有限的视口中来查看文档。度量文档相对于视口的滚动距离的属性有两对。返回相等的值: window.pageXoffSet/window.scrollX和window.pageYoffset/window.scrollY
可以使用scroll()、scrollTo()、和scrollBy()两个方法滚动页面。这三个方法都能接受相对视口距离的x和y坐标。这两个参数在前两个方法中表示要滚动到的坐标。在最后一个方法中表示滚动的距离。
// 相对于当前视口向下滚动100像素
window.scrollBy(0,100)
// 相对于当前视口向右滚动40像素
window.scrolBy(40,0)
// 滚动到页面左上角
window.scrollTo(0,0)
// 滚动到距离页面左边100像素的位置
window.scrollTo(100,100)
这几个方法也接受一个ScrollToOptions字典。除了提供偏移量。还可以通过behavior属性来告诉浏览器是否平滑滚动。
// 正常滚动
window.scrollTo({
left: 100,
top: 100,
behavior: 'auto'
})
// 平滑滚动
window.scrollTo({
left: 100,
top: 100,
behavior: 'smooth'
})
7. 🚂导航与打开新窗口
window.open()这个方法可以用于导航到指定的URL。也可以用于打开新浏览器窗口。这个方法接受4个参数:要加载的URL、目标窗口、特性字符串和表示新窗口在浏览器中是否替代当前加载页面的布尔值。通常。调用这个方法的时候只传递3个参数。最后一个参数只有在不打开新窗口的时候才会使用。
如果window.open()的第二个参数是一个已经存在的窗口或者frame.则会在对应的窗口打开URL。下面是一个例子。
window.open("http://wwww.wrox.com","topFrame")
执行这行代码就相当于用户点击了一个href属性。为wwww.wrox.com,target属性为“topFrame”的链接。如果有一个窗口名字叫做topFrame。那么这个窗口就会打开这个URL。否则就会打开一个新窗口并且把它命名为topFrame。第二个参数也可以是一个特殊的窗口名。比如_self,_parent,_top或_blank.
弹出窗口 如果window.open的第二个参数不是已有的窗口。则会打开一个新的窗口或者标签。第三个参数,即特性字符串。用于指定新窗口的配置。如果没有传递第三个参数。则新窗口(或者新标签页)会带有默认的所有浏览器特性。(工具栏,地址栏,状态栏等都是默认配置)。如果打开的不是新窗口,就忽略第三个参数。
特性字符串是一个都好分割设置的字符串。用于指定新窗口包含的特性。
| 设置 | 值 | 说明 |
|---|---|---|
| fullscreen | "yes"或者"no" | 表示新窗口是否最大化。仅仅支持IE |
| height | 数值 | 新窗口的高度 |
| left | 数值 | 新窗口的X坐标 |
| location | "yes"或者"no" | 表示是否显示地址栏。不同的浏览器默认值也一样 |
| Menubar | "yes"或者"no" | 表示是否显示菜单栏,默认为no |
| resizable | "yes"或"no" | 表示是否可以拖动窗口改变大小,默认为no |
| scrollbars | "yes"或者"no" | 表示是否可以在内容过长时滚动 |
| status | "yes"或者"no" | 表示是否显示状态栏,不同浏览器下默认值也一样 |
| toolbar | "yes"或者"no" | 表示是否显示工具栏,默认为no |
| top | 数值 | 新窗口的Y轴坐标 |
| width | 数值 | 新窗口的高度,这个值不能小于100 |
window.open("http://www.baidu.com","wroxWindow","height=400,width=400,top=10,resizable=yes")
这行代码会打开一个可以缩放的窗口。大小为400*400像素。位于离屏幕左边和顶边10像素的位置。
window.open方法返回一个对新建窗口的引用。这个对象与普通的window对象没有区别。知识为了控制新窗口提供了方便。例如:某些浏览器不允许缩放或者移动窗口。但是可能允许缩放或者移动通过window.open创建的窗口。跟使用window对象一样.可以使用这个对象操纵打开新的窗口.
let wroxWin=window.open("http://www.wrox.com","wroxWindow",
"height=400,width=400,top=10,resizable=yes")
wroxWin.resizeTo(500,500)
wroxWin.moveTo(100,100)
我们还可以使用close()方法像这样关闭新打开的窗口.