Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
者 | 敘帝利
鏈接 | www.cnblogs.com/nzbin/p/7073601.html
前言
這篇文章我已經(jīng)醞釀了半年之久,或者說拖沓了這么久吧。想說的東西很多,卻又無從說起。如今輕量級框架如雨后春筍,層出不窮。我想每個人都應(yīng)該歸納總結(jié)工作中的常見需求,編寫一套適合自己的 CSS 框架。
在之前的文章中,我提到了面向?qū)ο蟮?CSS(比如 BEM、OOCSS、SMACSS,詳見 http://vanseodesign.com/css/dry-principles/)。這是一種思想,并不涉及具體的 CSS 問題,主要是類命名的策略!現(xiàn)在仍然有很多人對于前端框架的認(rèn)識還停留在表面,認(rèn)為 Bootstrap 是后端人員專用,前端沒必要等等。
我不知道這種說法從何而來,我最開始也不喜歡使用框架,或許和很多人的想法一樣,畏懼新知識、害怕難以駕馭、遇到問題的時候無法解決等等。最關(guān)鍵的一點是很多人認(rèn)為框架的樣式是固定的,修改起來太麻煩,還不如自己根據(jù)設(shè)計圖寫起來方便。
為什么使用框架?答案顯而易見,效率。除此之外,使用框架或者研究框架的意義還有很多,比如面向?qū)ο笏枷氲木唧w實現(xiàn)。在上一家公司工作的時候,開始的幾個項目我也是用最原始的方法書寫 CSS 。項目之中最讓我頭疼的就是類的命名。我想大多數(shù)人都是根據(jù)功能去命名,這就造成了很多的冗余,相同的組件可能寫很多次。簡單舉一個例子,如下圖,個人中心的登錄界面。
很多人包括我剛開始的時候可能會選擇下面的類命名及布局方式,其通用性非常差:
<div class="login-area">
<div class="login-img">
<img src="..." />
</div>
<div class="login-text">
<a href="...">請點擊登錄</a>
</div>
</div>
然而了解 Bootstrap 的人應(yīng)該一眼就發(fā)現(xiàn)上圖就是一個 media 對象,無非一些小細(xì)節(jié)需要調(diào)整一下:
<div class="media">
<div class="media-left">
<img src="..." />
</div>
<div class="media-body media-middle">
<a href="...">請點擊登錄</a>
</div>
</div>
為了讓文字與圖片居中對齊,我們可以使用 Bootstrap 的.media-middle
的輔助類。如果在工作中還要根據(jù)需求自定義一些輔助類調(diào)整細(xì)節(jié),當(dāng)然這是一個移動端的例子,可以選擇移動端框架相關(guān)的 media 對象。
另外,在項目改版的時候,原始的方法的修改更是慘不忍睹,可以說是噩夢,冗長的 CSS 文件、混亂的功能劃分、類名、色值等等。最后也只能硬著頭皮一點一點修改。那一刻我才體會到框架的意義以及前端工具的重要性。我從工作中總結(jié)出,要么你可以熟練的使用某一個框架,要么就自己實現(xiàn)一個框架。
目前市面上前端框架主要分重量級與輕量級。重量級主要有 Bootstrap、Semantic、UIkit、Foundation 等,輕量級有 Pure、Skeleton、Miligram 等。經(jīng)常關(guān)注前端動態(tài)的工程師會發(fā)現(xiàn)輕量級框架每年都層出不窮。在我上面提到的主流輕量級框架之外還有很多類似的框架。
我一直問自己,為什么要重復(fù)造輪子。經(jīng)過研究,我發(fā)現(xiàn)這些輕量級框架其實大多都不能勝任工作需求,而且模仿的痕跡很重,基本上都或多或少的有 Bootstrap 的影子。那么這些輕量級框架有沒有意義呢?當(dāng)然有。但是就我個人觀點,選擇輕量級框架反倒不如自己實現(xiàn)一個框架。因為大多輕量級框架就像是工作總結(jié),是根據(jù)自己的業(yè)務(wù)需求實現(xiàn)的。所以大多不具有通用性。
前端框架的對比主要以 Bootstrap、Semantic、UIkit 為主,因為我個人感覺這三個最具有代表性,而且設(shè)計風(fēng)格各有特色。Foundation 也有很多大公司在用,但以我個人觀點,無論是框架的易用性還是設(shè)計風(fēng)格,相比其它幾個框架稍遜一籌。
其中 Bootstrap 和 Semantic 是面向?qū)ο蟮淖詈皿w現(xiàn)。
我先說一下 Bootstrap 的優(yōu)勢,不是設(shè)計風(fēng)格,不是模塊,不是特效,而是柵格,響應(yīng)式柵格。Bootstrap 的柵格在與其它框架對比中占有絕對優(yōu)勢,無論是柵格的劃分還是類名的風(fēng)格都堪稱經(jīng)典。如果讀者有心看一下 Bootstrap 的 Less 源文件,就會感受到 Bootstrap 對于響應(yīng)式柵格的獨具匠心。其實在 Bootstrap 之前也有很多柵格方案,但是給人的感覺就是不夠利索,類名繁瑣不好記。而后來的很多框架,尤其輕量級的框架大多都有 Bootstrap 的影子。
下面我們通過對比幾個框架的柵格和按鈕來看一下類命名的策略。
Bootstrap
<div class="row">
<div class="col-md-8"></div>
<div class="col-md-4"></div>
</div>
<button class="btn btn-primary" type="submit">Button</button>
Semantic
<div class="ui grid">
<div class="ten wide column"></div>
<div class="six wide column"></div>
</div>
<button class="ui primary basic button">Primary</button>
Foundation
<div class="row">
<div class="small-3 columns"></div>
<div class="small-9 columns"></div>
</div>
<button type="button" class="primary button">Primary</button>
UIkit
<div class="uk-grid">
<div class="uk-width-1-2"></div>
<div class="uk-width-1-2"></div>
</div>
<button class="uk-button uk-button-primary" type="button">Primary</button>
Pure
<div class="pure-g">
<div class="pure-u-1-2"></div>
<div class="pure-u-1-2"></div>
</div>
<button class="pure-button pure-button-primary">A Primary Button</button>
通過上面的對比,大家應(yīng)該已經(jīng)發(fā)現(xiàn)了這些框架的命名策略的不同。不可否認(rèn),Bootstrap 的命名最經(jīng)典。
之前在網(wǎng)上看到有人討論關(guān)于框架的易用性,有人說 Bootstrap 的類名太長,然而通過上面幾個框架的對比,Bootstrap 的類并不繁瑣,而且用預(yù)處理器編寫框架時嵌套會比較靈活。
Semantic 的類名最簡潔,通過多個定語的修飾組成一句話,確實很有意思。但是過多的修飾類在編寫框架時會稍顯凌亂,有利有弊,因人而異吧。
Foundation 的柵格應(yīng)該是最豐富的,策略上類似 Bootstrap,只是對公共屬性進行了拆分,大家也可以看看其中的具體細(xì)節(jié)。
UIkit 和 Pure 的策略相同,都加了前綴以區(qū)分其它框架,但是很顯然類名過于冗長了。我在編寫框架時也這樣想過,但是最終放棄了這種方式。
CSS 預(yù)處理器早已不是什么新鮮事,但是真正能夠在工作中運用的人有多少呢?熟練使用預(yù)處理器特性的人又有多少呢?
我之前工作的時候也沒有用預(yù)處理器,因為不用,所以也意識不到預(yù)處理器的好處。主要是覺得麻煩,因為要使用編譯器編譯一下,還不如直接寫 CSS 方便。但是在項目維護的時候就意識到預(yù)處理器的好處。
后來在幾個項目中嘗試了預(yù)處理器,但是對于模塊化的寫法不太明確。預(yù)處理器作為工具,可以實現(xiàn)模塊化編寫 CSS,那么應(yīng)該如何劃分模塊?另外,預(yù)處理器有很多特性,但是大多數(shù)人剛開始只用到變量和嵌套,其它的特性幾乎很少用到。我相信在自己動手實現(xiàn)一個輕量級框架的過程中,我們可以對預(yù)處理器有一個全面的了解。
目前流行的預(yù)處理器有 Less,Sass,Stylus 三個,選擇哪個完全是看自己的習(xí)慣。我最開始因為 Bootstrap 了解的 Less,但是因為習(xí)慣選擇了 Sass,其次 Sass 的功能要更全面一些。
無論是工作還是自己寫項目,都要搭建一個項目環(huán)境,也就是安裝一系列的 npm 包。相比刀耕火種的開發(fā)方式,使用工具開發(fā)的前期準(zhǔn)備過程稍顯麻煩,然而一旦環(huán)境建好,后期的開發(fā)將會游刃有余。
Miligram 這個輕量級框架在 Github 上有很高人氣,但是說實話,用處并不大。不過這個框架的構(gòu)建方式非常值得學(xué)習(xí)。雖然 CSS 對于很多人來說很簡單,但是真要去寫一個框架,還是非常棘手,這時候就需要借鑒一些優(yōu)秀的框架。
編寫框架大致會用到的 npm 如下:
--autoprefixer
--node-sass
--npm-run-all
--rimraf
--onchange
其實最主要的就是一個 node-sass,其它的都是輔助 CSS 文件的生成修改,大家感興趣的話可以去 npm 官網(wǎng)搜索這些插件,了解具體用法,如有不懂可以給我留言,我就不啰嗦了。
終于到了本篇文章的重頭戲。
簡單介紹一下,我給自己編寫的框架取名 Snack,原意“快餐”,主要表達簡單之意。雖然是輕量級框架,但我并不想拿輕量級做為噱頭,畢竟體量輕意味著某些功能的缺失以及疏漏。這個框架的意義更多的是交流學(xué)習(xí),我試圖借鑒其它框架的優(yōu)秀之處,盡量簡化類名,以及嘗試探索一些更通用的組件。
大多數(shù)的輕量級框架只是 CSS 框架,不涉及 JS 部分,主要用于網(wǎng)頁的布局。我之所以打算自己編寫框架,是因為工作中重復(fù)的東西太多,通過框架可以很好的將這些零散組件整合到一起。另一方面,寫個小項目,學(xué)點新知識是一件趣事。
編寫框架是去年想做的事情,但因為時間原因,拖了很久。寫框架之初我曾陷入一個誤區(qū),我打算設(shè)計一些比較前衛(wèi)的樣式,立體的按鈕、浮動的面板等,比如下圖中的風(fēng)格。
https://dribbble.com/shots/524593-Soft-Interface-Black
但是在斷斷續(xù)續(xù)編寫框架的過程中,我逐漸找到了方向,上圖的樣式只是一種皮膚,編寫框架之初不應(yīng)該把重點放在這上面。當(dāng)然,好的 UI 設(shè)計也是框架成功的一部分。
編寫框架的第一步就是要確定框架應(yīng)該包含哪些模塊。因為是輕量級框架,所以模塊肯定沒有重量級框架那么全面,只有核心的一些組件。通過比較一些輕量級框架以及工作總結(jié),大致常用的模塊包括柵格、媒體、按鈕、排版、表單、表格、面板以及輔助工具。
在常用的這幾個組件中,需要重點關(guān)注的是柵格、表單及面板,媒體組件也很重要,但是自由發(fā)揮的空間不大,我直接用了 Bootstrap 的媒體組件。
首先是類命名的層次與結(jié)構(gòu)。類命名一直是我比較糾結(jié)的地方,剛開始工作的時候為了起一個見名知意又簡潔的類名總是抓耳撓腮。我在編寫框架時盡量避免與 Bootstrap 的類名重疊,但也不能完全避免。對比其他框架會發(fā)現(xiàn),這種情況不可避免的會出現(xiàn),畢竟類名會有一定的規(guī)律性以及層次性。在這一點上我比較喜歡 Bootstrap 的風(fēng)格。下面和 Bootstrap 的表單做一個對比。
Bootstrap 的表單結(jié)構(gòu)及類名
--div.form-horizontal
--div.form-group
--label.control-label
--input.form-control
Snack 的表單結(jié)構(gòu)及類名
--div.form-row
--div.form-item
--label.form-label
--input.form-field
這個表單結(jié)構(gòu)整體而言還算不錯,只是個別地方需要修改。有一些框架不給input
等元素起類名,而是給父元素一個類名,個人對這種做法表示疑問,不起類名會降低框架編寫及使用的靈活性。
第二個策略是組件的修飾,比如按鈕及面板都存在多個語境(顏色、大小等),在這一點上我編寫框架時做了一些簡化,風(fēng)格上有些 Semantic 的影子。
<button class="btn primary">primary</button>
<table class="table bordered striped">...</table>
<div class="boxes primary">...</div>
關(guān)于修飾類的策略是一個仁者見仁智者見智的問題,至于哪種方法更好,還需要在編寫框架的過程中摸索。
演示示例: https://nzbin.github.io/snack/#grid
任何框架必須建立在柵格的基礎(chǔ)上才能靈活布局。我在前面提到了 Bootstrap 的精華就是柵格系統(tǒng)。柵格系統(tǒng)的編寫需要使用預(yù)處理器的循環(huán)功能,否則就要做無謂的重復(fù)勞動了。我遇到過一些輕量級框架是用 Less 編寫的,其柵格系統(tǒng)就沒有用循環(huán),這樣的源碼稍顯唐突,可能是作者對 Less 的循環(huán)功能不熟,當(dāng)然 Less 本身的循環(huán)比較弱,用起來有些別扭。
關(guān)于預(yù)處理器的循環(huán),可以參照我之前翻譯的 《CSS 預(yù)處理器中的循環(huán)》,比較詳細(xì)地對比了三種流行預(yù)處理器的循環(huán)功能。簡單說一下,Less 沒有循環(huán),但可以用遞歸實現(xiàn),而 Sass 和 Stylus 有真循環(huán)。
我編寫的柵格系統(tǒng)也是默認(rèn) 12 列,但是后來發(fā)現(xiàn) 12 列的柵格缺少最常用的列寬(比如 10%、20%、30%等),比如下面 CodePen 展示的例子用 12 列柵格是無法完成的,所以我又添加了 10 列柵格,但仍然無法面面俱到,不過已經(jīng)很靈活了。
柵格的使用和 Bootstrap 是一樣的,除了 12 列柵格外,10 列柵格以及均分柵格都要添加.cols-
類
<!-- 默認(rèn) 12 列柵格,所以省略 cols-12 -->
<div class="row">
<div class="col-5"></div>
<div class="col-7"></div>
</div>
<!-- 10 列柵格 -->
<div class="row cols-10">
<div class="col-3"></div>
<div class="col-7"></div>
</div>
這個柵格并沒有響應(yīng)式,只有一個斷點,小屏手機上的話所有柵格都會單行顯示。一方面,這樣的設(shè)計符合大多數(shù)輕量級框架的初衷;另一方面,我打算再寫一個針對移動端的框架,畢竟 Web 端和移動端的風(fēng)格差距較大,按照業(yè)務(wù)需求分開會更好。不過最近我更改了源文件,為響應(yīng)式預(yù)留了擴展方式。
演示示例: https://nzbin.github.io/snack/#forms
在上面的命名策略中已經(jīng)展示了 Snack 表單的基本結(jié)構(gòu),基本表單除了結(jié)構(gòu)之外,樣式上并沒有太多可以討論的地方。在此說一下表單中checkbox
的結(jié)構(gòu)調(diào)整,先看一下 Bootstrap 的checkbox
結(jié)構(gòu)。
<!-- checkbox -->
<div class="checkbox">
<label>
<input type="checkbox" value=""> checkbox
</label>
</div>
<!-- checkbox-inline -->
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox1" value="option1"> checkbox
</label>
以上兩種結(jié)構(gòu)不能有偏差,稍有偏差樣式就會錯亂,靈活性較差。其次我在想兩種結(jié)構(gòu)能不能整合在一起,增強靈活性。想了很久,找到了方法,Snack 結(jié)構(gòu)如下:
<!-- checkbox -->
<div class="checkbox">
<label>
<input type="checkbox" value=""> checkbox
</label>
</div>
<!-- checkbox-inline -->
<div class="checkbox inline">
<label>
<input type="checkbox" value=""> checkbox
</label>
</div>
也可以將樣式直接加到label
標(biāo)簽上。另外,如果將input
移到label
標(biāo)簽外也是沒有問題的,如下:
<!-- checkbox -->
<div class="checkbox">
<input type="checkbox" id="checkbox1" value="">
<label for="checkbox1">checkbox</label>
</div>
<!-- checkbox-inline -->
<div class="checkbox inline">
<input type="checkbox" id="inlineCheckbox1" value="">
<label for="inlineCheckbox1">checkbox</label>
</div>
這種結(jié)構(gòu)有一個好處,就是可以自定義input
樣式,詳見下面的 CodePen 的scss
文件。radio
的設(shè)置和checkBox
是一樣的。
輔助類是一系列類的組合,比如字號大小、顏色值、padding、margin 以及左右浮動等。在一些 Bootstrap 搭建的后臺管理系統(tǒng)中尤為常見,這樣布局起來就會比較靈活。以下是一個邊框的輔助類。
.border-left-right {
border-left: 1px solid #eee;
border-right: 1px solid #eee;
}
.border-top-bottom {
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
}
.border-left {
border-left: 1px solid #eee;
}
.border-right {
border-right: 1px solid #eee;
}
.border-top {
border-top: 1px solid #eee;
}
.border-bottom {
border-bottom: 1px solid #eee;
}
關(guān)于助類的更多內(nèi)容可以搜索閱讀這篇文章《如何編寫通用的 Helper Class》
演示示例: https://nzbin.github.io/snack/#boxes
盒組件是我整個框架中比較滿意的一個模塊。之所以要做這個組件主要是覺得 Bootstrap 的 list 組件和 panel 組件可以整合到一起。當(dāng)然,這樣的做法有利有弊。盒組件在后臺管理系統(tǒng)的布局中表現(xiàn)的尤為突出。
其命名也是多種多樣,比如 panel、widget、portlet、ibox、card等,每個后臺管理系統(tǒng)框架都會對這個組件進行深度開發(fā),可見其在布局上的重要性。給一個組件起一個合適的類名也很關(guān)鍵,想了很久,最后用了box
的類名,當(dāng)然一般情況下盡量不要用box
,因為這個類名比較寬泛。下面的 CodePen 模擬了 Bootstrap 的 list 及 panel 組件。
給框架添加主題是一件有趣的事情。Snack 的默認(rèn)主題是白色,因為喜歡黑色,最后添加了暗夜主題,編寫主題只需改變組件的顏色。演示文檔 的頁面用了暗夜主題,點擊上方的紅色按鈕可以切換主題。
如果大家問我那個框架更好,我會毫不猶豫的選擇 Bootstrap。在工作中可以根據(jù)需求的難易進行框架選擇,如果業(yè)務(wù)比較重,最好根據(jù) Bootstrap 進行二次開發(fā);反之,可以選擇一些輕量級框架,最好還是根據(jù)自己的需求造輪子,如果大家愿意選擇或是借鑒我的框架,那會是我的榮幸。
Github: https://github.com/nzbin/snack
Docs: https://nzbin.github.io/snack
eb前端技術(shù)由html、css和 javascript三大部分構(gòu)成,是一個龐大而復(fù)雜的技術(shù)體系,其復(fù)雜程度不低于任何一門后端語言。而我們在學(xué)習(xí)它的時候往往是先從某一個點切入,然后不斷地接觸和學(xué)習(xí)新的知識點,因此對于初學(xué)者很難理清楚整個體系的脈絡(luò)結(jié)構(gòu)。本文將對Web前端知識體系進行簡單的梳理,對應(yīng)的每個知識點點到為止,不作詳細(xì)介紹。目的是幫助大家審查自己的知識結(jié)構(gòu)是否完善,如有遺漏或不正確的地方,希望共勉。
HTML 篇
1、BOM
BOM 是 Browser Object Model
的縮寫,即瀏覽器對象模型,當(dāng)一個瀏覽器頁面初始化時,會在內(nèi)存創(chuàng)建一個全局的對象,用以描述當(dāng)前窗口的屬性和狀態(tài),這個全局對象被稱為瀏覽器對象模型,即BOM。BOM的核心對象就是window,window
對象也是BOM的頂級對象,其中包含了瀏覽器的 6個核心模塊:
document -
即文檔對象,渲染引擎在解析HTML代碼時,會為每一個元素生成對應(yīng)的DOM對象,由于元素之間有層級關(guān)系,因此整個HTML代碼解析完以后,會生成一個由不同節(jié)點組成的樹形結(jié)構(gòu),俗稱DOM樹,document
用于描述DOM樹的狀態(tài)和屬性,并提供了很多操作DOM的API。
frames - HTML 子框架,即在瀏覽器里嵌入另一個窗口,父框架和子框架擁有獨立的作用域和上下文。
history - 以棧(FIFO)的形式保存著頁面被訪問的歷史記錄,頁面前進即入棧,頁面返回即出棧。
location - 提供了當(dāng)前窗口中加載的文檔相關(guān)信息以及一些導(dǎo)航功能。
navigator - 用來描述瀏覽器本身,包括瀏覽器的名稱、版本、語言、系統(tǒng)平臺、用戶特性字符串等信息。
screen - 提供了瀏覽器顯示屏幕的相關(guān)屬性,比如顯示屏幕的寬度和高度,可用寬度和高度。
2、DOM 系統(tǒng)
DOM 是 Document Object Model 的縮寫,即 文檔對象模型,是所有瀏覽器公共遵守的標(biāo)準(zhǔn),DOM
將HTML和XML文檔映射成一個由不同節(jié)點組成的樹型結(jié)構(gòu),俗稱DOM樹。其核心對象是document,用于描述DOM樹的狀態(tài)和屬性,并提供對應(yīng)的DOM操作API。隨著歷史的發(fā)展,DOM
被劃分為1級、2級、3級,共3個級別:
1級DOM - 在1998年10月份成為W3C的提議,由DOM核心與DOM
HTML兩個模塊組成。DOM核心能映射以XML為基礎(chǔ)的文檔結(jié)構(gòu),允許獲取和操作文檔的任意部分。DOM
HTML通過添加HTML專用的對象與函數(shù)對DOM核心進行了擴展。
2級DOM - 鑒于1級DOM僅以映射文檔結(jié)構(gòu)為目標(biāo),DOM
2級面向更為寬廣。通過對原有DOM的擴展,2級DOM通過對象接口增加了對鼠標(biāo)和用戶界面事件(DHTML長期支持鼠標(biāo)與用戶界面事件)、范圍、遍歷(重復(fù)執(zhí)行DOM文檔)和層疊樣式表(CSS)的支持。同時也對DOM
1的核心進行了擴展,從而可支持XML命名空間。
3級DOM -
通過引入統(tǒng)一方式載入和保存文檔和文檔驗證方法對DOM進行進一步擴展,DOM3包含一個名為“DOM載入與保存”的新模塊,DOM核心擴展后可支持XML1.0的所有內(nèi)容,包括XML
Infoset、 XPath、和XML Base。
瀏覽器對不同級別DOM的支持情況如下所示:
從圖中可以看出,移動端常用的 webkit 內(nèi)核瀏覽器目前只支持DOM2,而不支持DOM3 。
新手福利獲取方式:
1.在你手機的右上角有【關(guān)注】選項,或點擊我的頭像,點擊關(guān)注?。P(guān)注我)
2.關(guān)注后,手機客戶端點擊我的主頁面,右上角有私信,請私信發(fā)我:html
其實作為一個開發(fā)者,有一個學(xué)習(xí)的氛圍跟一個交流圈子特別重要這里請私信我“html”不管你是小白還是大牛歡迎入住大家一起交流成長。小編會在里面不定期分享干貨源碼,包括我精心整理的一份零基礎(chǔ)教程。歡迎各位感興趣的的小伙伴。
學(xué)習(xí)思路:
3、事件系統(tǒng)
事件是用戶與頁面交互的基礎(chǔ),到目前為止,DOM事件從PC端的 鼠標(biāo)事件(mouse) 發(fā)展到了 移動端的 觸摸事件(touch) 和
手勢事件(guesture),touch事件描述了手指在屏幕操作的每一個細(xì)節(jié),guesture 則是描述多手指操作時更為復(fù)雜的情況,總結(jié)如下:
第一根手指放下,觸發(fā) touchstart,除此之外什么都不會發(fā)生
手指滑動時,觸發(fā)touchmove
第二根手指放下,觸發(fā) gesturestart
觸發(fā)第二根手指的 touchstart
立即觸發(fā) gesturechange
任意手指移動,持續(xù)觸發(fā) gesturechange
第二根手指彈起時,觸發(fā) gestureend,以后將不會再觸發(fā) gesturechange
觸發(fā)第二根手指的 touchend
觸發(fā)touchstart (多根手指在屏幕上,提起一根,會刷新一次全局touch) _ ___
彈起第一根手指,觸發(fā) touchend
更多關(guān)于手勢事件的介紹請參考:
gesture事件處理復(fù)雜手勢
DOM2.0 模型將事件處理流程分為三個階段,即 事件捕獲階段 、 事件處理階段 、 事件冒泡階段, 如圖所示:
事件捕獲 :當(dāng)用戶觸發(fā)點擊事件后,頂層對象document 就會發(fā)出一個事件流,從最外層的DOM節(jié)點向目標(biāo)元素節(jié)點傳遞,最終到達目標(biāo)元素。
事件處理 :當(dāng)?shù)竭_目標(biāo)元素之后,執(zhí)行目標(biāo)元素綁定的處理函數(shù)。如果沒有綁定監(jiān)聽函數(shù),則不做任何處理。
事件冒泡 :事件流從目標(biāo)元素開始,向最外層DOM節(jié)點傳遞,途中如果有節(jié)點綁定了事件處理函數(shù),這些函數(shù)就會被執(zhí)行。
利用事件冒泡原理可以實現(xiàn) 事件委托
,所謂事件委托,就是在父元素上添加事件監(jiān)聽器,用以監(jiān)聽和處理子元素的事件,避免重復(fù)為子元素綁定相同的事件。當(dāng)目標(biāo)元素的事件被觸發(fā)以后,這個事件就從目標(biāo)元素開始,向最外層元素傳遞,最終冒泡到父元素上,父元素再通過event.target
獲取到這個目標(biāo)元素,這樣做的好處是,父元素只需綁定一個事件監(jiān)聽,就可以對所有子元素的事件進行處理了,從而減少了不必要的事件綁定,對頁面性能有一定的提升。
4、HTML解析過程
瀏覽器加載 html 文件以后,渲染引擎會從上往下,一步步來解析HTML標(biāo)簽,大致過程如下:
用戶輸入網(wǎng)址,瀏覽器向服務(wù)器發(fā)出請求,服務(wù)器返回html文件;
渲染引擎開始解析 html 標(biāo)簽,并將標(biāo)簽轉(zhuǎn)化為DOM節(jié)點,生成 DOM樹;
如果head 標(biāo)簽中引用了外部css文件,則發(fā)出css文件請求,服務(wù)器返回該文件,該過程會阻塞后面的解析;
如果引用了外部 js 文件,則發(fā)出 js 文件請求,服務(wù)器返回后立即執(zhí)行該腳本,這個過程也會阻塞html的解析;
引擎開始解析 body 里面的內(nèi)容,如果標(biāo)簽里引用了css 樣式,就需要解析剛才下載好的css文件,然后用css來設(shè)置標(biāo)簽的樣式屬性,并生成渲染樹;
如果 body 中的 img 標(biāo)簽引用了圖片資源,則立即向服務(wù)器發(fā)出請求,此時引擎不會等待圖片下載完畢,而是繼續(xù)解析后面的標(biāo)簽;
服務(wù)器返回圖片文件,由于圖片需要占用一定的空間,會影響到后面元素的排版,因此引擎需要重新渲染這部分內(nèi)容;
如果此時 js 腳本中運行了 style.display="none",布局被改變,引擎也需要重新渲染這部分代碼;
直到 html 結(jié)束標(biāo)簽為止,頁面解析完畢。
5、重繪 和 回流
當(dāng)渲染樹中的一部分(或全部)因為元素的規(guī)模尺寸,布局,隱藏等改變而需要重新構(gòu)建。這就稱為回流。比如上面的img文件加載完成后就會引起回流,每個頁面至少需要一次回流,就是在頁面第一次加載的時候。
當(dāng)渲染樹中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風(fēng)格,而不會影響布局的,比如 background-color。則就叫稱為重繪。
從上面可以看出,回流必將引起重繪,而重繪不一定會引起回流。會引起重繪和回流的操作如下:
添加、刪除元素(回流+重繪)
隱藏元素,display:none(回流+重繪),visibility:hidden(只重繪,不回流)
移動元素,比如改變top,left的值,或者移動元素到另外一個父元素中。(重繪+回流)
對style的操作(對不同的屬性操作,影響不一樣)
還有一種是用戶的操作,比如改變?yōu)g覽器大小,改變?yōu)g覽器的字體大小等(回流+重繪)
另外,transform
操作不會引起重繪和回流,是一種高效率的渲染。這是因為transform屬于合成屬性,對合成屬性進行transition/animation
動畫時將會創(chuàng)建一個合成層,這使得動畫元素在一個獨立的層中進行渲染,當(dāng)元素的內(nèi)容沒有發(fā)生改變,就沒必要進行重繪,瀏覽器會通過重新復(fù)合來創(chuàng)建動畫幀。
6、本地存儲
本地存儲最原始的方式就是 cookie,cookie 是存放在本地瀏覽器的一段文本,數(shù)據(jù)以鍵值對的形式保存,可以設(shè)置過期時間。 但是 cookie
不適合大量數(shù)據(jù)的存儲,因為每請求一次頁面,cookie 都會發(fā)送給服務(wù)器,這使得 cookie
速度很慢而且效率也不高。因此cookie的大小被限制為4k左右(不同瀏覽器可能不同,分HOST),如下所示:
Firefox和Safari允許cookie多達4097個字節(jié),包括名(name)、值(value) 和 等號。
Opera允許cookie多達4096個字節(jié),包括:名(name)、值(value) 和 等號。
Internet Explorer允許cookie多達4095個字節(jié),包括:名(name)、值(value) 和 等號。
在所有瀏覽器中,任何cookie大小超過限制都被忽略,且永遠(yuǎn)不會被設(shè)置。
html5 提供了兩種在客戶端存儲數(shù)據(jù)的新方法:localStorage 和 sessionStorage, 它們都是以key/value
的形式來存儲數(shù)據(jù),前者是永久存儲,后者的存儲期限僅限于瀏覽器會話(session),即當(dāng)瀏覽器窗口關(guān)閉后,sessionStorage中的數(shù)據(jù)被清除。
localStorage的存儲空間大約5M左右(不同瀏覽器可能不同,分
HOST),這個相當(dāng)于一個5M大小的前端數(shù)據(jù)庫,相比于cookie,可以節(jié)約帶寬,但localStorage在瀏覽器隱私模式下是不可讀取的,當(dāng)存儲數(shù)據(jù)超過了localStorage
的存儲空間后會拋出異常。
此外,H5還提供了逆天的websql和
indexedDB,允許前端以關(guān)系型數(shù)據(jù)庫的方式來存儲本地數(shù)據(jù),相對來說,這個功能目前應(yīng)用的場景比較少,此處不作介紹。
7、瀏覽器緩存機制
瀏覽器緩存機制是指通過 HTTP 協(xié)議頭里的 Cache-Control (或 Expires) 和 Last-Modified (或 Etag)
等字段來控制文件緩存的機制。
Cache-Control 用于控制文件在本地緩存有效時長。最常見的,比如服務(wù)器回包:Cache-Control:max-age=600
表示文件在本地應(yīng)該緩存,且有效時長是600秒 (從發(fā)出請求算起)。在接下來600秒內(nèi),如果有請求這個資源,瀏覽器不會發(fā)出 HTTP
請求,而是直接使用本地緩存的文件。
Last-Modified 是標(biāo)識文件在服務(wù)器上的最新更新時間。下次請求時,如果文件緩存過期,瀏覽器通過 If-Modified-Since
字段帶上這個時間,發(fā)送給服務(wù)器,由服務(wù)器比較時間戳來判斷文件是否有修改。如果沒有修改,服務(wù)器返回304告訴瀏覽器繼續(xù)使用緩存;如果有修改,則返回200,同時返回最新的文件。
Cache-Control 通常與 Last-Modified 一起使用。一個用于控制緩存有效時間,一個在緩存失效后,向服務(wù)查詢是否有更新。
Cache-Control 還有一個同功能的字段:Expires。Expires 的值一個絕對的時間點,如:Expires: Thu, 10 Nov
2015 08:45:11 GMT,表示在這個時間點之前,緩存都是有效的。
Expires 是 HTTP1.0 標(biāo)準(zhǔn)中的字段,Cache-Control 是 HTTP1.1
標(biāo)準(zhǔn)中新加的字段,功能一樣,都是控制緩存的有效時間。當(dāng)這兩個字段同時出現(xiàn)時,Cache-Control 是高優(yōu)化級的。
Etag 也是和 Last-Modified 一樣,對文件進行標(biāo)識的字段。不同的是,Etag
的取值是一個對文件進行標(biāo)識的特征字串。在向服務(wù)器查詢文件是否有更新時,瀏覽器通過 If-None-Match
字段把特征字串發(fā)送給服務(wù)器,由服務(wù)器和文件最新特征字串進行匹配,來判斷文件是否有更新。沒有更新回包304,有更新回包200。Etag 和
Last-Modified 可根據(jù)需求使用一個或兩個同時使用。兩個同時使用時,只要滿足基中一個條件,就認(rèn)為文件沒有更新。
另外有兩種特殊的情況:
手動刷新頁面(F5),瀏覽器會直接認(rèn)為緩存已經(jīng)過期(可能緩存還沒有過期),在請求中加上字段:Cache-Control:max-age=0,發(fā)包向服務(wù)器查詢是否有文件是否有更新。
強制刷新頁面(Ctrl+F5),瀏覽器會直接忽略本地的緩存(有緩存也會認(rèn)為本地沒有緩存),在請求中加上字段:Cache-Control:no-cache
(或 Pragma:no-cache),發(fā)包向服務(wù)重新拉取文件。
8、History
用戶訪問網(wǎng)頁的歷史記錄通常會被保存在一個類似于棧的對象中,即history對象,點擊返回就出棧,跳下一頁就入棧。 它提供了以下方法來操作頁面的前進和后退:
window.history.back( ) 返回到上一個頁面
window.history.forward( ) 進入到下一個頁面
window.history.go( [delta] ) 跳轉(zhuǎn)到指定頁面
HTML5 對History Api 進行了增強,新增了兩個Api 和一個事件,分別是pushState、replaceState 和
onpopstate:
pushState是往history對象里添加一個新的歷史記錄,即壓棧。
replaceState 是替換history對象中的當(dāng)前歷史記錄。
當(dāng)點擊瀏覽器后退按鈕或 js調(diào)用history.back 都會觸發(fā) onpopstate 事件。
與其類似的還有一個事件:onhashchange,onhashchange是老API,瀏覽器支持度高,本來是用來監(jiān)聽hash變化的,但可以被利用來做客戶端前進和后退事件的監(jiān)聽,而onpopstate是專門用來監(jiān)聽瀏覽器前進后退的,不僅可以支持hash,非hash的同源
url 也支持。
9、HTML5離線緩存
HTML5離線緩存又叫Application
Cache,是從瀏覽器的緩存中分出來的一塊緩存區(qū),如果要在這個緩存中保存數(shù)據(jù),可以使用一個描述文件(manifest file),列出要下載和緩存的資源。
manifest 文件是簡單的文本文件,它告知瀏覽器被緩存的內(nèi)容(以及不緩存的內(nèi)容)。manifest 文件可分為三個部分:
- CACHE MANIFEST - 在此標(biāo)題下列出的文件將在首次下載后進行緩存
- NETWORK - 在此標(biāo)題下列出的文件需要與服務(wù)器的連接,且不會被緩存
- FALLBACK - 在此標(biāo)題下列出的文件規(guī)定當(dāng)頁面無法訪問時的回退頁面(比如 404 頁面)
離線緩存為應(yīng)用帶來三個優(yōu)勢:
離線瀏覽 - 用戶可在應(yīng)用離線時使用它們
速度 - 已緩存資源加載得更快
減少服務(wù)器負(fù)載 - 瀏覽器將只從服務(wù)器下載更新過或更改過的資源。
10、Web語義化 和 SEO
Web語義化是指使用語義恰當(dāng)?shù)臉?biāo)簽,使頁面有良好的結(jié)構(gòu),頁面元素有含義,能夠讓人和搜索引擎都容易理解。
SEO是指在了解搜索引擎自然排名機制的基礎(chǔ)之上,對網(wǎng)站進行內(nèi)部及外部的調(diào)整優(yōu)化,改進網(wǎng)站在搜索引擎中關(guān)鍵詞的自然排名,獲得更多的展現(xiàn)量,吸引更多目標(biāo)客戶點擊訪問網(wǎng)站,從而達到互聯(lián)網(wǎng)營銷及品牌建設(shè)的目標(biāo)。
搜索引擎通過爬蟲技術(shù)獲取的頁面就是由一堆 html 標(biāo)簽組成的代碼,人可以通過可視化的方式來判斷頁面上哪些內(nèi)容是重點,而機器做不到。
但搜索引擎會根據(jù)標(biāo)簽的含義來判斷內(nèi)容的權(quán)重,因此,在合適的位置使用恰當(dāng)?shù)臉?biāo)簽,使整個頁面的語義明確,結(jié)構(gòu)清晰,搜索引擎才能正確識別頁面中的重要內(nèi)容,并予以較高的權(quán)值。比如h1~h6這幾個標(biāo)簽在SEO中的權(quán)值非常高,用它們作頁面的標(biāo)題就是一個簡單的SEO優(yōu)化。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。