BOM:瀏覽器對象模型之瀏覽器剖析入門

  • BOM簡介
  • BOM與DOM的關係
  • BOM對象包含的內容
  • 從新認識瀏覽器

 1、分裂的BOM和被收服的DOM

BOM定義:是browser object model的縮寫,簡稱瀏覽器對象模型。php

主要處理瀏覽器窗口(window)和框架(iframe),描述了與瀏覽器進行交互的方法和接口,能夠對瀏覽器窗口進行訪問和操做,不過一般瀏覽器特性的JavaScript擴展都被看作是BOM的一部分,好比:彈出新的窗口,移動關閉瀏覽器窗口或調整瀏覽窗口大小,提供web瀏覽器詳細信息的定位對象,提供屏幕分辨率詳細信息的屏幕對象,對cookie的支持,IE擴展了BOM,加入了ActiveXObject類,能夠經過JavaScript實例化ActiveX對象。(來源百度)
css

說人話來解析一篇:

以DOM爲例來講(假設你知道DOM是什麼),咱們平常編寫代碼的時候無非就是增刪改查DOM節點,而實現這些操做的就是瀏覽器內核給個人們document對象上的一系列方法,這些方法咱們也一般叫作操做文檔的接口。DOM這些操做的都是咱們本身編寫的HTML文檔或者xml文檔,那麼BOM就是瀏覽器提供給咱們操做瀏覽器的接口,畢竟瀏覽器不是咱們本身編寫的代碼,操做不可能像DOM那樣想刪就刪,想改就改,BOM提供的基本上都查詢瀏覽下相關的信息的接口。(BOM的具體操做不少手冊都有詳細的文檔,在第二部分我會列出幾個重要的操做和一些兼容方法)html

DOM與BOM的關係?W3C纔是大哥!

在平常開發映像中,DOM與BOM好像是獨立的兩個模塊,其實否則,DOM的document對象的縮寫形式,可是在瀏覽器接口中沒有browser...這個東西,但並不表明它沒有存在,相反它是無所不在,BOM給JavaScript語言的瀏覽器接口就是window(不肯定其餘語音的接口是否同樣,沒有用過其餘語言來寫前端交互操做),就是這個全局對象,document是window的屬性,因此這二者的關係就很是清楚了,DOM實際上是BOM的一部分,只是由於DOM的重要性,咱們一般將其獨立出來解釋。前端

那這裏管W3C什麼事呢?別搞笑,瀏覽器做爲一款基於互聯網的應用,你說W3C可不能夠來講兩句話呢?因此W3C作了一個很是英明的決定,制定了DOM的標準,你印象中的前端開發很是痛苦的一件事莫非就是兼容瀏覽器了,現現在的最新版瀏覽器基本上都兼容了W3C的DOM標準了,商業利益在時代的趨勢前都是廢銅爛鐵,最終DOM被收服了。這個標準制定了標準文檔對象和屬性(HTML5就是產物之一),並制定了訪問文檔的接口;還包括構建核心DOM的標準模型,XML DOM標準模型,以及HTML DOM標準模型。node

可是咱們今天要詳細瞭解的BOM,準確的說除了DOM覺得的BOM部分,就沒有那麼幸運了,基本上都不兼容,畢竟這個世界若是每一個人都長同樣那會多麼無趣。因此說它分裂有點悲觀,應該是多樣性,畢竟這個世界如此燦爛而美好。web

 2、BOM包含的內容和經常使用接口

前面咱們介紹了BOM重要的一員DOM,可是一般咱們開發時表達的BOM是除了DOM之外的部分,因此這裏所說的BOM也是除了DOM之外的部分。移動web開發

  • window
  • Navigator
  • History
  • Location
  • Screen

 1.window中經常使用的屬性和方法:瀏覽器

 1.1/innerHeight、innerWidth獲取窗口的文檔顯示區域的高度。須要注意的是outerHeight、outerWidth這兩個屬性也是用來獲取瀏覽器窗口的寬高,但這兩個屬性的寬高包含了滾動條的寬高。緩存

 1.2/pageXOffset、pageYOffset設置或返回當前頁面相對於窗口顯示區左上角的X軸和Y軸的位置,一般也被稱做是橫向滾動條的最左側的位置和縱向滾動條最頂端的位置。這兩個屬性出現比較多的應用場景就是懶加載(關於懶加載在網絡部分會詳細說明,下面有一個模擬demo)。服務器

