第08章 - BOM

8.1 window 对象

window 对象扮演双重角色:即是访问浏览器的接口,又是 ECMAScript 规定的 Global 对象


8.1.1 全局作用域

在全局作用域上定义的变量和函数都会变成 window 对象的属性和方法

var age = 29;

function sayAge(){
    alert(this.age);
}

alert(window.age); //29
sayAge(); //29
window.sayAge(); //29

全局变量和 window 属性的差别之一:全局变量不能通过 delete 操作从 window 对象中删除。因为用 var 添加的 window 属性,其 [[Configurable]] 特性被设置为 false,因此不能删除

var age = 29;
window.color = "red";

//全局变量不能删除
delete window.age;

//全局属性可以删除
delete window.color; //returns true
alert(window.age); //29
alert(window.color); //undefined

全局变量和 window 属性的差别之二:访问不存在的全局变量会报错,访问不存在的 window 属性返回 undefined

//oldValue 不存在,会报错
var newValue = oldValue;

//window.oldValue 属性不存在,仅仅返回 undefined
var newValue = window.oldValue;

8.1.2 窗口关系及框架

每个框架都有自己的 window 对象,保存在 frames 中,可以通过数值索引,索引从 0 开始,顺序是从左到右、从上到下

两个特殊的框架名称:

  • top 指向最顶层框架
  • parent 指向上层框架

8.1.3 窗口位置

screenLeftscreenTop 返回显示区域的坐标,除了火狐浏览器不支持,其他几种浏览器新版本都支持。

  • 谷歌浏览器、IE 浏览器和 Win10 浏览器都返回 0 和工具栏高度
  • 火狐浏览器不支持这两个属性

screenXscreenY 返回窗口的坐标

  • 谷歌浏览器返回和 screenLeft、 screenTop 相同的值
  • 火狐和新版 IE 浏览器返回 -8 -8
  • 新版 Win10 浏览器返回 0 0

下面这段代码可以在不同浏览器下都获得数值

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

但是因为各种浏览器的返回值各不相同,所以无法在跨浏览器的条件下取得窗口的精确坐标


moveTomoveBy 方法可以将浏览器移动到准确的新位置,但是大部分新浏览器不再支持中两个方法,只有 IE 还支持

//move the window to the upper-left coordinate
window.moveTo(0,0);
//move the window down by 100 pixels
window.moveBy(0, 100);

//move the window to position (200, 300)
window.moveTo(200, 300);
//move the window left by 50 pixels
window.moveBy(-50, 0);

8.1.4 窗口大小

innerWidth, innerHeight 在各个浏览器中均返回视口大小


outerWidth, 和 outerHeight

  • 在谷歌浏览器中还是返回视口大小
  • 其他浏览器窗口大小

IE 浏览器在 IE8 之前的没有提供这几个属性。虽然无法在跨浏览器的条件下取得窗口的大小,但是可以利用下面的代码取得视口的大小

var 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;
    }
}

改变浏览器大小

resizeToresizeBy 方法可以改变浏览器的大小,但是大部分新浏览器不再支持中两个方法,只有 IE 还支持

//resize to 100 x 100
window.resizeTo(100, 100);
//resize to 200 x 150
window.resizeBy(100, 50);
//resize to 300 x 300
window.resizeTo(300, 300);

8.1.5 导航和打开窗口

window.open 方法可以导航到一个特定的 URL ,也可以打开一个新浏览器。接受四个参数:

  • URL
  • 窗口目标
  • 特性字符创
  • 历史记录

只有第一个参数是必须的,其他都有默认值


弹出窗口

下面的代码在指定框架中打开新的页面

//等同于 <a href="http://www.wrox.com" target="topFrame"></a>
window.open("http://www.wrox.com/", "topFrame");

常用的目标窗口名称

  • _self
  • _parent
  • _top
  • _blank

第三个参数可以指定浏览器的特性,比如是否隐藏工具栏地址栏等等

设置 说明
fullscreen "yes" or "no" 是否最大化
height 数值
left 数值
location "yes" or "no"
menubar "yes" or "no"
resizable "yes" or "no"
scrollbars "yes" or "no"
status "yes" or "no"
toolbar "yes" or "no"
top 数值
width 数值

window.open 方法返回窗口对象,可以对这个对象进行操作

var wroxWin =window.open("http://www.wrox.com/","wroxWindow",
            "height=400,width=400,top=10,left=10,resizable=yes");

//resize it
wroxWin.resizeTo(500, 500);

//move it
wroxWin.moveTo(100, 100);

close 方法可以关闭窗口对象,closed 属性可以检测窗口对象是否已经关闭

wroxWin.close();
alert(wroxWin.closed); //true

window 对象的 opener 属性保存着打开本 window 对象的那个 window 对象

var wroxWin =window.open("http://www.wrox.com/","wroxWindow",
            "height=400,width=400,top=10,left=10,resizable=yes");
alert(wroxWin.opener == window); //true

