# window 对象

# 全局作用域

window 对象是 ECMAScript 中 Global 对象。因此所有全局作用域中声明的变量、函数都会变为 window 对象的属性和方法;

抛开全局变量会成为 window 对象的属性不谈,定义全局变量与在 window 对象上直接定义属性还是有一点差别:全局变量不能通过 delete 操作符删除,而直接在 window 对象上定义的属性可以。

var age = 18
window.color = 'red'

// 在 IE9 < 9 时抛出错误,在其他浏览器中都返回 false
delete window.age

// 在 IE9 < 9 时抛出错误,在其他浏览器中都返回 true
delete window.color

console.log(window.age) // 18
console.log(window.color) // undefined

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

# 窗口关系及框架

如果页面中包含框架,则每个框架都拥有自己的 window 对象,并且保存在 frames 集合中,可以通过数值索引(从 0 开始,从左至右,从上至下)或者框架名称来访问相应的 window 对象。每个 window 对象都有一个 name 属性,其中包含框架的名称,如下面代码:

<html>
  <head>
    <title>Frame Example</title>
  </head>
  <frameset rows="160, *">
    <frame src="frame.html" name="topFrame"></frame>
    <frameset cols="50%, 50%">
      <frame src="anotherframe.html" name="leftFrame"></frame>
      <frame src="yetanotherframe.html" name="rightFrame"></frame>
    </frameset>
  </frameset>
</html>

对于这个例子,可以通过 window.frames[0] 或者 window.frames['topFrame'] 来获取上方的框架,可以使用 top 而非 window 来引用这些框架:top.frames[0]

top 对象始终指向最高(最外)层的框架,也就是浏览器的窗口;使用它可以确保在一个框架中正确地访问另一个框架,因为对于在一个框架中编写的任何代码来说,其中的 window 对象指向的都是那个框架的特定实例,而非最高层的框架。下图是不同框架中,访问自身的不同方式:

在这里插入图片描述

与 top 相对的另一个 window 对象是 parent,顾名思义,parent 对象始终指向当前框架的直接上层框架,在没有框架的情况下,parent 一定等于 top,也就是都等于 window 对象。

与框架有关的最后一个对象是 self,他始终指向 window,实际上 self 和 window 对象可以互换使用。引入 self 对象的目的是为了与 top 和 parent 对象对应起来,因此他不额外包含其他值。

# 窗口位置

screenLeft 和 screenTop 属性,分别用于表示窗口相对于屏幕左边以及上边的位置。使用下列代码可以跨浏览器取得窗口左边和上边的位置:

var leftPos = (typeof window.screenLeft === 'number') ? window.screenLeft : window.screenX
var topPos = (typeof window.screenTop === 'number') ? window.screenTop : window.screenY

需要注意的是:在 IE、Opera 中,screenLeft 和 screenTop 中保存的是从屏幕左边和上边到由 window 对象表示的页面可见区域的距离。换句话说,如果 window 对象是最外层对象,而且浏览器窗口紧贴屏幕最上端,也就是 y 轴坐标为 0,那么 screenTop 的值就是位于页面可见区域上方的浏览器工具栏的像素高度。但是在 Chrome、Firefox 中,screenY 或 screenTop 中保存的是整个浏览器窗口相对于屏幕的坐标值,即 0 ;

使用 moveTo() 和 moveBy() 方法游客可能将窗口精确地移动到一个新的位置。这两个方法都接收两个参数:

moveTo() 方法接收的新位置的 x 和 y 坐标值; moveBy() 方法接收的是在水平和垂直方向上移动的像素值。

// 将窗口移动到屏幕左上角
window.moveTo(0, 0)

// 将窗口向下移动 100 像素
window.moveBy(0, 100)

// 将窗口移动到 200,300
window.moveTo(200, 300)

// 将窗口向左移动 50 像素
window.moveBy(-50, 0)

需要注意的是,这链各个方法可能会被浏览器禁用,而且,在 Opera 和 IE 7(及更高的版本)中默认就是禁用的。另外,这链各个方法都不适用与框架,只能对最外层的 window 对象使用。

如果符合下列情况,则普通网页中的 JavaScript 无法通过调用该函数来移动浏览器窗口

  • 当前窗口或标签页不是由window.open方法创建的
  • 当前标签页所在的窗口包含有多个标签页

# 窗口大小

  • IE9+、Safari 和 Firefox:outerWidth 和 outerHeight 返回浏览器窗口本身的尺寸(无论从最外层的 window 对象还是从某个框架访问);
  • Opera:outerWidth 和 outerHeight 表示页面视图容器的大小,也就是单个标签页对应的浏览器窗口;
  • Chrome:outerWidth 和 outerHeight 与 innerWidth 和 innerHeight 返回相同的值,即视口大小而非浏览器窗口大小;