//用定時器模擬懶加載,實踐應用pageYOffset/innerHeight屬性
//css
body{
    height: 3000px;
}
div{
    position: absolute;
    left: 200px;
    top: 1500px;
    width: 200px;
    height: 200px;
    background: red;
    
}
//html
<div id = "demo" style="opacity: 0.3;"></div>
//js
function check(_id){
    var oDiv = document.getElementById(_id);
    //幾個關鍵屬性:
    //element.offsetTop -->元素距離窗口頁面的最上端的距離
    //window.pageYOffset -->縱向滾動條距離窗口的距離
    //window.innerHeight -->窗口可視高度
    if(oDiv.offsetTop <= window.pageYOffset + window.innerHeight){
        console.log("a");
        oDiv.timer = setInterval(function(){
            if(oDiv.style.opacity == '1'){
                clearInterval(oDiv.timer);
            }else{
                oDiv.style.opacity = parseFloat(oDiv.style.opacity) + 0.1;
            }
        },100);
    }
}
//鼠標滑動事件
window.onscroll = function(){
    check('demo');
}
View Code

 1.3/screenLeft/screenTop/screenX/screenY返回瀏覽器相對於顯示器最左側和最上冊的距離,這四個屬性先後兩個一組相對應的,表達的是同一個意思,只是在不一樣瀏覽器採用不一樣名稱(注意兼容了)。

 1.4/parent返回父級窗口對象,這裏涉及的內容是<iframe src=""></iframe>窗口嵌套,寫在iframe內的子窗口也有本身的window對象,這個子窗口的window對象能夠經過parent屬性獲取到父級窗口的window對象,從而達到獲取父級窗口對象上的內容。可是沒有父級窗口獲取子級的window對象的屬性和方法,這個涉及的內容與瀏覽器的網絡相關內容,須要經過同源策略來解決。後期會有博客詳細介紹。

 1.5/top返回最頂級窗口對象,這個屬性與parent實質上一模一樣,parent經過逐級獲取父級窗口,top直接獲取的是最頂級窗口的window對象。

 1.6/self返回當前窗口的應用(window == window.self -->true)括號的表達式前提是window在相關做用域沒有被修改指向的前提。

 1.7/name設置當前瀏覽器窗口的名稱,這個名稱不論當前窗口的頁面或鏈接如何改變,name都不會變化。

(注意命名污染問題:parent、top、self、name在window上是特性,除name外是可寫入的外,其餘不能寫,若是在全局做用趕上定義了這些變量可能會致使程序出錯。)

1.8/下面是一些關於window的方法,處於版面控制,我用代碼框摺疊起來了(畢竟這些並非這篇博客的重點)。

//1.1-- alert() 彈窗 --用來
//1.2-- setInterval() 按照指定的週期(以毫秒計)來調用函數或計算表達。
//1.3-- clearInterval() 取消setInterval()方法設置的timeout。
//1.4-- setTimeout() 在指定的毫秒數後調用函數或計算表達式
//1.5-- clearTimeout() 取消setTimeout()方法設置的timenout
//1.6-- confirm("我帥不帥?") --彈出提示信息,帶有"肯定"、"取消"兩個按鈕,點擊這兩個按鈕分別會返回true、false
//1.7-- prompt("hello world") -- 彈出輸入框,參數是提示信息,輸入的內容再確認後會做爲返回值,若是取消則返回false
//   -- onbeforeunload 它不是window的方法,而是一個事件,也是彈窗功能,別誤會了,離開頁面時觸發的。
//1.8-- scrollBy(x,y) 按照指定的像素值來滾動滾動條(對滾動條位置作加減操做) -- 數值能夠爲正負,正負關係就不解釋了。
//1.9-- scrollTO(x,y) 安裝指定的像素值來定位滾動條 -- (直接將滾動條定位到指定的位置)
//1.10- open(URL,name,specs,replace) 用來開啓新窗口(獨立的瀏覽器窗口或者當前瀏覽器窗口開啓一個新的頁面)
//        -- 只給url就是在當前瀏覽器窗口開啓一個新的頁面,給定寬高(特徵值)就會開啓一個新的瀏覽器窗口
//1.11- moveBy()可把窗口的當前座標移動到指定位置,詳細可參考手冊:http://www.runoob.com/try/try.php?filename=try_win_moveby
//1.12- moveTO()將指定的窗口移動到相對當前窗口的位置,詳細可參考手冊:http://www.runoob.com/try/try.php?filename=try_win_moveto
View Code

 2.Navigator對象和方法

說明:navigator對象重要是提供瀏覽器信息,好比瀏覽器嗅探就是基於這個對象的userAgent屬性來完成的。而後還有脫機判斷的onLine判斷是否脫機,cookieEnabled判斷是否能使用cookie。