如果将 window 对象的 opener 属性设置为 null ,则主窗口和被打开窗口分别在独立的进程中运行,两个窗口对象不再有关系

var wroxWin =window.open("http://www.wrox.com/","wroxWindow",
            "height=400,width=400,top=10,left=10,resizable=yes");
wroxWin.opener = null;

安全限制

由于打开窗口可能存在安全隐患,大部分浏览器都设置了很多安全限制。


屏蔽程序

如果打开窗口被浏览器本身屏蔽,则 window.open 方法返回 null

var wroxWin = window.open("http://www.wrox.com", "_blank");
if (wroxWin == null){
    alert("The popup was blocked!");
}

如果打开窗口被插件或者扩展程序屏蔽,则 window.open 会抛出异常。下面的代码,无论窗口是被浏览器屏蔽,还是被扩展程序屏蔽,都可以正确处理。

var blocked = false;
try {
    var wroxWin = window.open("http://www.wrox.com", "_blank");
    if (wroxWin == null){
        blocked = true;
    }
} catch (ex){
    blocked = true;
}
if (blocked){
    alert("The popup was blocked!");
}

8.1.6 间歇调用和超时调用

超时调用:setTimeout 先等待一段时间,然后将任务添加到执行队列中。需要注意的是:执行队列中的任务是根据调度执行的,不一定立即执行

回调任务可以是字符串,但是不推荐这种用法,通常还是一个回调函数

//不推荐
setTimeout("alert(‘Hello world!’) ", 1000);

//推荐用法
setTimeout(function() {
    alert("Hello world!");
}, 1000);

setTimeout 方法返回一个标识符 ID,clearTimeout 使用这个 ID 可以取消超时调用,即不再进行超时等待,也不会向执行队列中插入任务


//设置超时调用
var timeoutId = setTimeout(function() {
    alert("Hello world!");
}, 1000);

//取消超时调用
clearTimeout(timeoutId);

间歇调用:setInterval 每隔一段时间,就向执行队列中插入任务。


//不推荐用法
setInterval("alert(‘Hello world!’) ", 10000);

//推荐用法
setInterval(function() {
    alert("Hello world!");
}, 10000);

setInterval 方法也返回一个标识符 ID,clearInterval 使用这个 ID 取消间歇调用,即不再继续向执行队列中插入新的任务,但是已经插入到执行队列中的任务会继续执行。

var num = 0;
var max = 10;
var intervalId = null;

function incrementNumber() {
    num++;

    //如果达到条件,则取消间歇调用
    if (num == max) {
        clearInterval(intervalId);
        alert("Done");
    }
}

intervalId = setInterval(incrementNumber, 500);

上面的功能也可以利用递归超时调用来完成

var num = 0;
var max = 10;
function incrementNumber() {
    num++;

    //如果满足条件则进行下一次超市调用,否则退出
    if (num < max) {
        setTimeout(incrementNumber, 500);
    } else {
        alert("Done");
    }
}

setTimeout(incrementNumber, 500);

超时调用在等待一定时间、向执行队列添加任务,然后退出;而间歇调用会不断地向执行队列中添加任务,想要退出必须手动调用 clearInterval 方法。因此,应该尽可能的使用超时调用,而不是间歇调用。

8.1.7 系统对话框

8.2 location 对象

location 对象是最有用的 BOM 对象之一:

  • 它保存着当前加载文档的一些有用信息
  • 可以进行导航
  • 既是 window 的属性,又是 document 的属性
  • 将 URL 进行了解析,并将各部分信息保存在自己的属性中
属性名 例子 说明
host "www.wrox.com:80" 主机名加端口
hostname "www.wrox.com" 主机名
href "http:/www.wrox.com" 当前加载页的完整 URL,location 对象的 toString() 方法返回的也是这个值
hash "#contents" 返回 URL 中的 hase
pathname "/WileyCDA" 返回路径或者文件名
port "8080" 端口号
protocol "http:" 协议字符串
search "?q=javascript" 查询字符串

8.2.1 解析查询字符串参数

算法:

  • 第一步:把首字母 ? 去掉
  • 第二步:用 "&" 字符切分查询字符串,得到查询键值对
  • 第三步:将每个键值对用 "=" 切分,得到键值
  • 第四步:别忘了用 decodeURIComponent 解码

function getQueryStringArgs(){
    //get query string without the initial ?
    var qs = (location.search.length > 0 ? location.search.substring(1) : ""),
    
    //object to hold data
    args = {},
    
    //get individual items
    items = qs.length ? qs.split("&") : [],
    item = null,
    name = null,
    value = null,
    
    //used in for loop
    i = 0,
    len = items.length;
    
    //assign each item onto the args object
    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;
}

//assume query string of ?q=javascript&num=10
var args = getQueryStringArgs();

alert(args["q"]); //"javascript"
alert(args["num"]); //"10"

8.2.2 改变位置

location.assign 方法改变浏览器的位置

设置 window.location 和 location.href 属性也是调用 assing 方法,效果一样


