快速瞭解JavaScript的BOM模型

ECMAScript是JavaScript的核心,而BOM(瀏覽器對象模型,Browser Object Model)是在Web中使用JavaScript的核心。javascript

BOM對象中,window對象是最頂層對象,在瀏覽器環境中它是一個Global全局對象,其它對象是window對象的子對象(屬性)。BOM主要用於管理瀏覽器窗口及窗口之間的通信。下面是BOM對象的組成結構。html

image

window對象

windowBOM的核心對象,表示瀏覽器的一個實例。有雙重角色,便是經過JavaScript訪問瀏覽器窗口的一個接口,又是ES規定的Global對象。這意味着在網頁中定義的任何一個對象、變量和函數,都以window做爲其Global對象。java

var age = 29;
function sayAge() {
    console.log(this.age);
}
console.log(window.age);    // 29
sayAge();                    // 29
window.sayAge();            // 29

如上所示,在全局做用域中定義的變量和函數都被自動歸在了window對象名下。而sayAge()存在於全局做用域中,方法中的this.age被映射到window.age,所以顯示的仍然是正確的結果。跨域

然而,定義的全局變量不能經過delete操做符刪除,定義在window對象上的屬性卻能夠。數組

window除了locationnavigatorscreenhistorydocument外,還有一些屬性。瀏覽器

  • window.console:返回Console對象的引用,能夠向瀏覽器控制檯輸出日誌信息。僅用於調試,不該該給用戶呈現。(只讀)
  • window.frames:數組對象,列出當前窗口的全部直接子窗口。(只讀)
  • window.frameElement:當前窗口嵌入另外一個窗口(嵌入<object>、<iframe>),若是當前窗口是頂層,返回null。(只讀)
  • window.innerHeight:窗口的視圖可見高度(單位:像素),也包括滾動條高度。(只讀)
  • window.innerWidth:窗口的視圖可見寬度(單位:像素),也包括滾動條的寬度。(只讀)
  • window.length:當前窗口中包含框架數量。框架爲<frame><iframe>。(只讀)
  • window.locationbar:檢查visibility屬性的地址欄對象,用來表示是否可見。(只讀)
  • window.localStorage:訪問Document源的對象Storage;將數據存儲在瀏覽器會話中。相似sessionStorage,但數據可長期保留;而頁面會話結束時,sessionStorage數據會清除。(只讀)
  • window.menubar:檢查visibility屬性的菜單欄對象,用來表示是否可見。(只讀)
  • window.outerHeight:整個瀏覽器窗口的高度(單位:像素)。(只讀)
  • window.outerWidth:整個瀏覽器窗口的寬度(單位:像素)。(只讀)
  • window.parent:當前窗口或子窗口的父窗口的引用。(只讀)
  • window.personalbar:檢查visibility屬性的我的工具欄對象,用來表示是否可見。(只讀)
  • window.scrollX:頁面水平方向滾動距離(單位:像素),window.pageXOffset是別名。(只讀)
  • window.scrollY:頁面垂直方向已滾動距離(單位:像素),window.pageYOffset是別名。(只讀)
  • window.scrollbars:檢查visibility屬性的滾動條對象,用來表示是否可見。(只讀)
  • window.self:指向當前window對象的引用。
  • window.sessionStorage:容許訪問當前源的sessionStorage對象。與localStorage類似,不一樣在於sessionStorage在頁面會話結束時清除,而localStorage沒有過時時間。
  • window.top:窗口層級最頂層窗口的引用。
  • window.windowwindow對象自己。

介紹了一些window的屬性,下面咱們看一下關於window的方法。緩存

消息框

window有三種消息框:警告框 alert、確認框confirm和提示框prompt安全

window.alert(message)會顯示一個警告對話框,上面顯示有指定的文本內容以及一個肯定按鈕。例如window.alert("警告框來襲");的顯示以下:服務器

image

window.confirm(message)是一個具備可選消息的模態框。用於驗證是否接受用戶操做的確認框。cookie

var result = window.confirm("你要離開嗎?");
if (result) {
    // 按下肯定後執行的操做
    console.log("肯定");
} else {
    // 按下取消後執行的操做
    console.log("取消");
}

運行結果:

image

window.prompt(text, value) 是用於顯示文字信息提示用戶輸入文字的提示框。

  • text參數爲提示用戶輸入信息的提示內容,可省略。
  • value參數爲文本輸入框中的默認值,可省略。
var result = window.prompt("你的生日是何時的?", "1997-01-01");
if (result == "2011-10-23") {
    alert("你和我生日同樣耶!");
}