2.1封裝瀏覽器嗅探對象

var nVer = navigator.appVersion,
    nAgt = navigator.userAgent,
    browser = navigator.appName,
    version = '' + parseFloat(navigator.appVersion),
    majorVersion, nameOffset, verOffset, ix, network = 'unknown';
// Opera
if ((verOffset = nAgt.indexOf('Opera')) != -1) {
    browser = 'Opera';
    version = nAgt.substring(verOffset + 6);
    if ((verOffset = nAgt.indexOf('Version')) != -1) {
        version = nAgt.substring(verOffset + 8);
    }
}
// Opera Next 
if ((verOffset = nAgt.indexOf('OPR')) != -1) {
    browser = 'Opera';
    version = nAgt.substring(verOffset + 4);
}
// MSIE
else if ((verOffset = nAgt.indexOf('MSIE')) != -1) {
    browser = 'Microsoft Internet Explorer';
    version = nAgt.substring(verOffset + 5);
}
// Chrome
else if ((verOffset = nAgt.indexOf('Chrome')) != -1) {
    browser = 'Chrome';
    version = nAgt.substring(verOffset + 7);
}
// Safari
else if ((verOffset = nAgt.indexOf('Safari')) != -1) {
    browser = 'Safari';
    version = nAgt.substring(verOffset + 7);
    if ((verOffset = nAgt.indexOf('Version')) != -1) {
        version = nAgt.substring(verOffset + 8);
    }
}
// Firefox
else if ((verOffset = nAgt.indexOf('Firefox')) != -1) {
    browser = 'Firefox';
    version = nAgt.substring(verOffset + 8);
}
// MSIE 11+
else if (nAgt.indexOf('Trident/') != -1) {
    browser = 'Microsoft Internet Explorer';
    version = nAgt.substring(nAgt.indexOf('rv:') + 3);
}
// WeiXin
else if (nAgt.indexOf('NetType/') != -1) {
    browser = 'WeiXin';
    if (nAgt.indexOf('NetType/WIFI') != -1) {
        network = 'WIFI';
    }else if(nAgt.indexOf('NetType/2G') != -1) {
        network = '2G';
    }else if(nAgt.indexOf('NetType/3G+') != -1) {
        network = '3G+';
    }
    verOffset = nAgt.lastIndexOf('/')
    version = nAgt.substring(verOffset + 1);
    if (browser.toLowerCase() == browser.toUpperCase()) {
        browser = navigator.appName;
    }
}
// Other browsers
else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
    browser = nAgt.substring(nameOffset, verOffset);
    version = nAgt.substring(verOffset + 1);
    if (browser.toLowerCase() == browser.toUpperCase()) {
        browser = navigator.appName;
    }
}

// trim the version string
if ((ix = version.indexOf(';')) != -1) version = version.substring(0, ix);
if ((ix = version.indexOf(' ')) != -1) version = version.substring(0, ix);
if ((ix = version.indexOf(')')) != -1) version = version.substring(0, ix);
majorVersion = parseInt('' + version, 10);
if (isNaN(majorVersion)) {
    version = '' + parseFloat(navigator.appVersion);
    majorVersion = parseInt(navigator.appVersion, 10);
}

// mobile version
var mobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer);

// start system detect
var os = '';
var clientStrings = [
    {s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/},
    {s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/},
    {s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/},
    {s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/},
    {s: 'Windows Vista', r: /Windows NT 6.0/},
    {s: 'Windows Server 2003', r: /Windows NT 5.2/},
    {s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/},
    {s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/},
    {s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/},
    {s: 'Windows 98', r: /(Windows 98|Win98)/},
    {s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/},
    {s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/},
    {s: 'Windows CE', r: /Windows CE/},
    {s: 'Windows 3.11', r: /Win16/},
    {s: 'Android', r: /Android/},
    {s: 'Open BSD', r: /OpenBSD/},
    {s: 'Sun OS', r: /SunOS/},
    {s: 'Linux', r: /(Linux|X11)/},
    {s: 'iOS', r: /(iPhone|iPad|iPod)/},
    {s: 'Mac OS X', r: /Mac OS X/},
    {s: 'Mac OS', r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/},
    {s: 'QNX', r: /QNX/},
    {s: 'UNIX', r: /UNIX/},
    {s: 'BeOS', r: /BeOS/},
    {s: 'OS/2', r: /OS\/2/},
    {s: 'Search Bot', r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/}
];
for (var id in clientStrings) {
    var cs = clientStrings[id];
    if (cs.r.test(nAgt)) {
        os = cs.s;
        break;
    }
}
var osVersion = '';
if (/Windows/.test(os)) {
    osVersion = /Windows (.*)/.exec(os)[1];
    os = 'Windows';
}
switch (os) {
    case 'Mac OS X':
        osVersion = /Mac OS X (10[\.\_\d]+)/.exec(nAgt)[1];
        break;
    case 'Android':
        osVersion = /Android ([\.\_\d]+)/.exec(nAgt)[1];
        break;
    case 'iOS':
        osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer);
        osVersion = osVersion[1] + '.' + osVersion[2] + '.' + (osVersion[3] | 0);
        break;
}

