先来说一下BOM,什么是BOM?BOM就是浏览器对象模型,大家都知道,ECMAScript是JavaScript的核心,但如果要在WEB中使用JavaScript,那么BOM则无疑才是真正的核心,BOM,提供很多对象,用于访问浏览器功能,这些功能与任何页面内容无关,多年来,缺少事实上的规范导致BOM既有意思又有问题,因为浏览器提供商会按照各自的想法去拓展它,于是,浏览器之间共有的对象就成为了事实上的标准。
BOM的核心对象是window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过JavaScript访问浏览器的一个接口,又是ECMAScript规定的Global对象,这意味着在网页中定义的任何一个对象、变量和函数,都以window作为其Global对象,因此有权访问parseInt()等方法。
不过,定义全局变量与在window对象上直接定义属性还是有一点差别的:全局变量不能通过delete操作符删除,而直接在window对象上定义的属性可以。
BOM的作用:控制窗口、框架、和弹出窗口,利用location对象中的页面信息、使用navigator对象了解浏览器、screen对象以及history对象等。
今天主要来介绍一下Frame框架,
如果页面中包含框架,则每个框架,都拥有自己的window对象,并且保存在frames集合中,。在frames集合中,可以通过数值索引(从0开始,从左至右,从上到下)或者框架名称来访问相应的window对象,每个window对象都有一个name属性,其中包含框架的名称。
来个例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>练习</title> </head> <frameset rows="160,*"> <frame src="frame.htm" name="topFrame"> <frameset cols="50%,50%"> <frame src="anotherframe.htm" name="leftframe"> <frame src="yetanotherframe.htm" name="rightframe"> </frameset> </frameset> </html>
上面代码表示,把窗口分3个框架,上面高160px,剩下的都是下面的框架,(rows=160,*)
下面的框架又分两个框架,左右各占50%,(cols="50%,50%"),
另外,每个frame框架,可以再次细分,在这就不再细分了,
下面来说一下,怎么取到每一个框架,(要在最外层的框架里写js代码哟,当然在里层框架内也可以写js代码,不过今天的代码都是在最外层框架写的)。
按上、左、右的顺序依次取:
上:window.frames[0]、window.frames["topFrame"]、top.frames.[0]、top.frames["topFrame"]、frames[0]、frames["topFrame"]。
下左:window.frames[1]、window.frames["leftframe"]、top.frames.[1]、top.frames["leftframe"]、frames[1]、frames["leftframe"]。
下左:window.frames[2]、window.frames["rightframe"]、top.frames.[2]、top.frames["rightframe"]、frames[2]、frames["rightframe"]。
注释:top对象始终指向最高(最外)层的框架,也就是浏览器窗口。使用它可以确保在一个框架中正确的访问另一个框架。因为对于在一个框架中编写的任何代码来说,其中的window对象指向的都是那个框架的特定实例,而非最高层的框架。
与top相对的另一个window对象是patent。顾名思义,parent(父)对象始终指向当前框架的直接上层框架,在某些情况下,parent有可能等于top;但在没有框架的情况下,parent一定等于top。
注意:每个框架中的window对象都是独立的,都有自己的构造函数。
窗口位置:
获取窗口位置,因为浏览器对screenLeft、screenTop与screenX、screenY支持的不同,所以用一个兼容的方法来获取窗口位置:
// 获取窗口位置
var leftPos=(typeof window.screenLeft=="number")?window.screenLeft:window.screenX;
var topPos=(typeof window.screenTop=="number")?window.screenTop:window.screenY;
console.log(leftPos);//窗口距离屏幕左边的距离(px)
console.log(topPos);//窗口距离屏幕上边的距离(px)
以上代码,在跨浏览器情况下还是无法精确的获得到窗口的位置,若果想精确获取,需要分浏览器讨论,不过多讲述。
移动窗口:
然而,使用moveTo()、moveBy()却可能将窗口精确的移动到一个位置。这两个方法都接收两个参数,其中moveTo()接收的是新位置的x和y坐标值,而moveBy()接收的是在水平和垂直方向上移动的像素数。
window.moveTo(0,0);//将窗口移动到窗口左上角
window.moveBy(0,100);//将窗口向下移动100像素。
window.moveTo(200,300);//将窗口移动到(200,300);
window.moveBy(-50,0);//将窗口向左移动50像素;
这两个方法经常会被浏览器禁用,不适用与框架,不起作用很正常。
窗口大小:
innerWith、innerHeight:是窗口的可视区域大小,不包括边框
outerWidth、outerHeight:是窗口的整体大小,包括边框
在Chrome浏览器中上述两种值返回的大小一样,引浏览器而异。
document.documentElement.clientWidth、document.documentElement.clientHeight中保存了页面视口信息,
但在IE6混杂模式下必须通过document.body.clientWidth、document.body.clientHeight才能取得相同信息。
虽然最终无法确定浏览器窗口本身大小,但却可以取得页面视口的大小,如下所示:
var pageWidth=window.innerWidth;
var pageHeight=window.innerHeight;
if(typeof pageWidth!="number"){//检查pageWidth是否是数值,因为IE8以上版本才支持上面属性
if(document.compatMode=="CSS1Compat"){//检查是否处于标准模式
pageWidth=document.documentElement.clientWidth;
pageHeight=document.documentElement.clientHeight;
}else{
pageWidth=document.body.clientWidth;
pageHeight=document.body.clientHeight;
}
}
console.log(pageWidth);//787
console.log(pageHeight);//657
改变窗口大小:
resizeTo()和resizeBy()方法可以调整浏览器窗口大小,这两个方法接收两个参数,其中resizeTo()接收浏览器窗口的新宽度和新高度,resizeBy()接收新窗口与原窗口宽度与高度之差。如:
window.resizeTo(100,100);//调整到100x100
window.resizeBy(100,50);//调整到200x150
window.resizeTo(300,300);//调整到300x300
以上方法同样被浏览器禁用,同样不适用框架。。。
导航和弹出窗口:
window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。这个方法可以接受4个参数:要加载的URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。通常只需传递第一各参数,最后一个参数只在不打开新窗口的情况下使用。
如果window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数参数指定的URL。
window.open("http://www.baidu.com","topFrame");
如果topFrame框架不存在,就会创建一个新窗口并将其命名为topFrame,此外,第二个参数也可以是下列任何一个特殊的窗口名称:_self、_parent、_top、_blank
window.open("http://www.baidu.com","_self");
上面代码将会在自己的窗口下打开百度
弹出窗口:
当第二个参数并不是一个已存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串创建一个新窗口或新标签,如果没有传入第三个参数,那么就会打开一个带有全部默认设置(工具栏、地址栏、状态栏等)的新浏览器窗口,在不打开新窗口的情况下,会忽略第三个参数。
第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。
下面是这个字符串的设置选项:
设置 | 值 | 说明 |
fullscreen | yes或no | 表示浏览器窗口是否最大化 |
height | 数值 | 表示新窗口的高度。不能小于100 |
left | 数值 | 表示新窗口的左坐标。不能是负值 |
location | yes或no | 表示是否在浏览器窗口中显示地址栏。不同浏览器的默认值不同。如果是no,地址栏可能会隐藏,也可能会被禁用 |
menubar | yes或no | 是否显示菜单栏。默认为no |
resizable | yes或no | 是否可以拖动浏览器边框改变窗口大小,默认为no |
scrollbars | yes或no | 如果内容在视口中显示不下,是否允许滚动。默认为no |
status | yes或no | 是否在浏览器窗口中显示状态栏。默认为no |
toolbar | yes或no | 是否显示工具栏。默认为no |
top | 数值 | 新窗口的上坐标 |
width | 数值 | 新窗口的宽度,不能小于100 |
用法:
window.open("http://www.baidu.com","xinchaungkou","heihgt=400,400,top=10,left=10,resizable=yes");
上述代码会打开一个新的可以调整大小的窗口,窗口初始大小为400x400像素,并且距屏幕上沿和左边都是10像素。
var xinchuangkou=window.open("http://www.baidu.com","xinchaungkou","heihgt=400,400,top=10,left=10,resizable=yes");
xinchuangkou.moveTo(200,200);//将新建窗口移动到(200,200)的位置
xinchuangkou.resizeTo(300,300);//将新窗口大小变到300x300
xinchuangkou.close();//关闭新打开的窗口
用window.open()打开的新窗口可以用moveTo()和resizeTo()等方法,也可以用close()方法关闭。
xinchuangkou.opener指向打开它的原窗口。
xinchuangkou.opener==null;//将新打开的窗口与原窗口通信切断,是其在单独的进程中运行
检测window.open()的新窗口是否被屏蔽:
如果是浏览器内置的屏蔽程序阻止的弹出窗口,那么window.open()很可能会返回null。此时,只要检测这个返回的值就可以确定弹出窗口是否被屏蔽了。
如果是浏览器拓展或其他程序阻止的弹出窗口,那么window.open()通常会抛出一个错误。因此,要想准确的地检测出窗口是否被屏蔽,必须在检测返回值的同时,将对window.open()的调用封装在一个try-catch块中,如下所示:
var blocked=false;
try{
var xinchuangkou=window.open("http://www.baidu.com","xinchaungkou","heihgt=400,400,top=10,left=10,resizable=yes");
if(xinchuangkou==null){
blocked=true;
}
}catch(ex){
blocked=true;
}
if(blocked){
alert("the popup was blocked!");
}
超时调用和间歇调用:
//超时调用:setTimeout();
var timeOut=setTimeout(function(){alert("函数")},1000);
//取消超时调用
clearTimeout(timeOut);
//间歇调用:setInterval();
var intervalId=setInterval(function(){alert("函数")},2000);
//取消间歇调用
clearInterval(intervalId);
注意 :超时调用和间歇调用的代码是在全局环境中执行的,因此函数中的this值在非严格模式下指向window对象,在严格模式下是undefined;
另外,这两个方法的在指定的时间后,并不一定立即执行,因为javascript是单线程语言,当事件到了之后,如果队列有任务在执行,他会等到这任务结束再执行,如果队列为空,那么它才会立即执行;
系统对话框:
alert()、confirm()、prompt()
//alert()是警告框,参数是字符串,不过多介绍
//confirm()是确认框,会有ok和cancel两个按钮
if(confirm("你选择确认还是取消")){
alert("确认");
}else{
alert("取消");
}
//prompt()是提示框,用于提示用户输入一些文本,除了有ok和cancel按钮外,还有一个文本输入域
//该方法接收两个参数,要显示给用户的文本提示和文本输入域的默认值(可以为空字符串)
//若点击确认,会返回输入域的值,若点击取消或以其他方式关闭对话框,会返回null
var result=prompt("请输入你的名字","tom");
if(result!=null){
alert("你的名字是:"+result);
}
location对象:
location对象是最有用的BOM对象之一,它提供了域当前窗口中加载的文档有关的信息,还提供了一些导航的功能,它还有一些特别,location对象即使window的属性,又是document的属性,所以window.location和document.location是同一个对象,下面列出location对象的所有属性:
属性名 | 例子 | 说明 |
hash | “#contents” | 返回url中的hash(#号后跟零或多个字符),如果url中不包含散列(hash值),则返回空字符串 |
host | “www.wrox.com:80” | 返回服务器名称和端口号(如果有) |
hostname | “www.wrox.com” | 返回不带端口号的服务器名称 |
href | “www.wrox.com:80” | 返回当前加载页面的完整url,而location对象的toString()方法也返回这个值 |
pathname | "wileyCDA" | 返回url中目录和(或)文件名 |
port | "8080" | 返回url中指定的端口号,如果url中不含端口号,则返回空字符串 |
protocol | “http:” | 返回页面使用的协议。通常是http:或https: |
search | "?q=javascript" | 返回url中的查询字符串。这个字符串以问号开头 |
location.search返回从?到url末尾的所有内容,但是却没有办法逐个访问其中的每个查询字符串参数,因此可以封装一个方法返回一个包含所有参数的对象;
// window.location=window.location+"?name=tom&age=32"; function getQueryStringArgs(){ //取得查询字符串并去掉开头的问号 var qs=(window.location.search.length>0?window.location.search.substring(1):""); //保存数据的对象 var args={}; //取得每一项 var items = qs.length ? qs.split("&") : []; var item = null,name=null,value=null; //在for循环中使用 var 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; } var args=getQueryStringArgs(); console.log(args);//{name: "tom", age: "32"} console.log(args.name);//tom console.log(args.age);//32
位置操作:
location.assign("http://www.baidu.com");
window.location="http://www.baidu.com";
location.href="http://www.baidu.com";
上面三个方法都一样,都可以打开对应url的页面
利用location的属性来将原来的url该成新的url
//假设初始的url值为http://www.wrox.com/wileyCDN/
//将url修改为"http://www.wrox.com/wileyCDN/#section1"
location.hash="#section1";
//将url修改为"http://www.wrox.com/wileyCDN/?q=javascript"
location.search="?q=javascript";
//将url修改为"http://www.yahoo.com/wileyCDN/#section1"
location.hostname="www.yahoo.com";
//将url修改为"http://www.wrox.com/wileyCDN/mydir/"
location.pathname="mydir";
//将url修改为"http://www.wrox.com:8080/wileyCDN/"
location.port=8080;
//每次修改location的属性(hash除外),页面都会以新的url重新加载。
//注意修改hash值不会重新加载页面,只会在浏览器历史记录中生成一条新记录
上诉方法都会在浏览器历史中留下历史记录,"后退"按钮会导航到前一个页面。而用location.replace(url)方法跳转页面,不会产生历史记录,所以不会返回到之前的页面。
最后一个方法,location.reload()方法会刷新当前url,若果不传参数,就会用最有效的方式重新加载,比如浏览器缓存中加载;
如果location.reload(true),传了true,会重新请求服务器,重新加载。location.reload()之后的代码有可能执行,也有可能不执行,取决于网络延迟或系统资源等因素。
navigator对象,可用来识别客户端浏览器的事实标准。userAgent属性存在所有浏览器中的navigator对象中,比较有用
检测插件:对于非IE浏览器,可以使用plugins数组来达到这个目的。该数组中的每一项都包含下列属性:
name:插件名称
description:插件描述
filename:插件的文件名
length:插件所处理的MIME类型数量
//非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; } //在IE中检测插件 function hasIEPlugin(name){ try{ new ActiveXObject(name); return true; }catch(ex){ return false; } } //检测所有浏览器中的Flash插件(兼容写法) function hasFlash(){ var result = hasplugin("Flash"); if(!result){ result=hasIEPlugin("shockwaveFlash.ShockwaveFlash");//Flash的标识符 } return result; }
还可以用navigator对象中的两个方法注册处理程序,不过多介绍;
screen对象,在编程中用处不大,主要含一些屏幕信息;
history对象:是window对象的属性,每个框架每个标签页下面的window对象都有自己的history属性
history中的go()方法可以在用户记录中任意跳转,可以向后也可以向前
//后退一页
history.go(-1)
//前进一页
history.go(1)
//前进两页
history.go(2)
//也可以传字符串,此时浏览器会跳转到历史记录中包含该字符串的第一个位置-----可能后退也可能前进
history.go("wrox.com")
//另外还有两个简写的方法
history.back();后退一页
history.forward();前进一页
//history对象还有一个length属性,保存着历史记录的数量,从而可以检测用户打开窗口后的第一个页面
if(history.length==0){
//这是用户打开窗口后的第一个页面(更改hash值也会记录到历史看记录里)
}