location.assign("http://www.wrox.com");

window.location = "http://www.wrox.com";
location.href = "http://www.wrox.com";

设置 location 对象的其他属性也可以改变浏览器位置


//assume starting at http://www.wrox.com/WileyCDA/
//changes URL to "http://www.wrox.com/WileyCDA/#section1"
location.hash = "#section1";
//changes URL to "http://www.wrox.com/WileyCDA/?q=javascript"
location.search = "?q=javascript";
//changes URL to "http://www.yahoo.com/WileyCDA/"
location.hostname = "www.yahoo.com";
//changes URL to "http://www.yahoo.com/mydir/"
location.pathname = "mydir";
//changes URL to "http://www.yahoo.com:8080/WileyCDA/

防止产生历史记录

location.replace() 方法可以重新定位浏览器位置,但是不产生历史记录


<!DOCTYPE html>
<html>
<head>
    <title>You won’t be able to get back here</title>
</head>

<body>
    <p>Enjoy this page for a second, because you won’t be coming back here.</p>
    <script type="text/javascript">
        setTimeout(function () {
            location.replace("http://www.wrox.com/");
        }, 1000);
    </script>
</body>
</html>

重新加载页面

location.reload() 方法重新加载页面。注意:调用这个方法后,因为重新加载页面,所以之后的代码可能不会被执行。

location.reload(); //可能会从缓存加载
location.reload(true); //强制从服务器加载

8.3 navigator 对象

通过读取 navigator 对象的各种属性,可以获取浏览器的各种信息。具体用法可以查阅资料

8.3.1 检测插件

navigator 对象的 plugins 属性是个数组,其中每一项都是包含一个插件的信息

//插件检测,在 IE 下不工作
function hasPlugin(name){
    name = name.toLowerCase();
    for (var i=0; i < navigator.plugins.length; i++){
        if (navigator.plugins[i].name.toLowerCase().indexOf(name) > -1){
            return true;
        }
    }
    return false;
}

//检测 flash
alert(hasPlugin(”Flash”));
//检测 quicktime
alert(hasPlugin(”QuickTime”));

检测 IE 中的插件要使用 ActiveXObject

//检测 Internet Explorer 插件
function hasIEPlugin(name){
    try {
        new ActiveXObject(name);
        return true;
    } catch (ex){
        return false;
    }
}

//检测 flash
alert(hasIEPlugin(“ShockwaveFlash.ShockwaveFlash”));
//检测 quicktime
alert(hasIEPlugin(“QuickTime.QuickTime”))

综合使用上面两种方法可以检测各种浏览器的插件

//检测 flash
function hasFlash(){
    var result = hasPlugin(“Flash”);

    if (!result){
        result = hasIEPlugin(“ShockwaveFlash.ShockwaveFlash”);
    }

    return result;
}

//检测 quicktime
function hasQuickTime(){
    var result = hasPlugin(“QuickTime”);

    if (!result){
        result = hasIEPlugin(“QuickTime.QuickTime”);
    }

    return result;
}

//检测 flash
alert(hasFlash());
//检测 quicktime
alert(hasQuickTime());

8.3.2 注册处理程序

还不成熟,不需要了解

8.4 screen 对象

screen 可以获取用户显示器的各种信息,相关属性和方法请自行查阅资料

8.5 history 对象

每个窗口和框架都有自己的 history 对象,他是 window 的一个属性。利用 history 对象,可以在用户的浏览历史页面中跳转

按编号跳转

//go back one page
history.go(-1);

//go forward one page
history.go(1);

//go forward two pages
history.go(2);

按站点名字跳转

//go to nearest wrox.com page
history.go(“wrox.com”);

//go to nearest nczonline.net page
history.go(“nczonline.net”);

向前向后跳转

//go back one page
history.back();

//go forward one page
history.forward();

判断当前页面是否是当前窗口打开的第一个页面

if (history.length == 0){
    //this is the first page in the user’s window
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • ECMAScript 是 JavaScript 的核心,但如果要在 Web 中使用 JavaScript,那么 B...
    劼哥stone阅读 807评论 2 5
  • 最近在图书馆看到了一本名为《我曾在深夜痛哭,想要和你聊人生》的书,翻开看了几页,我已没有了读下去的勇气,不是因为书...
    小璇风阅读 626评论 0 2
  • 三年前的夏天,李先生告诉我,如果你想嫁那我就娶你啊。 奈何三年过去了,李先生和我已然断了联系。 这些年来,陆...
    亦里木阅读 288评论 0 0
  • 如果要找一个跟修行类似的事情来,我会选运动。 先从专业说起。运动员的作息时间是最接近僧人的。看篮球的都知道已经退役...
    梵夫说阅读 290评论 0 0
  • 风对雨说再猛些吗没问题 雨向大地讲我要你沐浴树、花与小草频点头又弯腰 风顺雨意万物迎了雨
    蒋光头jL94430阅读 974评论 15 16