//detect data
var params = {};
params.os = os;//操做系統
params.osVersion = osVersion ? osVersion : 'unknown';//操做系統版本
params.mobile = mobile;//是否移動端訪問
params.browser = browser;//瀏覽器
params.browserVersion = version;//瀏覽器版本
params.browserMajorVersion = majorVersion;//瀏覽器major版本

//輸出對象
console.log(params);
View Code

這個代碼量有點大,若是步理解瀏覽器嗅探是什麼的話能夠先查查資料,具體怎麼用等到相關的內容再作說明。

2.2/onLine判斷脫機主要用途就是用於離線緩存,實現離線應用。

3.History用於記錄當前窗口的鏈接,能夠經過該對象的方法實現歷史訪問頁面的切換。

//屬性:
length==>返回當前窗口瀏覽網頁的歷史次數
//方法:
back()==>加載history列表中的前一個url
forward()==>加載history列表中的下一個url
go()==>加載history列表中的某一個具體頁面,提供索引做爲參數

history在HTML5中有比較大的強化,具體到HTML5的內容中去說。

4.Location對象

location相對前面其餘對象除了window之外是最有用的一個,好比經過錨點映射實現單頁面應用就是在移動web開發中佔有很是大地位。還有經過Location.Reload()方法從新載入當前文檔,經過boolean值來實現是否繞開緩存從新加載當前頁面,又或者是取瀏覽器的緩存的數據(這對於網絡優化和交互體驗有很是的地位)。(服務器能夠經過報文定義當前頁面在瀏覽器是否緩存,緩存多長時間時間,這些內容都會在網絡博客剖析)

考慮到這部分有太多內容須要衍生,就簡單的對location作一些引導性說明,後期在具體的博客中來闡述。

 3、從新認識瀏覽器

爲何我會在這裏來聊瀏覽器呢?又或者說爲何須要在這裏聊瀏覽器呢?還或者說我爲何要就着BOM的內容來引述瀏覽器呢?這是由於本人本身從學習前端以來一路踩坑而來,咱們一般理解的web前端學習內容就是HTML、CSS、JavaScript,可是這離前端的差距還特別大,別忽略了瀏覽器在前端開發的存在,由於它無所不在。

可是我爲何會在BOM的內容下來聊瀏覽器呢?這是由於咱們平常的開發和學習(初級階段)大多都是與文檔打交道,也就是DOM,這時候你或許會用jQuery了,能夠開發出很精美的網頁了,可是你知道爲何jQuery會退出歷史舞臺嗎?若是你對前端的理解還只是html、css、js,而後用js操做html和css也就是操做dom,那你的技術落後差很少十年,v8引擎2008年九月發佈,nodejs於2009年發佈,處於體驗優化和團隊協做的模塊化、服務端渲染等技術都是創建在對瀏覽器的基礎上完成的。好比瀏覽器的網絡交互方式,頁面渲染方式,UI進程管理這些都是瀏覽器內核的關鍵模塊。BOM在必定程度上讓咱們跳出了html,css,js的意識範圍,原來前端開發還有這樣的接口,這樣的功能,可是他更精彩的部分仍是被深深的隱藏等待你去發掘,這條取經之路剛剛開始。下面我將瀏覽器核心的幾個模塊列出來供你們參考:

  • 資源加載和網絡棧
  • HTML解析和DOM模型
  • CSS解析器和樣式佈局
  • 渲染樹
  • 硬件加速機制與js引擎(V8引擎)
  • 移動端渲染機制
  • 多媒體

 後面將就着這些問題對瀏覽器相關內容逐一闡述,本人也還在學習階段,這些內容一方面是學習總結,另外一方面是爲了學習有清晰的目標和思路,寫博客會讓我對涉及到的知識點須要清晰的認識和理解,同時也能夠表達本身的疑惑,相互學習,若是有不正確的內容還請不吝賜教。

相關文章
相關標籤/搜索