获取页面视口的大小,如下代码:

var pageWidth = window.innerWidth
var 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
  }
}

使用 resizeTo() 和 resizeBy() 方法可以调整浏览器窗口的大小,都接收两个参数:

  • resizeTo() 接收浏览器窗口的新高度和新宽度
  • resizeBy() 接收新窗口与原窗口的宽度和高度之差
// 调整到 100 * 100
window.resizeTo(100, 100)

// 调整到 200 * 150
window.resizeBy(100, 50)

// 调整到 300 * 300
window.resizeTo(300, 300)

# 导航和打开窗口

使用 window.open 既可以导航到一个特定的 URL,也可以打开一个新的浏览器窗口,他接收 4 个参数:

  1. 要加载的URL;
  2. 窗口目标;
  3. 一个特性字符串;
  4. 一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值;

最后一个参数只在不打开新窗口的情况下使用;

如果为 window.open() 传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定 URL:

// 等同于 <a href="http://jiegiser.github.io/note" target="topFrame"></a>
window.open("http://jiegiser.github.io/note", "topFrame")

调用上面的代码就相当于用户点击了那个 a 标签,如果有一个名叫 toFrame 的窗口或者框架,就会在该窗口或框架加载这个 URL,否则就会创建一个新的窗口并将其命名为 topFrame。

# 弹出窗口

如果给 window.open() 传递的第二个参数并不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传人的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,那么就会打开一个带有全部默认设置(工具栏、地址栏和状态栏等)的新浏览器窗口(或者打开一个新标签页--根据浏览器设置)在不打开新窗口的情况下,会忽略第三个参数。 第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。下表列出了可以出现这个字符串中的设置选项:

设置 说 明
fullscreen yes 或 no 表示浏览器窗口是否最大化。仅限 IE
height 数值 表示新窗口的高度。不能小于 100
left 数值 表示新窗口的左坐标。不能是负值数值
location yes 或 no 表示是否在浏览器窗口中显示地址栏。不同浏览器的默认值不同。如果设置为 no,地址栏可能会隐藏,也可能会被禁用(取决于浏览器)
menubar yes 或 no 表示是否在浏览器窗口中显示菜单栏。默认值为 no
resizable yes 或 no 表示是否可以通过拖动浏览器窗口的边框改变其大小。默认值为 no
status yes 或 no 表示是否在浏览器窗口中显示状态栏。默认值为 no
toolbar yes 或 no 表示是否在浏览器窗口中显示工具栏。默认值为 no
top yes 或 no 表示新窗口的上坐标。不能是负值
width yes 或 no 表示新窗口的宽度。不能小于 100

上面的属性都可以通过键值对形式的字符串来指定,其中键值对中不能出现空格:

window.open('jiegiser.github.io/note', 'note', 'height=400,widht=400,top=10,left=10,resizable=yes')

window.open() 方法会返回一个指向新窗口的引用。引用的对象与其他 window 对象大致相似,但我们可以对其进行更多控制。例如,有些浏览器在默认情況下可能不允许我们针对主浏览器窗口调整大小或移动位置,但却允许我们针对通过 window.open() 创建的窗口调整大小或移动位置。通过这个返回的对象,可以像操作其他窗口一样操作新打开的窗口,如下所示。

var note = window.open('jiegiser.github.io/note', 'note', 'height=400,widht=400,top=10,left=10,resizable=yes')

// 调整大小
note.resizeTo(500, 500)

// 移动位置
note.moveTo(100, 100)

使用 close() 方法还可以关闭新打开的窗口

note.close()

这个方法仅适用于 window.open() 打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户的允许是不能关闭它的。不过,弹出窗口倒是可以通过调用 top.close() 在不经过用户允许的情况下关闭自己。弹出窗口关闭之后,窗口的引用仍然还在,但除了像下面检测其 closed 属性之外,已经没有其他用处了:

note.close()
console.log(note.closed) // true

新创建的窗口中有一个指针指向打开它的原始窗口对象,这个属性只在弹出窗口中的最外层 window 对象 (top) 中有定义,而且指向调用 window.open() 的窗口或框架:

var note = window.open('jiegiser.github.io/note', 'note', 'height=400,widht=400,top=10,left=10,resizable=yes')
note.opener === window // true

