Web前端知識體系精簡
Web前端技術由 html、css 和 javascript 三大部分構成,是一個龐大而複雜的技術體系,其複雜程度不低於任何一門後端語言。而我們在學習它的時候往往是先從某一個點切入,然後不斷地接觸和學習新的知識點,因此對於初學者很難理清楚整個體系的脈絡結構。本文將對Web前端知識體系進行簡單的梳理,對應的每個知識點點到為止,不作詳細介紹。目的是幫助大家審查自己的知識結構是否完善,如有遺漏或不正確的地方,希望共勉。
JAVASCRIPT 篇
0、基礎語法
Javascript 基礎語法包括:變數宣告、資料型別、函式、控制語句、內建物件等。
在ES5 中,變數宣告有兩種方式,分別是 var 和 function ,var 用於宣告普通的變數,接收任意型別,function用於宣告函式。另外,ES6 新增了 let、const、import 和 class 等四個命令,分別用以宣告 普通變數、靜態變數、模組 和 類 。
JS資料型別共有六種,分別是 String、Number、Boolean、Null、Undefined 和 Object 等, 另外,ES6新增了 Symbol 型別。其中,Object 是引用型別,其他的都是原始型別(Primitive Type)。
原始型別也稱為基本型別或簡單型別,因為其佔據空間固定,是簡單的資料段,為了便於提升變數查詢速度,將其儲存在棧(stack)中(按值訪問)。為了便於操作這類資料,ECMAScript 提供了 3 個基本包裝型別:Boolean、Number 和 String 。基本包裝型別是一種特殊的引用型別,每當讀取一個基本型別值的時候,JS內部就會建立一個對應的包裝物件,從而可以呼叫一些方法來操作這些資料。
引用型別由於其值的大小會改變,所以不能將其存放在棧中,否則會降低變數查詢速度,因此其儲存在堆(heap)中,儲存在變數處的值是一個指標,指向儲存物件的記憶體處(按址訪問),對於引用型別的值,可以為其新增屬性和方法,也可以改變和刪除其屬性和方法;但基本型別不可以新增屬性和方法。關於更多介紹請參考:詳解 ECMAScript 資料型別
Javascript 可以通過 typeof 來判斷原始資料型別,但不能判斷引用型別,要知道引用型別的具體型別,需要通過 Object 原型上的 toString 方法來判斷,關於資料型別判斷可以參考:檢測資料型別的四種方案
JS中的函式存在著三種角色:普通函式、建構函式、物件方法。同一個函式,呼叫方式不同,函式的作用不一樣,所扮演的角色也不一樣。直接呼叫時就是普通函式,通過new建立物件時就是建構函式,通過物件呼叫時就是方法。
JS常用的內建物件有window、Date、Array、JSON、RegExp 等,window是瀏覽器在執行指令碼時建立的一個全域性物件,主要描述瀏覽器視窗相關的屬性和狀態,這個後面會講到,Date 和 Array 使用場景最多,JSON主要用於物件的序列化和反序列化,還有一個作用就是實現物件的深拷貝。RegExp 即正規表示式,是處理字串的利器。 關於更多介紹請參考:陣列常用操作方法總結 , JavaScript 正規表示式總結
1、函式原型鏈
JS是一種基於物件的語言,但在ES6 之前是不支援繼承的,為了具備繼承的能力,Javascript 在函式物件上建立了原型物件 prototype,並以函式物件為主線,從上至下,在JS內部構建了一條原型鏈。原型鏈把一個個獨立的物件聯絡在一起,Object 則是所有物件的祖宗, 任何物件所建立的原型鏈最終都指向了Object,並以 Object 終結。
簡單來說,就是建立了變數查詢機制,當訪問一個物件的屬性時,先查詢物件本身是否存在,如果不存在就去該物件所在的原型連上去找,直到 Object 物件為止,如果都沒有找到該屬性才會返回 undefined。因此,我們可以通過原型鏈來實現繼承機制。關於函式原型鏈請參考:認識原型物件和原型鏈
2、函式作用域
函式作用域就是變數在宣告它們的函式體以及這個函式體巢狀的任意函式體內都是有定義的。通俗來講就是,在一個函式裡,有些變數可以訪問,有些不可以訪問。那些能訪問的變數所形成的範圍,就是這個函式的作用域。
在 JavaScript 中,沒有塊級作用域,只有函式作用域,也就是說 if、while、for 語句不會形成獨立的作用域。但有一個特殊情況,即 with 語句和 catch 語句會形成臨時作用域,語句執行結束後,該作用域就會被釋放。關於函式作用域請參考:函式作用域和作用域鏈
3、this 指標
this 指標存在於函式中,用以標識函式執行時所處的上下文。函式的型別不同,this 指向規則也不一樣:對於普通函式,this 始終指向全域性物件window;對於建構函式,this則指向新建立的物件;對於方法,this指向呼叫該方法的物件。另外,Function物件也提供了call、apply 和 bind 等方法來改變函式的 this 指向,其中,call 和 apply 主動執行函式,bind一般在事件回撥中使用,而 call 和 apply 的區別只是引數的傳遞方式不同。關於更多介紹請參考:深入理解 call,apply和 bind
如果往深的去理解,無論什麼函式,this 是否被改變, 本質上,this 均指向觸發函式執行時的那個物件。而在函式執行時,this 的值是不能被改變的。
4、new 操作符
函式的建立有三種方式,即 顯式宣告、匿名定義 和 new Function() 。前面提到,JS 中的函式即可以是函式,也可以是方法,還可以是建構函式。
當使用new來建立物件時,該函式就是建構函式,JS 將新物件的原型鏈指向了建構函式的原型物件,於是就在新物件和函式物件之間建立了一條原型鏈,通過新物件可以訪問到函式物件原型 prototype 中的方法和屬性。關於建構函式和 new 操作符請參考: 深入理解 new 操作符
5、閉包
閉包不是一個孤立的概念,需要從函式作用域的角度來理解。
每個函式都有自己的作用域,如果在一個函式裡定義了另一個函式,那麼對應的就有兩個作用域,這兩個作用域就會形成一個鏈條,俗稱作用域鏈。本質上講,作用域鏈是一個自上而下的連結串列, 連結串列的最頂端是內部函式作用域,連結串列的最底端是全域性作用域。內部函式有權訪問整個作用域鏈上的變數。正常情況下,每當一個函式執行完畢,對應的作用域就會從該連結串列上移除,然後銷燬。
但如果函式 A 把函式 B 作為返回值返回時,情況又不一樣。
首先,函式 A 返回的是函式 B 的引用,也就是說,B 可能會在其他地方被呼叫。上面提到,函式 B 的定義是位於函式 A 內部,因此 A 和 B 會形成一條作用域鏈,函式 B 有可能會讀取 A 中的變數 。為了保證函式 B 能夠在其他地方正確執行,函式 B 所在的這條作用域鏈就不能被破壞。所以,即使函式 A 執行返回後,A 的作用域也不能釋放,需要一直儲存在記憶體中,以確保函式 B 能夠正常讀取裡面的變數。函式 B 具有永久訪問 A 作用域的特權,確切說,函式 B 就是閉包 。
用一句話總結就是: 閉包,是一個有權訪問另一個函式作用域的函式。
6、單執行緒與事件迴圈
Javascript 是單執行緒語言。在瀏覽器中,當JS程式碼被載入時,瀏覽器會為其分配一個主執行緒來執行任務,主執行緒會在棧中建立一個全域性執行環境 (全域性作用域)。每當有一個函式進入執行流時,就會形成一個對應的執行環境(函式作用域),並將該執行環境壓入棧中。每當一個函式執行完畢以後,對應的執行環境就會從棧中彈出,然後被銷燬。這就是執行環境棧,執行環境棧的作用就是保證所有的函式能按照正確的順序被執行。
但在瀏覽器中,有一些任務是非常耗時的,比如 ajax請求、定時器、事件等。為了保證主執行緒任務不受影響,Javascript 內部維護了一個任務佇列, 當這些耗時任務結束時(Ajax 請求返回、定時器超時、事件被觸發),就將對應的回撥函式插入佇列中進行等待。這些任務的執行時機並不確定,只有當所有同步任務執行完畢後,執行環境棧被清空(棧底的全域性執行環境會一直存在,直到程式退出)以後,然後再從任務佇列中依次讀取回撥函式,並將其壓入執行環境棧中。於是,主執行緒開始執行新的同步任務,執行完畢後再從棧中彈出,棧被清空。
主執行緒從任務佇列中讀取任務是不斷迴圈的,每當棧被清空後,主執行緒就會從任務佇列中讀取新的任務並執行,如果沒有新的任務,就會一直等待,直到有新的任務。JavaScript 的這種執行機制就叫做任務迴圈。因為每個任務都由一個事件所觸發,所以也叫事件迴圈。
7、非同步通訊 Ajax技術
Ajax是瀏覽器專門用來和伺服器進行互動的非同步通訊技術,其核心物件是 XMLHttpRequest,通過該物件可以建立一個 Ajax 請求。Ajax 請求是一個耗時的非同步操作,當請求發出以後,Ajax 提供了兩個狀態位來描述請求在不同階段的狀態,這兩個狀態位分別是 readyState 和 status ,readyState 通過 5個狀態碼來描述一個請求的 5 個階段:
0 - 請求未傳送,初始化階段
1 - 請求傳送中,伺服器還未收到請求
2 - 請求傳送成功,伺服器已收到請求
3 - 伺服器處理完成,開始響應請求,傳輸資料
4 - 客戶端收到請求,並完成了資料下載,生成了響應物件
status 用於描述服務端對請求處理的情況,200 表示正確響應了請求,404 表示伺服器找不到資源,500 代表伺服器內部異常等等。
Ajax 物件還可以設定一個 timeout 值,代表超時時間。切記:timeout 只會影響 readyState,而不會影響 status,因為超時只會中斷資料傳輸,但不會影響伺服器的處理結果。 如果 timeout 設定的不合理,就會導致響應碼 status 是 200,但 response裡卻沒有資料,這種情況就是伺服器正確響應了請求,但資料的下載被超時中斷了。
為了保證使用者資訊的安全,瀏覽器引入了同源策略,對指令碼請求做了限制,不允許 Ajax 跨域請求伺服器 ,只允許請求和當前地址同域的伺服器資源。但不限制 HTML 標籤傳送跨域請求,比如 script、img、a 標籤等,因此可以利用標籤跨域能力來實現跨域請求,這就是 JSONP 能夠跨域的原理。
JSONP 雖然可以解決跨域問題,但只能傳送 GET 請求,並且沒有有效的錯誤捕獲機制 。為了解決這個問題,W3C 在 XMLHttpRequest Level2 中提出了 CORS 規範,即 跨域資源共享。它不是一個新的 API,而是一個標準規範 。當瀏覽器發現該請求需要跨域時,就會自動在頭資訊中新增一個 Origin 欄位,用以說明本次請求來自哪個源。伺服器根據這個值,決定是否同意這次請求。 關於 CORS 的詳細介紹請參考:跨域資源共享 CORS 詳解
隨著移動端的快速發展,Web 技術的應用場景正在變得越來越複雜,關注點分離原則在系統設計層面就顯得越來越重要,而 XMLHttpRequest 是 Ajax 最古老的一個介面,因而不太符合現代化的系統設計理念。因此,瀏覽器提供了一個新的 Ajax 介面,即 Fetch,Fetch 是基於 ES6 的 Promise 思想設計的,更符合關注點分離原則。關於 Fetch 的更多介紹請參考:傳統 Ajax 已死,Fetch 永生
8、模組化
歷史上,Javascript 規範一直沒有模組(module)體系,即無法將一個大程式拆分成互相依賴的小檔案,再用簡單的方法拼裝起來。在 ES6 之前,為了實現 JS 模組化程式設計,社群制定了一些模組載入方案,最主要有 CMD 和 AMD 兩種,分別以 commonjs 和 requirejs 為代表。ES6 在語言標準的層面上,實現了模組化程式設計,其設計思想是,儘量靜態化,使得編譯時就能確定模組的依賴關係,即編譯時載入,而 CMD 和 AMD 是在執行時確定依賴關係,即執行時載入。關於 ES6 模組化請參考:ES6模組化
9、Node.js
Node.js 是一個基於 Chrome V8 引擎的 JavaScript 執行環境,它的執行不依賴於瀏覽器作為宿主環境,而是和服務端程式一樣可以獨立的執行,這使得JS程式設計第一次從客戶端被帶到了服務端,Node.js 在服務端的優勢是,它採用單執行緒和非同步I/O模型,實現了一個高併發、高效能的執行時環境。相比傳統的多執行緒模型,Node.js 實現簡單,並且可以減少資源開銷。關於 Node.js單執行緒模型請參考:淺析 Node.js 單執行緒模型
10、ES6
ES6 是 ECMAScript 6.0 的簡寫,即 Javascript 語言的下一代標準,已經在 2015年6月正式釋出了,它的目標是讓JS能夠方便的開發企業級大型應用程式,因此,ES6的一些規範正在逐漸向Java、C# 等後端語言標準靠近。ES6 規範中,比較重大的變化有以下幾個方面:
- 新增 let、const 命令 來宣告變數,和var 相比,let 宣告的變數不存在變數提升問題,但沒有改變JS弱型別的特點,依然可以接受任意型別變數的宣告;const 宣告的變數不允許在後續邏輯中改變,提高了JS語法的嚴謹性。
- 新增解構賦值、rest語法、箭頭函式等,這些都是為了讓程式碼看起來更簡潔,而包裝的語法糖。
- 新增模組化機制,這是 JavaScript 走向規範比較重要的一步,讓前端更方便的實現工程化。
- 新增類和繼承的概念,配合模組化,JavaScript 也可以實現高複用、高擴充套件的系統架構。
- 新增模板字串功能,高效簡潔,結束拼接字串的時代。
- 新增 Promise 機制,解決非同步回撥多層巢狀的問題。
CSS 篇
1、CSS選擇器
CSS選擇器即通過某種規則來匹配相應的標籤,併為其設定CSS樣式,常用的有類選擇器、標籤選擇器、ID選擇器、後代選擇器、群組選擇器、偽類選擇器(before/after)、兄弟選擇器(+~)、屬性選擇器等等。
2、CSS Reset
HTML 標籤在不設定任何樣式的情況下,也會有一個預設的CSS樣式,而不同核心瀏覽器對於這個預設值的設定則不盡相同,這樣可能會導致同一套程式碼在不同瀏覽器上的顯示效果不一致,而出現相容性問題。因此,在初始化時,需要對常用標籤的樣式進行初始化,使其預設樣式統一,這就是CSS Reset ,即CSS樣式重置,比如:*{margin:0,padding:0} 就是最簡單CSS Reset, 關於CSS重置請參考:Neat.css
3、盒子佈局
盒子模型是CSS比較重要的一個概念,也是CSS 佈局的基石。 常見的盒子模型有塊級盒子(block)和行內盒子(inline-block),與盒子相關的幾個屬性有:margin、border、padding和content 等,這些屬性的作用是設定盒子與盒子之間的關係以及盒子與內容之間的關係。其中,只有普通文件流中塊級盒子的垂直外邊距才會發生合併,而行內盒子、浮動盒子或絕對定位之間的外邊距不會合並。另外,box-sizing 屬性的設定會影響盒子width和height的計算。
4、浮動佈局
設定元素的 float 屬性值為 left 或 right,就能使該元素脫離普通文件流,向左或向右浮動。一般在做宮格佈局時會用到,如果子元素全部設定為浮動,則父元素是塌陷的,這時就需要清除浮動,清除浮動的方法也很多,常用的方法是在元素末尾加空元素設定clear:both, 更高階一點的就給父容器設定before/after來模擬一個空元素,還可以直接設定overflow屬性為auto/hidden來清除浮動。除浮動可以實現宮格佈局,行內盒子(inline-block)和table也可以實現同樣的效果。
5、定位佈局
設定元素的position屬性值為 relative/absolute/fixed,就可以使該元素脫離文件流,並以某種參照座標進行偏移。其中,releave 是相對定位,它以自己原來的位置進行偏移,偏移後,原來的空間不會被其他元素佔用;absolute 是絕對定位,它以離自己最近的定位父容器作為參照進行偏移;為了對某個元素進行定位,常用的方式就是設定父容器的poistion:relative,因為相對定位元素在不設定 top 和 left 值時,不會對元素位置產生影響;fixed 即固定定位,它則以瀏覽器視窗為參照物,PC網頁底部懸停的banner一般都可以通過fixed定位來實現,但fixed屬性在移動端有相容性問題,因此不推薦使用,可替代的方案是:絕對定位+內部滾動。
6、彈性佈局
彈性佈局即Flex佈局,定義了flex的容器一個可伸縮容器,首先容器本身會根據容器中的元素動態設定自身大小;然後當Flex容器被應用一個大小時(width和height),將會自動調整容器中的元素適應新大小。Flex容器也可以設定伸縮比例和固定寬度,還可以設定容器中元素的排列方向(橫向和縱向)和是否支援元素的自動換行。有了這個神器,做頁面佈局的可以方便很多了。注意,設為Flex佈局以後,子元素的float、clear和vertical-align 屬性將失效。關於flexbox請參考:圖解CSS3 Flexbox屬性
7、CSS3 動畫
CSS3中規範引入了兩種動畫,分別是 transition 和 animation,transition 可以讓元素的CSS屬性值的變化在一段時間內平滑的過渡,形成動畫效果,為了使元素的變換更加豐富多彩,CSS3還引入了transfrom 屬性,它可以通過對元素進行 平移(translate)、旋轉(rotate)、放大縮小(scale)、傾斜(skew) 等操作,來實現2D和3D變換效果。transiton 還有一個結束事件 transitionEnd,該事件是在CSS完成過渡後觸發,如果過渡在完成之前被移除,則不會觸發transitionEnd 。
animation 需要設定一個@keyframes,來定義元素以哪種形式進行變換, 然後再通過動畫函式讓這種變換平滑的進行,從而達到動畫效果,動畫可以被設定為永久迴圈演示。設定 animation-play-state:paused 可以暫停動畫,設定 animation-fill-mode:forwards 可以讓動畫完成後定格在最後一幀。另外,還可以通過JS監聽animation的開始、結束和重複播放時的狀態,分別對應三個事件,即 animationStart、animationEnd、animationIteration 。注意,當播放次數設定為1時,不會觸發 animationIteration 。
和 transition相比,animation 設定動畫效果更靈活更豐富,還有一個區別是:transition 只能通過主動改變元素的css值才能觸發動畫效果,而animation一旦被應用,就開始執行動畫。另外,HTML5 還新增了一個動畫API,即 requestAnimationFrame,它通過JS來呼叫,並按照螢幕的繪製頻率來改變元素的CSS屬性,從而達到動畫效果,關於這個API的介紹請參考:requestAnimationFrame
8、BFC
BFC是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面元素。比如:內部滾動就是一個BFC,當一個父容器的overflow-y設定為auto時,並且子容器的長度大於父容器時,就會出現內部滾動,無論內部的元素怎麼滾動,都不會影響父容器以外的佈局,這個父容器的渲染區域就叫BFC。滿足下列條件之一就可觸發 BFC:
- 根元素,即 HTML 元素
- float 的值不為 none
- overflow 的值不為 visible
- display 的值為 inline-block、table-cell、table-caption
- position 的值為 absolute 或 fixed
9、Sprite,Iconfont,@font-face
對於大型站點,為了減少http請求的次數,一般會將常用的小圖示排到一個大圖中,頁面載入時只需請求一次網路, 然後在css中通過設定background-position來控制顯示所需要的小圖示,這就是Sprite圖。
Iconfont,即字型圖示,就是將常用的圖示轉化為字型資源存在檔案中,通過在CSS中引用該字型檔案,然後可以直接用控制字型的css屬性來設定圖示的樣式,字型圖示的好處是節省網路請求、其大小不受螢幕解析度的影響,並且可以任意修改圖示的顏色。
@font-face是CSS3中的一個模組,通過@font-face可以定義一種全新的字型,然後就可以通過css屬性font-family來使用這個字型了,即使作業系統沒有安裝這種字型,網頁上也會正常顯示出來。
10、CSS Hack
早期,不同核心瀏覽器對CSS屬性的解析存在著差異,導致顯示效果不一致,比如 margin 屬性在ie6中顯示的距離會比其他瀏覽器中顯示的距離寬2倍,也就是說margin-left:20px;在ie6中距左側元素的實際顯示距離是40px,而在非ie6的瀏覽器上顯示正常。因此,如果要想讓所有瀏覽器中都顯示是20px的寬度,就需要在CSS樣式中加入一些特殊的符號,讓不同的瀏覽器識別不同的符號,以達到應用不同的CSS樣式的目的,這種方式就是css hack, 對於ie6中的margin應用hack就會變成這樣:.el {margin-left:20px;_margin-left:10px}
相容各大瀏覽器的 css hack 如下:
HTML 篇
1、BOM
BOM 是 Browser Object Model 的縮寫,即瀏覽器物件模型,當一個瀏覽器頁面初始化時,會在記憶體建立一個全域性的物件,用以描述當前視窗的屬性和狀態,這個全域性物件被稱為瀏覽器物件模型,即BOM。BOM的核心物件就是window,window 物件也是BOM的頂級物件,其中包含了瀏覽器的 6個核心模組:
document - 即文件物件,渲染引擎在解析HTML程式碼時,會為每一個元素生成對應的DOM物件,由於元素之間有層級關係,因此整個HTML程式碼解析完以後,會生成一個由不同節點組成的樹形結構,俗稱DOM樹,document 用於描述DOM樹的狀態和屬性,並提供了很多操作DOM的API。
frames - HTML 子框架,即在瀏覽器裡嵌入另一個視窗,父框架和子框架擁有獨立的作用域和上下文。
history - 以棧(FIFO)的形式儲存著頁面被訪問的歷史記錄,頁面前進即入棧,頁面返回即出棧。
location - 提供了當前視窗中載入的文件相關資訊以及一些導航功能。
navigator - 用來描述瀏覽器本身,包括瀏覽器的名稱、版本、語言、系統平臺、使用者特性字串等資訊。
screen - 提供了瀏覽器顯示螢幕的相關屬性,比如顯示螢幕的寬度和高度,可用寬度和高度。
2、DOM 系統
DOM 是 Document Object Model 的縮寫,即 文件物件模型,是所有瀏覽器公共遵守的標準,DOM 將HTML和XML文件對映成一個由不同節點組成的樹型結構,俗稱DOM樹。其核心物件是document,用於描述DOM樹的狀態和屬性,並提供對應的DOM操作API。隨著歷史的發展,DOM 被劃分為1級、2級、3級,共3個級別:
1級DOM - 在1998年10月份成為W3C的提議,由DOM核心與DOM HTML兩個模組組成。DOM核心能對映以XML為基礎的文件結構,允許獲取和操作文件的任意部分。DOM HTML通過新增HTML專用的物件與函式對DOM核心進行了擴充套件。
2級DOM - 鑑於1級DOM僅以對映文件結構為目標,DOM 2級面向更為寬廣。通過對原有DOM的擴充套件,2級DOM通過物件介面增加了對滑鼠和使用者介面事件(DHTML長期支援滑鼠與使用者介面事件)、範圍、遍歷(重複執行DOM文件)和層疊樣式表(CSS)的支援。同時也對DOM 1的核心進行了擴充套件,從而可支援XML名稱空間。
3級DOM - 通過引入統一方式載入和儲存文件和文件驗證方法對DOM進行進一步擴充套件,DOM3包含一個名為“DOM載入與儲存”的新模組,DOM核心擴充套件後可支援XML1.0的所有內容,包括XML Infoset、 XPath、和XML Base。
瀏覽器對不同級別DOM的支援情況如下所示:
從圖中可以看出,移動端常用的 webkit 核心瀏覽器目前只支援 DOM2,而不支援 DOM3 。
3、事件系統
事件是使用者與頁面互動的基礎,到目前為止,DOM事件從PC端的 滑鼠事件(mouse) 發展到了 移動端的 觸控事件(touch) 和 手勢事件(guesture),touch事件描述了手指在螢幕操作的每一個細節,guesture 則是描述多手指操作時更為複雜的情況,總結如下:
- 第一根手指放下,觸發 touchstart,除此之外什麼都不會發生
- 手指滑動時,觸發touchmove
- 第二根手指放下,觸發 gesturestart
- 觸發第二根手指的 touchstart
- 立即觸發 gesturechange
- 任意手指移動,持續觸發 gesturechange
- 第二根手指彈起時,觸發 gestureend,以後將不會再觸發 gesturechange
- 觸發第二根手指的 touchend
- 觸發touchstart (多根手指在螢幕上,提起一根,會重新整理一次全域性touch)
- 彈起第一根手指,觸發 touchend
更多關於手勢事件的介紹請參考:gesture事件處理複雜手勢
DOM2.0 模型將事件處理流程分為三個階段,即事件捕獲階段、事件處理階段、事件冒泡階段,如圖所示:
事件捕獲:當使用者觸發點選事件後,頂層物件document 就會發出一個事件流,從最外層的DOM節點向目標元素節點傳遞,最終到達目標元素。
事件處理:當到達目標元素之後,執行目標元素繫結的處理函式。如果沒有繫結監聽函式,則不做任何處理。
事件冒泡:事件流從目標元素開始,向最外層DOM節點傳遞,途中如果有節點繫結了事件處理函式,這些函式就會被執行。
利用事件冒泡原理可以實現 事件委託,所謂事件委託,就是在父元素上新增事件監聽器,用以監聽和處理子元素的事件,避免重複為子元素繫結相同的事件。當目標元素的事件被觸發以後,這個事件就從目標元素開始,向最外層元素傳遞,最終冒泡到父元素上,父元素再通過event.target 獲取到這個目標元素,這樣做的好處是,父元素只需繫結一個事件監聽,就可以對所有子元素的事件進行處理了,從而減少了不必要的事件繫結,對頁面效能有一定的提升。
4、HTML解析過程
瀏覽器載入 html 檔案以後,渲染引擎會從上往下,一步步來解析HTML標籤,大致過程如下:
- 使用者輸入網址,瀏覽器向伺服器發出請求,伺服器返回html檔案;
- 渲染引擎開始解析 html 標籤,並將標籤轉化為DOM節點,生成 DOM樹;
- 如果head 標籤中引用了外部css檔案,則發出css檔案請求,伺服器返回該檔案,該過程會阻塞後面的解析;
- 如果引用了外部 js 檔案,則發出 js 檔案請求,伺服器返回後立即執行該指令碼,這個過程也會阻塞html的解析;
- 引擎開始解析 body 裡面的內容,如果標籤裡引用了css 樣式,就需要解析剛才下載好的css檔案,然後用css來設定標籤的樣式屬性,並生成渲染樹;
- 如果 body 中的 img 標籤引用了圖片資源,則立即向伺服器發出請求,此時引擎不會等待圖片下載完畢,而是繼續解析後面的標籤;
- 伺服器返回圖片檔案,由於圖片需要佔用一定的空間,會影響到後面元素的排版,因此引擎需要重新渲染這部分內容;
- 如果此時 js 指令碼中執行了 style.display="none",佈局被改變,引擎也需要重新渲染這部分程式碼;
- 直到 html 結束標籤為止,頁面解析完畢。
5、重繪與迴流
當渲染樹中的一部分(或全部)因為元素的規模尺寸,佈局,隱藏等改變而需要重新構建。這就稱為迴流。比如上面的img檔案載入完成後就會引起迴流,每個頁面至少需要一次迴流,就是在頁面第一次載入的時候。
當渲染樹中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響佈局的,比如 background-color。則就叫稱為重繪。
從上面可以看出,迴流必將引起重繪,而重繪不一定會引起迴流。會引起重繪和迴流的操作如下:
- 新增、刪除元素(迴流+重繪)
- 隱藏元素,display:none(迴流+重繪),visibility:hidden(只重繪,不迴流)
- 移動元素,比如改變top,left的值,或者移動元素到另外一個父元素中。(重繪+迴流)
- 對 style 的操作(對不同的屬性操作,影響不一樣)
- 還有一種是使用者的操作,比如改變瀏覽器大小,改變瀏覽器的字型大小等(迴流+重繪)
注意問題:
transform 操作不會引起重繪和迴流,是一種高效率的渲染。這是因為transform屬於合成屬性,對合成屬性進行transition/animation 動畫時將會建立一個合成層,這使得動畫元素在一個獨立的層中進行渲染,當元素的內容沒有發生改變,就沒必要進行重繪,瀏覽器會通過重新複合來建立動畫幀。
6、本地儲存
本地儲存最原始的方式就是 cookie,cookie 是存放在本地瀏覽器的一段文字,資料以鍵值對的形式儲存,可以設定過期時間。 但是 cookie 不適合大量資料的儲存,因為每請求一次頁面,cookie 都會傳送給伺服器,這使得 cookie 速度很慢而且效率也不高。因此cookie的大小被限制為4k左右(不同瀏覽器可能不同,分HOST),如下所示:
- Firefox 和 Safari 允許 cookie 多達 4097 個位元組,包括名(name)、值(value) 和 等號。
- Opera 允許 cookie 多達 4096 個位元組,包括:名(name)、值(value) 和 等號。
- Internet Explorer 允許 cookie 多達4095個位元組,包括:名(name)、值(value) 和 等號。
在所有瀏覽器中,任何cookie大小超過限制都被忽略,且永遠不會被設定。
html5 提供了兩種在客戶端儲存資料的新方法:localStorage 和 sessionStorage, 它們都是以key/value 的形式來儲存資料,前者是永久儲存,後者的儲存期限僅限於瀏覽器會話(session),即當瀏覽器視窗關閉後,sessionStorage中的資料被清除。
localStorage的儲存空間大約5M左右(不同瀏覽器可能不同,分 HOST),這個相當於一個5M大小的前端資料庫,相比於cookie,可以節約頻寬,但localStorage在瀏覽器隱私模式下是不可讀取的,當儲存資料超過了localStorage 的儲存空間後會丟擲異常。
此外,H5還提供了逆天的websql和 indexedDB,允許前端以關係型資料庫的方式來儲存本地資料,相對來說,這個功能目前應用的場景比較少,此處不作介紹。
7、瀏覽器快取機制
瀏覽器快取機制是指通過 HTTP 協議頭裡的 Cache-Control (或 Expires) 和 Last-Modified (或 Etag) 等欄位來控制檔案快取的機制。
Cache-Control 用於控制檔案在本地快取有效時長。最常見的,比如伺服器回包:Cache-Control:max-age=600 表示檔案在本地應該快取,且有效時長是600秒 (從發出請求算起)。在接下來600秒內,如果有請求這個資源,瀏覽器不會發出 HTTP 請求,而是直接使用本地快取的檔案。
Last-Modified 是標識檔案在伺服器上的最新更新時間。下次請求時,如果檔案快取過期,瀏覽器通過 If-Modified-Since 欄位帶上這個時間,傳送給伺服器,由伺服器比較時間戳來判斷檔案是否有修改。如果沒有修改,伺服器返回304告訴瀏覽器繼續使用快取;如果有修改,則返回200,同時返回最新的檔案。
Cache-Control 通常與 Last-Modified 一起使用。一個用於控制快取有效時間,一個在快取失效後,向服務查詢是否有更新。
Cache-Control 還有一個同功能的欄位:Expires。Expires 的值一個絕對的時間點,如:Expires: Thu, 10 Nov 2015 08:45:11 GMT,表示在這個時間點之前,快取都是有效的。
Expires 是 HTTP1.0 標準中的欄位,Cache-Control 是 HTTP1.1 標準中新加的欄位,功能一樣,都是控制快取的有效時間。當這兩個欄位同時出現時,Cache-Control 是高優化級的。
Etag 也是和 Last-Modified 一樣,對檔案進行標識的欄位。不同的是,Etag 的取值是一個對檔案進行標識的特徵字串。在向伺服器查詢檔案是否有更新時,瀏覽器通過 If-None-Match 欄位把特徵字串傳送給伺服器,由伺服器和檔案最新特徵字串進行匹配,來判斷檔案是否有更新。沒有更新回包304,有更新回包200。Etag 和 Last-Modified 可根據需求使用一個或兩個同時使用。兩個同時使用時,只要滿足基中一個條件,就認為檔案沒有更新。
另外有兩種特殊的情況:
手動重新整理頁面(F5) - 瀏覽器會直接認為快取已經過期(可能快取還沒有過期),在請求中加上欄位:Cache-Control:max-age=0,發包向伺服器查詢是否有檔案是否有更新。
強制重新整理頁面(Ctrl+F5) - 瀏覽器會直接忽略本地的快取(有快取也會認為本地沒有快取),在請求中加上欄位:Cache-Control:no-cache (或 Pragma:no-cache),發包向服務重新拉取檔案。
關於更多瀏覽器快取介紹請參考:H5 快取機制淺析 移動端 Web 載入效能優化
8、History
使用者訪問網頁的歷史記錄通常會被儲存在一個類似於棧的物件中,即 history 物件,點選返回就出棧,跳下一頁就入棧。 它提供了以下方法來操作頁面的前進和後退:
- window.history.back( ) 返回到上一個頁面
- window.history.forward( ) 進入到下一個頁面
- window.history.go( [delta] ) 跳轉到指定頁面
HTML5 對History Api 進行了增強,新增了兩個Api 和一個事件,分別是pushState、replaceState 和 onpopstate:
- pushState是往history物件裡新增一個新的歷史記錄,即壓棧。
- replaceState 是替換history物件中的當前歷史記錄。
當點選瀏覽器後退按鈕或 js呼叫history.back 都會觸發 onpopstate 事件。
與其類似的還有一個事件:onhashchange,onhashchange是老 API,瀏覽器支援度高,本來是用來監聽hash變化的,但可以被利用來做客戶端前進和後退事件的監聽,而onpopstate 是專門用來監聽瀏覽器前進後退的,不僅可以支援 hash,非 hash 的同源 url 也支援。
9、HTML5離線快取
HTML5離線快取又叫Application Cache,是從瀏覽器的快取中分出來的一塊快取區,如果要在這個快取中儲存資料,可以使用一個描述檔案(manifest file),列出要下載和快取的資源。
manifest 檔案是簡單的文字檔案,它告知瀏覽器被快取的內容(以及不快取的內容)。manifest 檔案可分為三個部分:
CACHE MANIFEST - 在此標題下列出的檔案將在首次下載後進行快取
NETWORK - 在此標題下列出的檔案需要與伺服器的連線,且不會被快取
FALLBACK - 在此標題下列出的檔案規定當頁面無法訪問時的回退頁面(比如 404 頁面)
離線快取為應用帶來三個優勢:
離線瀏覽 - 使用者可在應用離線時使用它們
速度 - 已快取資源載入得更快
減少伺服器負載 - 瀏覽器將只從伺服器下載更新過或更改過的資源。
10、Web語義化與SEO
Web語義化是指使用語義恰當的標籤,使頁面有良好的結構,頁面元素有含義,能夠讓人和搜尋引擎都容易理解。
SEO是指在瞭解搜尋引擎自然排名機制的基礎之上,對網站進行內部及外部的調整優化,改進網站在搜尋引擎中關鍵詞的自然排名,獲得更多的展現量,吸引更多目標客戶點選訪問網站,從而達到網際網路營銷及品牌建設的目標。
搜尋引擎通過爬蟲技術獲取的頁面就是由一堆 html 標籤組成的程式碼,人可以通過視覺化的方式來判斷頁面上哪些內容是重點,而機器做不到。 但搜尋引擎會根據標籤的含義來判斷內容的權重,因此,在合適的位置使用恰當的標籤,使整個頁面的語義明確,結構清晰,搜尋引擎才能正確識別頁面中的重要內容,並予以較高的權值。比如h1~h6這幾個標籤在SEO中的權值非常高,用它們作頁面的標題就是一個簡單的SEO優化。
相關文章
- web前端知識體系圖Web前端
- web開發知識體系中必要的知識點Web
- 前端---梳理 http 知識體系 2前端HTTP
- 前端---梳理 http 知識體系 1前端HTTP
- jquery主要知識點(精簡)jQuery
- web前端知識點(JavaScript篇)Web前端JavaScript
- web前端知識點(webpack篇)Web前端
- Web前端基礎知識整理Web前端
- 大廠前端校招 - 知識體系前端
- 前端-基礎知識體系(初級-上)前端
- 前端-基礎知識體系(初級-下)前端
- web前端需要掌握什麼知識?Web前端
- 好程式設計師web前端分享web前端入門知識程式設計師Web前端
- Vue知識精簡總結-更新中Vue
- Web前端必備-Nginx知識彙總Web前端Nginx
- web前端知識梳理——HTML5(一)Web前端HTML
- 好程式設計師web前端教程分享web前端基礎知識程式設計師Web前端
- 前端知識體系思維導圖(持續更新...)前端
- web前端javascript+jquery知識點總結Web前端JavaScriptjQuery
- 小白階段如何學習Web前端知識Web前端
- 好程式設計師web前端教程分享web前端入門基礎知識程式設計師Web前端
- Web開發初探(系統理解Web知識點)Web
- Web前端之HTML+CSS的知識總結Web前端HTMLCSS
- 好程式設計師web前端分享Cookie知識程式設計師Web前端Cookie
- 參加web前端培訓要學哪些知識Web前端
- Web前端學習筆記之前端跨域知識總結Web前端筆記跨域
- [MongoDB知識體系] 一文全面總結MongoDB知識體系MongoDB
- [Redis知識體系] 一文全面總結Redis知識體系Redis
- Android知識體系大全!Android
- web知識梳理Web
- 好程式設計師分享Web前端知識之HTML程式設計師Web前端HTML
- 【Web前端基礎知識】css表示顏色的方法Web前端CSS
- Web前端主要學什麼?這些知識要掌握Web前端
- 零基礎該如何學習Web前端知識?Web前端
- Python知識體系-Python2基礎知識Python
- web前端學習知識點:V8的垃圾回收和記憶體限制Web前端記憶體
- 前端知識點前端
- HTML前端知識HTML前端