效果以下:

image

點擊肯定後,文本輸入框中文字被返回。若是爲空,則返回一個空字符串。點擊取消後,返回null

三個方法都具備堵塞效應,一旦彈出對話框,整個頁面就暫停執行,等待用戶作出反應。

window還有幾種方法控制窗口。例如open()close()stop()moveBy()/moveTo()resizeBy()/resizeTo()。下面介紹一下他們的功能。

窗口打開 & 關閉

window.open(url, target, features, replace)方法用於建立新的窗口。

  • url參數爲新窗口加載的URL
  • target參數爲新窗口的名字。每一個窗口都有一個window.name,這裏能夠指定窗口用於彈窗,若是不存在,新建窗口。這個名字可用做<a><form>的屬性target的值。字符串中不能含有空白字符。注意:target不是新窗口標題。
  • features參數爲字符串值,內容用逗號分隔,參數不能有空格,例如width=200,height=100
var params = 'scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,width=0,height=0,left=-1000,top=-1000';
window.open('/', 'test', params);

features能夠設置的值有:

  • left/top:新窗口的最左邊(left)與最頂部(top)的距離(單位:像素)。新窗口可見,不能設置在屏幕之外。
  • width/height:新窗口的寬度和高度(單位:像素)。寬高不得小於100
  • outerWidth/outerHeight:整個瀏覽器窗口的寬高。(單位:像素)。寬高不得小於100
  • menubar:是否顯示菜單欄。
  • toolbar:是否顯示工具欄。
  • location是否顯示地址欄。
  • personalbar:是否顯示用戶安裝的工具欄。
  • status:是否顯示狀態欄。
  • resizable:新窗口是否可調整大小。
  • scrollbars:是否出現滾動條。
  • titlebar:是否顯示標題欄。
  • close:是否顯示關閉按鈕。

