浏览器对象模型BOM
訪問和操作瀏覽器窗口的模型稱為瀏覽器對象模型BOM(Browser Object Model),但習(xí)慣上是把所有針對瀏覽器的JavaScript擴(kuò)展都納入BOM的范疇。BOM提供了一組獨(dú)立于網(wǎng)頁內(nèi)容而與瀏覽器交互的對象,但由于缺乏相關(guān)的行業(yè)規(guī)范,各瀏覽器提供商在很長一段時(shí)間內(nèi)都是按照各自的想法去實(shí)現(xiàn)這些對象的,因而瀏覽器之間共有的對象也就成為了事實(shí)上的標(biāo)準(zhǔn),這種局面在HTML5出現(xiàn)后有望得到改觀——HTML5致力于把很多BOM功能寫入正式規(guī)范。由于不同瀏覽器之間的差異性,這里總結(jié)的主要是一些我認(rèn)為比較常用的共有的特性,至于開發(fā)過程中的兼容性考慮,就交給流行的JS庫吧(比如jQuery、ExtJS)。
先看一下下面的這個(gè)BOM對象圖,從整體上對BOM有個(gè)認(rèn)識:
上圖中的window、document和location對象都具有雙重身份:window對象既是ECMAScript規(guī)范中的Global對象,也是BOM中的頂級對象;document對象既是BOM頂級對象的一個(gè)屬性,也是DOM模型中的頂級對象;location對象既是window對象的屬性,同時(shí)也是document對象的屬性。在BOM中,核心是window對象,下面就重點(diǎn)總結(jié)一下這個(gè)對象,document對象將在學(xué)習(xí)DOM模型時(shí)再做說明。
一、window對象
1、window作為ECMAScript中的Global對象
(1)引用Global對象的屬性和方法時(shí)可以省略對象名,因此在引用window對象的屬性和方法時(shí),也可以省略window。
(2)在全局作用域中this和window指向同一個(gè)對象,另外,還可以使用self來引用window對象,也即有this===window===self。
(3)在全局作用域中定義的變量和函數(shù)也會成為window對象的屬性和方法,但是和直接在window對象上定義屬性還是有區(qū)別:
A、全局變量不能使用delete刪除(相當(dāng)于給window定義屬性時(shí)將屬性特性[[Configurable]]賦值為false了),但是直接在window對象上定義的屬性可以使用delete刪除。這里有趣的是,如果同時(shí)定義了全局變量和window對象的屬性,則刪除window屬性時(shí)不起作用。
B、嘗試訪問未定義的全局變量會拋出異常,但是訪問未定義的window對象的屬性則只是返回undefined。
var age = '29';//全局作用域中定義的變量和函數(shù)會成為window對象的屬性和方法,但是不能使用delete刪除 function getAge(){return this.age; } console.info(window.age); // 29 console.info(window.getAge()); // 29 console.info(this == window); // true console.info(this == self); // true console.info(window == self); // true window.age = '23';//直接在window對象上定義屬性,會同時(shí)修改全局變量的值,相反,修改全局變量的值,window對象的屬性值也會修改 console.info(age); delete window.age;//既定義了全局變量,又在window對象上定義了屬性,刪除時(shí)雖然沒有報(bào)錯(cuò),但是并沒有起作用 console.info(age); //23 console.info(window.age); //23 window.color = 'red';//直接在window對象上定義屬性,可以使用delete刪除 console.info(window.color); delete window.color; console.info(window.color);//undefined2、window作為BOM中的頂級對象
(1)窗口關(guān)系及框架
先來看看在BOM中幾個(gè)具有特殊含義的對象top、window、parent、self:
- top:指向最高(最外)層的框架,也就是瀏覽器窗口。
- window:指向當(dāng)前框架的頂層對象。
- parent:指向當(dāng)前框架的直接上層框架,在沒有子框架的情況下,parent、window、top和self都相等,在有子框架的情況下,parent有可能等于top,也有不能不相等。
- self:始終指向window,引入self的目的只是為了與top和parent對象對應(yīng)起來。
如果頁面中包含框架,則每個(gè)框架都有自己的window對象,并且保存在父窗口的frames集合中,可以通過索引(從0開始,從左至右,從上至下)或者框架名稱訪問相應(yīng)的window對象。每個(gè)window對象都有一個(gè)name屬性,表示所處框架的名稱。下面是一個(gè)包括框架的頁面:
<html> <head><title>Frameset Example</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>在最外層的頁面中,可以通過下面的方式來訪問其中的框架:
(2)window作為頂層對象的主要方法
| 屬性和方法 | 返回值 | 參數(shù) | 說明 | ||
| 位置方法 | moveTo(x,y) | x和y表示新位置的x和y坐標(biāo)值 | |||
| moveBy(x,y) | x和y表示在水平和垂直方向上移動的像素?cái)?shù)?? | ||||
| 大小方法 | resizeTo(x,y) | x和y表示瀏覽器窗口的新寬度和新高度 | |||
| resizeBy(x,y) | x和y表示瀏覽器窗口的新寬度、新高度和原寬度、原高度的差 | ||||
| 對話框 | 同步 | alert() | ? | 提示文本 | 顯示時(shí)包含傳入的字符串和“確定”按鈕 |
| confirm() | 點(diǎn)擊“確認(rèn)”返回true,點(diǎn)擊“取消”返回false | 確認(rèn)文本 | 顯示時(shí)包含傳入的字符串、“確認(rèn)”按鈕(返回true)和“取消”按鈕(返回false),常用于確認(rèn)刪除操作 | ||
| prompt() | 點(diǎn)擊“確認(rèn)”返回文本輸入內(nèi)容,點(diǎn)擊“取消”返回null | 提示文本、文本輸入域 | 顯示時(shí)包含文本提示、“確認(rèn)”按鈕(返回文本輸入域的內(nèi)容)、“取消”按鈕(返回null)和文本輸入域。 | ||
| 異步 | find() | 相當(dāng)于使用瀏覽器菜單欄的“查找”命令打開對話框 | |||
| print() | 相當(dāng)于使用瀏覽器菜單欄的“打印”命令打開對話框 | ||||
| 調(diào)度 | 超時(shí) | setTimeOut() | 返回一個(gè)數(shù)值ID表示這個(gè)調(diào)用 | 執(zhí)行函數(shù)或代碼、執(zhí)行代碼前需要等待的時(shí)間(毫秒) | JavaScript是單線程的,超時(shí)調(diào)用和循環(huán)調(diào)用中的時(shí)間表示將需要執(zhí)行的函數(shù)或代碼加入到執(zhí)行隊(duì)列的時(shí)間,而不是實(shí)際執(zhí)行的時(shí)間,加入到執(zhí)行隊(duì)列之后一有資源就會馬上執(zhí)行。由于這個(gè)原因,setInterval()可能存在一些間隔會被跳過執(zhí)行,也可能間隔時(shí)間比預(yù)期的小,因此不建議使用循環(huán)調(diào)用,而采用下面的鏈?zhǔn)匠瑫r(shí)調(diào)用模式: setTimeout(function(){//處理代碼 setTimeout(arguments.callee, time); }, time); |
| clearTimeOut() | 根據(jù)ID取消超時(shí)調(diào)用 | 超時(shí)調(diào)用ID | |||
| 循環(huán) | setInterval() | 返回一個(gè)數(shù)值ID表示這個(gè)調(diào)用? | 執(zhí)行函數(shù)或代碼、循環(huán)執(zhí)行代碼的間隔時(shí)間(毫秒) | ||
| clearInterval() | 根據(jù)ID取消循環(huán)調(diào)用 | 循環(huán)調(diào)用ID | |||
| 新窗口 | 普通 | open() | 返回新打開窗口的引用 | 4個(gè)參數(shù):目標(biāo)URL,目標(biāo)窗口名稱,特性字符串,是否取代歷史記錄中當(dāng)前加載頁面的Boolean值 | 通常只需傳遞第一個(gè)參數(shù),最后一個(gè)參數(shù)只在不打開新窗口的情況下使用。 如果傳遞了第二個(gè)參數(shù),而且該參數(shù)是已有窗口或框架的名稱,那么就會在相應(yīng)的窗口或框架中加載目標(biāo)URL,如果是一個(gè)不存在的名稱,就會創(chuàng)建一個(gè)新窗口。第二個(gè)參數(shù)也可以是下面的特殊值:_self、_parent、_top、_blank。 |
說明:
A、表示窗口位置的屬性有screenLeft、screenTop、screenX、screenY、表示窗口大小的屬性有innerWidth、innerHeight、outerWidth、outerHeight,但是它們的具體含義和不同的瀏覽器密切相關(guān),在上表中沒有列入。這些屬性的差異性給窗口控制的兼容性造成了非常大的困擾,不過好在現(xiàn)在已經(jīng)有很多成熟的JS框架,在處理瀏覽器差異性建議使用這些JS框架。
B、moveTo()、moveBy()、resizeTo()、resizeBy()四個(gè)方法不適用于框架,只適用于最外層的window對象,而且這些方法可能會被瀏覽器禁用(在Opera和IE7+中默認(rèn)就是禁用的)。
C、window.open()方法中的第三個(gè)參數(shù)為特性字符串,是一個(gè)逗號分隔的設(shè)置字符串,用來表示在新窗口中都顯示哪些特性,整個(gè)特性字符串不允許出現(xiàn)空格,特性和特性以逗號分隔,特性和特性值以等號(=)間隔。這些特性有(藍(lán)色的為默認(rèn)值):
| 特性 | 取值范圍 | 說明 |
| fullscreen | yes|no | 表示瀏覽器窗口是否全屏,僅限IE |
| height | 數(shù)值(不能小于100) | 新窗口的高度 |
| width | 數(shù)值(不能小于100) | 新窗口的寬度 |
| left | 數(shù)值(不能是負(fù)值) | 新窗口的左坐標(biāo) |
| top | 數(shù)值(不能是負(fù)值) | 新窗口的上坐標(biāo) |
| toolbar | yes|no | 是否在瀏覽器窗口中顯示工具欄 |
| status | yes|no | 是否在瀏覽器窗口中顯示狀態(tài)欄 |
| scrollbars | yes|no | 如果內(nèi)容在視口中顯示不下,是否顯示滾動條 |
| resizable | yes|no | 是否可以通過拖動瀏覽器窗口的邊框來改變其大小 |
| menubar | yes|no | 是否在瀏覽器窗口中顯示菜單欄 |
| location | yes|no | 是否在瀏覽器窗口中顯示地址欄,不同瀏覽器默認(rèn)值不同,如果設(shè)置為no,地址欄可能會隱藏,也可能會被禁用 |
D、window.open()方法返回新創(chuàng)建窗口的一個(gè)引用,可以利用這個(gè)引用來操作新窗口,新窗口對象中有一個(gè)opener屬性指向原窗口。
//創(chuàng)建新窗口,返回這個(gè)新窗口對象的引用,如果代碼是在新打開窗口的頁面,則可以直接通過window訪問 var openWin = window.open("http://www.cnblogs.com/linjisong","cnblogs-lin","height=400,width=320,resizable=yes"); openWin.resizeTo(800,600);//重新定義大小 openWin.moveTo(100,100);//移動位置 console.info(openWin.opener === window);//true,新窗口對象中有一個(gè)opener屬性指向原窗口 openWin.close();//關(guān)閉新窗口 console.info(openWin.closed);//true,關(guān)閉之后可以訪問關(guān)閉狀態(tài)在使用window.open()方法時(shí),出于安全性考慮,很多瀏覽器會有一些限制,比如Firefox強(qiáng)制顯示地址欄等,在實(shí)際開發(fā)過程中,需要根據(jù)目標(biāo)瀏覽器來測試這些限制并采取相應(yīng)的措施。
E、在IE中,除了window.open()之外,還可以通過window.showModelDialog()來彈出一個(gè)窗口,通常稱之為“模態(tài)窗口”,這種窗口會獨(dú)占系統(tǒng)資源,用戶只有在關(guān)閉它之后才能繼續(xù)其它的操作。由于模態(tài)窗口不是兼容所有瀏覽器,這里不再展開,有興趣的朋友可以找相應(yīng)的資料了解一下。
二、history對象
history對象保存著從窗口被打開起的歷史記錄,每個(gè)瀏覽器窗口、標(biāo)簽頁、框架都有自己的history對象。history對象的主要屬性和方法有:
| 屬性/方法 | 例子 | 說明 |
| length | if(history.length == 0)?//第一個(gè)頁面 | 歷史記錄的數(shù)量 |
| go() | history.go(-1); history.go(0); history.go(2); history.go('linjisong'); | 負(fù)數(shù)表示向后跳轉(zhuǎn) 0表示刷新當(dāng)前頁面 正數(shù)表示向前跳轉(zhuǎn) 字符串參數(shù),表示跳轉(zhuǎn)到歷史記錄中包含該字符串的最近一個(gè)位置(可能前進(jìn),也可能后退) |
| back() | history.back();相當(dāng)于history.go(-1); | 后退一頁,可模仿瀏覽器“后退”按鈕 |
| forward() | history.forward();相當(dāng)于history.go(1); | 前進(jìn)一頁,可模仿瀏覽器“前進(jìn)”按鈕 |
三、location對象
location對象提供了與當(dāng)前窗口中加載的文檔有關(guān)的信息以及一些導(dǎo)航功能,它既是window對象的屬性,同時(shí)也是document對象的屬性,它的主要屬性和方法有:
| 屬性/方法 | 例子 | 說明 |
| hash | "#contents" | 返回URL中的hash(#號后跟零或多個(gè)字符),如果URL中不包括散列,返回空字符串 |
| host | "www.wrox.com:80" | 返回服務(wù)器名稱和端口號(如果有) |
| hostname | "www.wrox.com" | 返回不帶端口號的服務(wù)器名稱 |
| href | "http://www.wrox.com" | 返回當(dāng)前加載頁面的完整URL,location對象的toString()方法也返回這個(gè)值 |
| pathname | "/WileyCDA" | 返回URL中的目錄和文件名 |
| port | "8080" | 返回URL中指定的端口號,如果不含端口號,返回空字符串 |
| protocol | "http:" | 反應(yīng)頁面使用的協(xié)議,通常是http:或https: |
| search | "?q=javascript" | 返回URL的查詢字符串,這個(gè)字符串以問號開頭 |
| assign() | location.assign(URL) | 立即打開新URL并在瀏覽器歷史中生成一條記錄,相當(dāng)于直接設(shè)置location.href值,也可以修改location對象的其它屬性來重新加載 |
| replace() | location.replace(URL) | 打開新URL,但是不會生成歷史記錄,使用replace()之后,用戶不能通過“后退”回到前一個(gè)頁面 |
| reload() | location.reload([true]) | 重新加載當(dāng)前頁面,不傳遞參數(shù)時(shí)會以最有效方式加載(可能從緩存中加載),傳入true時(shí),則強(qiáng)制從瀏覽器重新加載 |
說明:location.search返回的是包括所有參數(shù)的字符串,可以通過下面的方法將這個(gè)字符串轉(zhuǎn)換為一個(gè)參數(shù)對象(原書第207頁):
function getQueryStringArgs(){var qs = (location.search.length > 0 ? location.search.substring(1) : ""),//去掉查詢字符串前面的問號args = {},items = qs.length ? qs.split("&") : [],//將參數(shù)以&分隔item = null,name = null,value = null,i = 0,len = items.length;for (i=0; i < len; i++){//循環(huán)處理,將每一個(gè)參數(shù)的名稱和值加入到參數(shù)對象中item = items[i].split("=");name = decodeURIComponent(item[0]);value = decodeURIComponent(item[1]);if (name.length){args[name] = value;}}return args;}var args = getQueryStringArgs();//假定查詢字符串返回?q=javascript&num=10 console.info(args["q"]); //"javascript"console.info(args["num"]); //"10"注意:該方法對于查詢字符串中同一個(gè)參數(shù)多個(gè)值的情況(類似?val=1&val=2)處理會有問題。
四、navigator對象
navigator對象用來描述瀏覽器本身,包括瀏覽器的名稱、版本、語言、系統(tǒng)平臺、用戶特性字符串等信息,但是各個(gè)瀏覽器及瀏覽器的不同版本之間對這個(gè)對象的實(shí)現(xiàn)也不盡相同。
在非IE瀏覽器中,可以使用navigator對象的plugins屬性來檢測插件的安裝情況:
function hasPlugin(name){name = name.toLowerCase();for (var i=0; i < navigator.mimeTypes.length; i++){if (navigator.mimeTypes[i].name.toLowerCase().indexOf(name) > -1){return true;}}return false; }也可以使用navigator對象的userAgent屬性(用戶代理字符串)來檢測客戶端對某種功能的支持情況。不過在檢測瀏覽器是否支持某種功能的時(shí)候,首先應(yīng)使用特性檢測來判斷,特性檢測的目標(biāo)不是判斷是什么瀏覽器,而是判斷瀏覽器是否支持某種能力,比如在IE早期版本中不存在document.getElementById(),而是使用非標(biāo)準(zhǔn)的document.all來獲取DOM元素,就可以使用如下代碼:
function getElement(id){if(document.getElementById){//特性檢測,如果支持,優(yōu)先使用document.getElementById()return document.getElementById(id); }else{return document.all[id];} }有時(shí)候雖然支持某種特性,但是這種特性并不是想要的功能,這種情況下,可以對特性進(jìn)一步做檢測,比如通過下面的代碼進(jìn)一步判斷支持的特性是否為函數(shù):
typeof document.createElement === 'function'當(dāng)然,特性檢測并不總是能湊效,這時(shí)不得已就只好通過navigator對象來對檢測了,因?yàn)閡serAgent是在瀏覽器發(fā)展過程中逐步演變而來的,因此使用這種檢測技術(shù)需要了解各種瀏覽器的發(fā)展歷史,這里就不具體展開了,建議就是使用成熟的JS庫來代替直接使用navigator.userAgent進(jìn)行檢測。
五、screen對象
screen對象用來表明客戶端的能力,包括瀏覽器窗口外部的顯示器的信息,如像素寬度和高度等,每個(gè)瀏覽器中的screen對象都包含著各不相同的屬性,其中五大瀏覽器都支持的屬性有:
- height:屏幕的像素高度
- width:屏幕的像素寬度
- availHeight:屏幕的像素高度減系統(tǒng)部件高度之后的值(只讀)
- availWidth:屏幕的像素寬度減系統(tǒng)部件寬度之后的值(只讀)
screen對象經(jīng)常集中出現(xiàn)在測定客戶端能力的站點(diǎn)跟蹤工具中,有時(shí)候也可能會用到其中的信息來調(diào)整瀏覽器窗口的大小,使其占據(jù)屏幕的可用空間,比如:
window.resizeTo(screen.availWidth, screen.availHeight); 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的浏览器对象模型BOM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用DOM操纵HTML文档几点粗浅认识
- 下一篇: DOM 基本方法