有些浏览器(如 IE8 和 Chrome)会在独立的的进程中运行每个标签页。当一个标签页打开另一个标签页时,如果两个 window 对象之间需要彼此通信,那么新标签页就不能运行在独立的进程中,在 chrome 中,将新创建的标签页的 opener 属性设置为 null,即表示在单独的进程中运行新标签页,如下代码:

var note = window.open('jiegiser.github.io/note', 'note', 'height=400,widht=400,top=10,left=10,resizable=yes')
note.opener = null

将 opener 属性设置为 null 就是告诉浏览器新创建的标签页不需要与打开它的标签页通信,因此可以在独立的进程中运行。标签页之间的联系一旦断开,将没有办法恢复。

# 弹出窗口屏蔽程序

在弹窗窗口被屏蔽时,就应该考虑两种可能性。如果浏览器内置的屏蔽程序阻止的弹出窗口,那么 window.open() 很可能会返回 null,此时,只要检测这个返回的值就可以确定窗口是否被屏蔽了,如下代码:

var note = window.open('jiegiser.github.io/note', '_blank')
if (note === null) {
  console.log('the popup was blocked!')
}

如果是浏览器扩展或其他程序阻止的弹出窗口,那么 window.open() 通常会抛出一个错误,因此,想要准确地检测出弹出窗口是否被屏蔽,必须在检测返回值的同时,将对 window.open() 的调用封装在一个 try catch 块中,如下:

var blocked = false

try {
  var note = window.open('jiegiser.github.io/note', '_blank')
  if (note === null) {
    blocked = true
  }
} catch(ex) {
  blocked = true
}

if (blocked) {
  console.log('the popup was blocked!')
}

需要注意的是检测弹出窗口是否屏蔽只是一方面,他并不会阻止浏览器显示与被屏蔽的弹出窗口有关的消息。

# setTimeout/setInterval

setTimeout 的第二个参数是一个表示等待多长时间的毫秒数,但经过该时间后指定的代码怒一定会执行,JavaScript 是一个单线程的解释器,因此一定时间内只能执行一段代码。为了控制要执行的代码,就会有一个 JavaScript 任务队列。这些任务会按照将他们添加到队列的顺序执行。setTimeout() 的第二个参数告诉 JavaScript 再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不为空,那么他就要等前面的代码执行完了以后再执行。

setTimeout 调用的代码都是在全局作用域中执行的,因此函数中 this 的值在非严格模式下指向 window 对象,在严格模式下是 undefined。

# 系统对话框

浏览器通过 alert()、confirm() 和 prompt() 方法可以调用系统对话框向用户显示消息。显示这些对话框的时候代码会停止执行,而关掉这些对话框后代码又会恢复执行。

对于 confirm() 可以检查他的一个返回的布尔值,true 代表点击了 ok,false 表示点击了取消或者点击了关闭按钮,确认对话框的典型用法如下:

if(confirm('Are you sure?')) {
  console.log('Yes')
} else {
  console.log('No')
}

对于 prompt(),提示框中除了显示确定以及取消按钮以外,还会显示一个文本输入域,以供用户在其中输入内容。他接受两个参数:要现实给用户的文本提示和文本输入域的默认值(可以是一个空字符串);点击确定会返回文本域中的值,如果点击了取消或者没有点击确定而是通过其他方式关闭了对话框,则方法返回 null:

var result = window.prompt('what are your name?', '')
if (result !== null) {
  console.log('welcome,' + result)
}

还有两个可以通过 JavaScript 打开的对话框:

// 显示 打印 对话框
window.print()

// 显示 查找 对话框
window.find()

# location 对象

location 对象既是 window 对象的属性,也是 document 对象的属性。换句话说, window.location 和 document.location 引用的是同一个对象。