同源策略,窗口只可訪問相同協議下的內容(相同協議://domain:port)。

window.close()方法用於關閉當前窗口,通常只用來關閉window.open()方法新建的窗口。使用window.closed屬性來判斷窗口是否被關閉。

在當前窗口中關閉窗口:

window.close();

window.stop()方法等同於單擊瀏覽器的中止按鈕。因爲腳本加載順序,該方法不能阻止已經包含在加載中的文檔,但能阻止圖片、新窗口和延遲加載的對象的加載。

window.stop();

窗口移動

window.moveBy(deltaX, deltaY)方法根據指定的值,移動當前窗口。

  • deltaX:窗口在水平方向移動的像素值。
  • deltaY:窗口在垂直方向移動的像素值。

window.moveTo(x, y)方法將當前窗口移動到指定的座標位置。

  • x:水平方向移動的橫座標
  • y:豎直方向移動的縱座標

moveBy()產生的是相對移動,moveTo()產生的是絕對移動。

當符合下列狀況時,普通網頁中的JavaScript沒法經過調用該函數來移動瀏覽器窗口:

  1. 當前窗口或標籤頁不是由window.open方法建立的;
  2. 當前標籤頁所在的窗口包含有多個標籤頁。

window.resizeBy(xDelta, yDelta)方法用於調整窗口的大小。

  • xDelta:窗口水平方向變化的像素值。
  • yDelta:窗口垂直方向變化的像素值。

window.resizeTo(aWidth, aHeight)方法用於調整窗口的大小。

  • aWidth:整數,表示新的outerWidth(單位:像素)。
  • aHeight:整數,表示新的outerHeight(單位:像素)。

resizeBy()相對大小方式調整窗口大小,resizeTo()絕對大小方式調整窗口大小。

依據下面的規則,普通網頁中的JavaScript沒法經過調用該函數來調整瀏覽器窗口大小:

  1. 不能設置哪些不是經過window.open建立的窗口或Tab的大小;
  2. 當一個窗口裏麪包含有一個以上Tab時,沒法設置窗口的大小。

窗口滾動

window.scroll()滾動窗口至文檔中的特定位置,
window.scrollBy()按窗口指定偏移量滾動文檔,
window.scrollTo()滾動窗口至文檔中的特定位置。

上面的三個方法的參數均可以是x-coordy-coord兩個參數,或者options一個參數。

  • x-coord:水平方向像素點橫座標。
  • y-coord:垂直方向像素點縱座標。

或者

  • options:一個ScrollToOptions字典。
// 在橫軸上移動到第100個像素置於窗口左邊,在縱軸上移動到第100個像素置於窗口頂部
window.scroll(100, 100);
// 或者
window.scroll({
    top: 100,
    left: 100,
    behavior: 'smooth'
});

options有三個屬性:

  • top:垂直方向滾動的像素值
  • left:水平方向滾動的像素值
  • behavior:滾動方式,smoothinstantauto,默認值auto

寫法也同樣,可是功能不同。window.scrollBy()滾動指定的距離,window.scroll()滾動至文檔中的絕對位置,window.scrollTo()實際上和window.scroll()方法是相同的。

打印

window.print()方法打開打印對話框打印當前文檔。

在開發項目中,有網頁提供打印服務的話,咱們能夠在頁面中設置一個按鈕,調用打印功能;但在以前,咱們須要判斷是否支持打印功能。

if (typeof window.print === 'function') {
    // 支持打印功能
        document.getElementById('printLink').onclick = function () {
        window.print();
    }
}

彈窗的聚焦/失焦

使用window.focus()window.blur()方法能夠是窗口得到或失去焦點。

還有一些方法,這裏就不介紹了。

location

location對象提供當前窗口中加載的文檔有關信息,還提供了一些導航功能。便是window對象的屬性,也是document對象的屬性。還能夠解析URL。下面列出一些location的屬性。

  • location.href:完整的URL值,容許更新。
  • location.origin:域名標準形式。包含協議、域名、端口號。
  • location.protocol:當前URL的協議,包括冒號(:)。
  • location.host:域名,包含:後面的端口號。
  • location.hostname:域名,不包括端口號。
  • location.port:端口號。
  • location.pathnameURL中路徑的部分,從/開始。
  • location.searchURL參數部分,從問號?開始。
  • location.hash:塊標識符部分,從#開始。
  • location.usernameURL域名前的用戶名。
  • location.passwordURL域名前的密碼。

只有origin屬性是隻讀的,其它屬性均可寫。

咱們給出一個網址http://localhost:8088/mall/?page=1&userid=2#part=top,使用上面的屬性來獲取它。

location.href;        // http://localhost:8088/mall/?page=1&userid=2#part=top
location.origin;    // http://localhost:8088
location.protocol;    // http:
location.host;        // localhost:8080
location.hostname;    // localhost
location.port;        // 8088
location.pathname;    // /mall/
location.search;    // ?page=1&userid=2
location.hash;        // #part=top

然而location.search獲取的是全部內容,沒辦法逐個獲取每一個查詢字符串參數。咱們能夠建立一個函數用以解析並返回包含全部參數的對象。

function getQueryArgs() {
    // 取的查詢字符串並去掉開頭問號
    var qa = (location.search.length > 0 ? location.search.substring(1) : ""),
    // 保存數據的對象
    args = {},
    // 取的每一項
    items = qa.length ? qa.split("&") : [],
    // 每一項和該項的鍵值
    item = null,name = null,value = null,
    len = items.length;
    // 逐個將每一項添加到args對象中
    for (let 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;
}

注意,若是對location.href寫入新的URL地址,瀏覽器會馬上跳轉到這個新地址。

除了上述的屬性外,location還有幾個方法。

assign

location.assign(url)方法接收URL字符串來使瀏覽器當即跳轉。而參數無效時會報錯。

location.assign('http://www.sample.com');

而給window.locationlocation.href兩個屬性賦值與調用assign()方法效果同樣。

replace

location.replace()location.assign()方法相似,都是跳轉到新的URL,但不會在瀏覽歷史History裏面生成新的記錄,後退按鈕沒法回到當前頁面。當腳本發現當前是移動設備時,可使用replace跳轉到移動版網頁。

// 跳轉到新的網址
location.replace('http://www.sample.com');

reload

location.reload(boolean)方法用於從新加載當前頁面。當參數爲false或爲空時,瀏覽器將該網頁從本地緩存從新加載並定位到當前位置。參數爲true時,瀏覽器向服務器從新請求,並定位到頂部(即scroillTop===0)。

location.reload();            // 從新加載(有可能從緩存中加載)
location.reload(true);        // 從新加載(從服務器從新加載)

reload()以後的代碼有可能不會執行,取決於網絡延遲或系統資源等因素。最好將reload()放在代碼最後一行。

location.toString()方法返回整個URL字符串,至關於讀取location.href屬性。

navigator對象

navigator用於獲取當前瀏覽器信息。可使用window.navigator屬性檢索navigator對象。

  • appCodeName:瀏覽器的代號名稱。Mozilla,Netscape 6和IE5的內部名稱都是Mozilla。(只讀)
  • appName:瀏覽器的名稱。因爲兼容性問題,HTML5規範容許該屬性返回Netscape。(只讀)
  • appVersion:瀏覽器版本號。通常不與實際版本對應。(只讀)
  • connection:提供NetworkInformation對象來獲取設備的網絡鏈接信息。(只讀)
  • cookieEnabled:瀏覽器當前頁面是否啓用cookie。(只讀)
  • geolocation:返回Geolocation對象,可訪問設備的位置信息。安全考慮會提示受權。(只讀)
  • hardwareConcurrency:瀏覽器環境擁有的CPU核心數。(只讀)
  • keyboard:返回Keyboard對象,提供檢索鍵盤佈局圖和切換從物理鍵盤捕獲按鍵的功能。(只讀)
  • language:瀏覽器主語言。(只讀)
  • languages:訪客所使用的語言數組,按優先順序排列。第一個元素賦給language,當值改變時,window觸發languagechange事件。(只讀)
  • mimeTypes:返回MimeTypeArray對象,包含可被識別的MimeType對象的數組。(只讀)
  • maxTouchPoints:返回當前設備同時支持觸摸接觸點的最大數量。(只讀)
  • onLine:表示瀏覽器當前是否聯網。(只讀)
  • oscpu:返回客戶端計算機的操做系統或使用的CPU。在Firefox中能夠獲取此值。
  • permissions:返回一個可用於查詢或更新某些APIs的權限狀態的對象。(只讀)
  • platform:瀏覽器所在系統平臺類型。不肯定此值是否有效。(只讀)
  • plugins:返回PluginArray對象,包含瀏覽器安裝的全部插件。(只讀)
  • product:當前瀏覽器產品名稱。以兼容爲目的,返回"Gecko"值。(只讀)
  • serviceWorker:返回ServiceWorkerContainer對象,提供對ServiceWorker的註冊、刪除、升級和通訊的訪問。(只讀)
  • storage:返回單例StorageManager對象,用於維護數據的持久化存儲,大體肯定存儲數據的空間。(只讀)
  • userAgent:返回當前瀏覽器的用戶代理。(只讀)
  • vendor:瀏覽器的供應商。例如Chrome中顯示Google Inc.
  • vendorSub:有關供應商的次要信息。

在介紹一下navigator對象中的一些方法。

javaEnabled

javaEnabled()代表瀏覽器是否啓用Java。是當前配置文件是否容許使用Java,而不是瀏覽器是否支持Java。

if (window.navigator.javaEnabled()) {
    // 瀏覽器中Java可用
}

sendBeacon

sendBeacon(url, data)是用於經過HTTP將少許數據異步傳輸到Web服務器。當傳輸成功時會返回true

  • url爲發送的地址;
  • dataArrayBufferViewBlobDOMString或者FormData類型的數據。

下面的例子展現了一個理論的統計代碼——卸載事件處理器中嘗試經過一個同步的XMLHttpRequest向服務器發送數據。這致使了頁面卸載被延遲。

window.addEventListener('unload', logData, false);
func logData() {
    var client = new XMLHttpRequest();
    client.open("POST", "/log", flase);    // 第三個參數代表是同步的xhr
    client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
    client.send(analyticsData);
}

這就是sendBeacon()方法存在的意義。使用sendBeacon()方法會使用戶代理在有機會時異步地向服務器發送數據,同時不會延遲頁面的卸載或影響下一導航的載入性能。這就解決了提交分析數據時的全部的問題:數據可靠,傳輸異步而且不會影響下一頁面的加載。此外,代碼實際上還要比其它技術簡單許多!

下面的例子展現了一個理論上的統計代碼模式——經過使用sendBeacon()方法向服務器發送數據。

window.addEventListener('unload', logData, false);
function logData() {
    navigator.sendBeacon("/log", analyticsData);
}

registerProtocolHandler

registerProtocolHandler(scheme, url, title)可讓Web站點爲自身註冊能用於打開或處理特定協議的功能。

  • scheme:包含站點處理協議的字符串。例如,傳入"sms"來註冊處理SMS文本信息連接。
  • url:處理器的URL字符串。應該包含一個"%"佔位符,會被將要受理的文檔的escaped連接所替換。這個連接多是一個真實URL,或者是一個電話號碼,郵件地址之類的。
  • title:處理器標題。展現給用戶,例如彈出"容許站點處理[scheme]連接嗎?"或者在瀏覽器設置中列出註冊的處理器時。
處理器的 URL必須以 http或者 https協議標記開頭,最好是 https,以知足一些瀏覽器出於安全考慮的要求。

screen對象

screen對象表示當前屏幕窗口,每每指當前正被渲染的window對象,提供顯示設備的信息。用處不大。主要介紹幾種屬性。

  • availTop:返回瀏覽器可用空間在屏幕上邊的像素值。
  • availLeft:返回瀏覽器可用空間在屏幕左邊的像素值。
  • availWidth:返回瀏覽器可用空間的水平寬度。
  • availHeight:返回瀏覽器可用空間的垂直高度。
  • colorDepth:返回屏幕的顏色深度(color depth)。根據CSSOM(CSS對象模型)視圖,爲兼容起見,該值總爲24。
  • height:返回屏幕的高度(單位:像素)。
  • orientation:返回一個ScreenOrientation實例,表示當前屏幕的方向。
  • pixelDepth:返回屏幕的位深度/色彩深度(bit depth)。根據CSSOM(CSS對象模型)視圖,爲兼容起見,該值總爲24。
  • width:返回屏幕的寬度(單位:像素)。

history對象

history對象保存着瀏覽器的歷史記錄。出於安全考慮,開發人員沒法得知用戶瀏覽器的URL。但能經過歷史列表實現後退和前進。下面是history對象主要的屬性。

  • length:返回當前窗口歷史列表中的URL數量。
  • scrollRestoration:容許Web應用程序在歷史列表上顯示地設置默認滾動恢復行爲。
  • statehistory堆棧最上層的狀態值。
const scrollRestoration = history.scrollRestoration;
if (scrollRestoration) {
    // 防止自動恢復頁面位置
    history.scrollRestoration = 'manual';
} else {
    // 查看當前頁面滾動恢復行爲
    console.log('The location on the page is not restored, user will need to scroll manually.');
}

還能夠經過history提供的方法來訪問歷史記錄。

go

go()方法能夠在用戶的歷史記錄中任意跳轉。傳遞數值爲跳轉的頁數。

history.go(-1);        // 返回一頁
history.go(2);        // 前進兩頁

也能夠傳遞歷史記錄中存在的字符串參數,若是歷史記錄中不包含傳遞的字符串,那什麼也不作。

history.go("sample.com");

還可使用 back() 方法後退和使用forward()方法前進來代替go()方法的功能。

注意,移動到之前訪問過的頁面時,頁面一般是從瀏覽器緩存之中加載,而不是從新要求服務器發送新的網頁。

pushState

pushState(state, title, url)方法可以在不加載頁面的狀況下在歷史中添加一條記錄。這個方法接收三個參數:

  • state參數是狀態對象,與pushState添加的記錄相關聯。表示瀏覽器的state屬性。
  • title參數是document.title的值,通常設定爲null。瀏覽器大多會忽略。
  • url參數指定新歷史記錄,用以改變當前url。這個參數不能跨域,即協議,域名,端口必須是相同的,若是出現跨域的狀況,即會提示。
history.pushState({id:1}, null, '?page=1');

replaceState

replaceState(stateObj, title, url)方法用來修改history對象的當前記錄,它是替換當前頁面在瀏覽器的歷史記錄。假設當前網頁是sample.com/index.html

history.pushState({id:1}, 'title1', '?page=1');    // URL顯示爲http://sample.com/index.html?page=1
history.pushState({id:2}, 'title2', '?page=2');    // URL顯示爲http://sample.com/index.html?page=2
history.replaceState({id:3}, 'title3', '?page=3');    // URL顯示爲http://sample.com/index.html?page=3
history.back();    // URL顯示爲http://sample.com/index.html?page=1
history.back();    // URL顯示爲http://sample.com/index.html
history.go(2);    // URL顯示爲http://sample.com/index.html?page=3

postate事件

當添加或更改歷史記錄時,會觸發popstate事件。若是被激活的歷史記錄條目是經過對history.pushState()的調用建立的,或者受到對history.replaceState()的調用的影響,popstate事件的state屬性包含歷史條目的狀態的副本。

須要注意的是調用history.pushState()history.replaceState()不會觸發popstate事件。只有在作出瀏覽器動做時,纔會觸發該事件,如用戶點擊瀏覽器返回按鈕(或者在JavaScript代碼中調用history.back()或者history.forward()方法)。

總結

BOM是以window對象爲依託的瀏覽器對象模型,它將瀏覽器看成一個對象,用於與瀏覽器窗口進行交互。window對象仍是Global對象,全局變量和函數都是它的屬性和方法,且全部原生的構造函數及其它函數也在它的命名空間下。但每一個瀏覽器廠商都有本身的BOM實現,所以兼容性較差。

更多內容請關注公衆號「海人的博客」,回覆「資源」便可得到免費學習資源!

image

相關文章
相關標籤/搜索