属性名 例子 说 明
hash '#contents' 返回 URL 中的 hash(# 号后跟零或多个字符),如果 URL 中不包含散列,则返回空字符串
host 'www.wrox.com:80' 返回服务器名称和端口号(如果有)
hostname 'www.wrox.com' 返回不带端口号的服务器名称
href 'http://www.wrox.com' 返回当前加载页面的完整 URL。而 location 对象的 tostring() 方法也返回这个值
pathname 'WileyCDA' 返回URL中的目录和(或)文件名
port '8080' 返回 URL 中指定的端口号。如果 URL 中不包含端口号,则这个属性返回空字符串
protocol 'http:' 返回页面使用的协议。通常是 http: 或 https:
search '?q=javascript' 返回 URL 的査询字符串。这个字符串以问号开头

# 查询字符串参数

下面代码是解析查询字符串,然后返回包含所有参数的对象:

function getQueryStringArgs() {
  // 取得查询字符串并去掉开头的问号
  var qs = (location.search.length > 0 ? location.search.substring(1) : '')
  
  // 保存数据的对象
  args = {}

  // 取得每一项
  items = qs.length ? qs.split('&') : []
  item = null
  name = null
  value = ''
  // 在 for 循环中使用
  i = 0
  len = items.length

  // 逐个将每一项添加到 args 中
  for (i = 0; i < len; i ++) {
    item = items[i].split('=')
    name = decodeURIComponent(item[0])
    value = decodeURIComponent(item[1])

    if (name.length) {
      args[name] = value
    }
  }
  return args
}

# 位置操作

使用 assign() 方法,改变浏览器的位置;需要传递一个 URL 参数:

location.assign('https://github.com/jiegiser')

如果是将 location.href 或 window.location 设置为一个 URL 值,也会以该值调用 assign() 方法。下面两行代码与显示调用 assign() 方法的效果一致:

window.location = 'https://github.com/jiegiser'
location.href = 'https://github.com/jiegiser'

另外修改 location 对象的其他属性也可以改变当前加载的页面。如下:

// 假设初始 URL 为 http://www.wrox.com/WileyCDA/

// 将 URL 修改为 http://www.wrox.com/WileyCDA/#section1
location.hash = '#section1'

// 将 URL 修改为 http://www.wrox.com/WileyCDA/?q=javascript
location.search = '?q=javascript'

// 将 URL 修改为 http://www.yahoo.com/WileyCDA/
location.hostname = 'www.yahoo.com'

// 将 URL 修改为 http://www.yahoo.com/mydir/
location.pathname = 'mydir'

// 将 URL 修改为 http://www.yahoo.com:8080/WileyCDA/
location.port = 8080

每次修改 location 的属性(hash 除外),页面都会以新 URL 重新加载。

通过上面修改 URL 之后,是可以通过点击浏览器的后退按钮回退,使用 replace() 方法,不会再浏览器的历史记录生成新的记录;他会替换当前浏览记录。这个方法就收一个参数,就是要导航到的 URL:

location.replace('https://jiegiser.github.io/note')

页面重新加载 reload() 方法。作用就是重新加载当前显示的页面。如果没有传递任何参数,并且页面自上次请求并没有改变过,页面就会从浏览器缓存中重新加载。如果需要强制从服务器重新加载,则需要穿第一个参数 true :

location.reload() // 重新加载(有可能从缓存中加载)
location.reload(true) // 重新加载(从服务器重新加载)

# nagigator 对象

# 检查插件

检查浏览器是否安装了特定的插件,使用 plugins 数组来获取,数组中的每一项都会包含下列属性:

  • name: 插件的名字
  • description: 插件的描述
  • filename:插件的文件名
  • length:插件所处理的 MIME 类型数量

下面代码是检测插件是否存在:

// 检测插件(在 IE 中无效)
function hasPlugins(name) {
  name = name.toLowerCase()
  for(var i = 0; i < nagigator.plugins.length; i ++) {
    if (nagigator.plugins[i].name.toLowerCase().indexOf(name) > -1) {
      return true
    }
  }
  return false
}

// 检测 Flash
console.log('Flash')

// 检测 QuickTime
console.log('QuickTime')

在 IE 浏览器中可以使用 ActiveXObject 类型,并尝试创建一个特定插件的实例,IE 中的插件是以 COM 对象的方式实现插件的,每个 COM 对象都有一个唯一标识,可以入戏代码进行检查:

// 检测 IE 中的插件
function hasIEPlugins(name) {
  try {
    new ActiveXObject(name)
    return true
  } catch(ex) {
    return false
  }
}

# history 对象

使用 go() 方法可有在用户的历史记录中任意跳转。可以向后也可以向前跳转。该方法接收一个参数,一个正数或者负数的页面数(整数值):

// 后退一页
history.go(-1)

// 前进一页
history.go(1)

// 前进两页
history.go(2)

也可以给 go() 方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置,可能后退,也可能前进。具体看哪个位置最近。如果历史记录中不包含该字符串,那么这个方法什么也不做:

// 跳转到最近的 wrox.com 页面
history.go('wrox.com')

// 跳转到最近的 nczonline.net 页面
history.go('nczonline.net')

另外还有两个简写方法 back() 和 forward() 来代替 go(),这两个方法就是后退和前进。

history 还有一个 length 属性,保存着历史记录的数量,如果是一个新的页面,那么这个属性为 0:

if (history.length === 0) {
  // 这应该是用户打开窗口后的第一个页面
}

评 论:

更新: 12/27/2020, 4:59:16 PM