內(nèi)容是《Web前端開發(fā)之Javascript視頻》的課件,請(qǐng)配合大師哥《Javascript》視頻課程學(xué)習(xí)。
BOM(Browser Object Model)瀏覽器對(duì)象模型;其提供了獨(dú)立于內(nèi)容而與瀏覽器窗口進(jìn)行交互的對(duì)象;
沒有BOM標(biāo)準(zhǔn):不同的瀏覽器按照各自的想法實(shí)現(xiàn)及擴(kuò)展BOM,于是,它們之間共有的對(duì)象成為了事實(shí)上的標(biāo)準(zhǔn);近年來,W3C為了把瀏覽器中Javascript最基本的部分標(biāo)準(zhǔn)化,已經(jīng)將BOM的主要方面納入了HTML5的規(guī)范中。
BOM由一系列相關(guān)的對(duì)象構(gòu)成;DOM中各對(duì)象之間是層次關(guān)系;window對(duì)象是整個(gè)BOM的核心,所有對(duì)象和集合都以某種方式回接到window對(duì)象;
window對(duì)象
window對(duì)象:
其是BOM的核心對(duì)象,也是頂級(jí)對(duì)象,表示瀏覽器的一個(gè)實(shí)例;
瀏覽器窗口對(duì)文檔提供一個(gè)顯示的容器,是每一個(gè)加載文檔的父對(duì)象;window對(duì)象表示整個(gè)瀏覽器窗口,但不表示其中所包含的內(nèi)容;可以用于移動(dòng)或調(diào)整瀏覽器的大小,或者產(chǎn)生其他的影響;
全局作用域:
在瀏覽器中,window對(duì)象具有雙重角色,即是通過Javascript訪問瀏覽器的一個(gè)接口,又是ES中的Global對(duì)象;
既然window是Global對(duì)象,所以window對(duì)象是所有其他對(duì)象的頂級(jí)對(duì)象,在網(wǎng)頁(yè)中定義的任何對(duì)象、變量和函數(shù),window對(duì)象都有權(quán)訪問;即所有在全局作用域中聲明的變量、函數(shù)都會(huì)變成window對(duì)象的屬性和方法;因此window前綴可以省略;
var age = 18;
function sayAge(){
alert(this.age);
}
alert(window.age);
sayAge();
window.sayAge();
定義全局變量與在window對(duì)象上直接定義屬性還是有一點(diǎn)差別:全局變量不能通過delete操作符刪除,而直接在window對(duì)象上的定義的屬性可以,如:
var age = 18;
window.color = "green";
console.log(delete window.age); // false
console.log(delete window.color); // true
console.log(window.age); // 18
console.log(window.color); // undefined
age屬性的特性中的[[Configurable]],值為false,因此其不能通過delete刪除;
console.log(Object.getOwnPropertyDescriptor(window,"age"));
console.log(Object.getOwnPropertyDescriptor(window,"color"));
嘗試訪問未聲明的變量會(huì)拋出錯(cuò)誤,但通過查詢window對(duì)象,可以知道某個(gè)可能未聲明的變量是否存在,如:
var age = oldAge; // 拋出錯(cuò)誤
var age = window.oldAge; // 不會(huì)拋出錯(cuò)誤,因?yàn)檫@是一次屬性查詢
文檔元素:
如果在HTML文檔中用id屬性來元素命名,并且如果window對(duì)象沒有此名字的屬性,window對(duì)象會(huì)賦予一個(gè)屬性,它的名字是id屬性的值,而它們的值指向表示文檔元素的HTMLElement對(duì)象,這稱為全局變量的隱式應(yīng)用;
在實(shí)際場(chǎng)景中,很少使用這種方式來訪問HTML元素,它是Web瀏覽器發(fā)展過程中遺留的一個(gè)現(xiàn)象,是現(xiàn)代瀏覽器向后兼容性的考慮,如:
<button id="okay">按鈕</button>
<input id="myinput" value="input" />
<div id="mydiv">mydiv</div>
<script>
var ui = ["okay","myinput"];
ui.forEach(function(id){
ui[id] = document.getElementById(id);
});
console.log(ui.okay);
console.log(ui.myinput);
// 定義一個(gè)更簡(jiǎn)單的方法
var $ = function(id){
return document.getElementById(id);
};
$("mydiv").innerHTML = "零點(diǎn)網(wǎng)絡(luò)";
console.log($("mydiv"));
</script>
窗口位置:
獲取窗口(視口)的位置(即相對(duì)于屏幕左邊和上邊的位置);各瀏覽器都實(shí)現(xiàn)了screenLeft和screenTop屬性表示窗口的位置;但是之前的firefox并不支持,現(xiàn)代firefox返回-8;只有IE是文檔區(qū)相對(duì)于主顯示器屏幕的位置;
Firefox使用了screenX和screenY屬性獲取窗口位置信息;各瀏覽器也實(shí)現(xiàn)了這兩個(gè)屬性,但并不統(tǒng)一:
chrome與Opera實(shí)現(xiàn)了screenLeft、screenTop與screenX、screenY的統(tǒng)一;且最大化時(shí),值為0;Firefox與IE實(shí)現(xiàn)了統(tǒng)一,但最大化時(shí),值為-8;且Firefox中的screenLeft、screenTop與這兩個(gè)屬性實(shí)現(xiàn)了對(duì)應(yīng);但I(xiàn)E的screenLeft、screenTop與這兩個(gè)屬性并不對(duì)應(yīng);screenLeft、screenTop是文檔區(qū)域的左上角的坐標(biāo),screenX、screenY是窗口的左上角坐標(biāo);
console.log(window.screenLeft);
console.log(window.screenTop);
console.log(window.screenX);
console.log(window.screenY);
// 為了兼容老的Firefox
var leftPos = (typeof window.screenLeft == "number") ? window.screenLeft : window.screenX;
var topPos = (typeof window.screenTop == "number") ? window.screenTop : window.screenY;
console.log("leftPos:",leftPos, ",topPos:",topPos);
pageXOffset及pageXOffset:設(shè)置或返回當(dāng)前頁(yè)面相對(duì)于可視區(qū)域的左及上的位置;但貌似只有Chrome支持,同時(shí),如果是設(shè)置的話,沒有效果;
注:目前,無法在跨瀏覽器的條件下取得窗口左邊和上邊的精確坐標(biāo)值;如果在框架中使用,除了IE,其他瀏覽器的值都與以上統(tǒng)一;
移動(dòng)瀏覽器窗口:
window.moveTo(50,100);
window.moveBy(100,200);
window.moveBy(-50,0);
注:一般很少用;這兩個(gè)方法有可能會(huì)被瀏覽器禁用;這兩個(gè)方法都不適用框架,只能對(duì)最外層的window對(duì)象使用;
窗口大?。?/strong>
如果要獲取瀏覽器窗口大小信息,各瀏覽器并不統(tǒng)一;但各瀏覽器都已實(shí)現(xiàn)了以下四個(gè)方法,但返回值并不一定相同:
console.log(window.innerWidth);
console.log(window.innerHeight);
console.log(window.outerWidth);
console.log(window.outerHeight);
在各瀏覽器的實(shí)現(xiàn)中,可以通過使用DOM提供的頁(yè)面視口的相關(guān)信息:
document.documentElement.clientWidth和document.documentElement.clientHeight中保存了頁(yè)面視口的信息;其返回值與innerWidth和innerHeight一致;
在低版本的IE中,必須通過document.body.clientWidth和document.body.clientHeight屬性獲取視口信息(實(shí)際上是實(shí)際內(nèi)容的尺寸,但不包括border值),但不標(biāo)準(zhǔn);
同時(shí),document.body.offsetWidth和document.body.offsetHeight也能獲取視口相關(guān)信息,同clientWidth和clientHeight類似,只不過其包括border的寬度;
跨瀏覽器取得頁(yè)面視口的大?。?/p>
var pageWidth = window.innerWidth,
pageHeight = window.innerHeight;
if(typeof pageWidth != "number"){
// 判斷頁(yè)面是否處于標(biāo)準(zhǔn)模式
if(document.compatMode == "CSS1Compat"){
pageWidth = document.documentElement.clientWidth;
pageHeight = document.documentElement.clientHeight;
}else{
pageWidth = document.body.clientWidth;
pageHeight = document.body.clientHeight;
}
}
console.log(pageWidth);
console.log(pageHeight);
調(diào)整瀏覽器窗口的大?。?/strong>
注:一般很少用;也有可能被禁用,同移動(dòng)窗口類似
window.resizeTo(400,300);
window.resizeBy(200,100);
滾動(dòng)窗口(如果有滾動(dòng)條):
對(duì)話框:
window對(duì)象通過alert()、confirm()和prompt()三個(gè)方法可以調(diào)用系統(tǒng)對(duì)話框向用戶顯示消息;
系統(tǒng)對(duì)話框與在瀏覽器中顯示的網(wǎng)頁(yè)沒有關(guān)系,也不包括HTML;它們的外觀由操作系統(tǒng)或?yàn)g覽器設(shè)置決定的,而不是由CSS決定的;此外,通過這幾個(gè)方法打開的對(duì)話框都是同步和模態(tài)的,也就是說,顯示這些對(duì)話框的時(shí)候代碼會(huì)停止執(zhí)行,而關(guān)掉這些對(duì)話框后代碼又會(huì)恢復(fù)執(zhí)行;
一般來說,不會(huì)使用,都是自己實(shí)現(xiàn)一個(gè)效果;
警告對(duì)話框window.alert(string):
警告對(duì)話框是一個(gè)帶感嘆圖標(biāo)的小窗口,通常用來輸出一些簡(jiǎn)單的文本信息;該方法接受一個(gè)字符串并將其顯示給用戶,并包含一個(gè)OK或確定的按鈕等待用戶關(guān)閉對(duì)話框;
通過alert()生成的警告對(duì)話框,用戶是無法控制的,比如,顯示的消息內(nèi)容,用戶只能看完消息后關(guān)閉對(duì)話框;
確認(rèn)對(duì)話框window.confirm(string):
確認(rèn)對(duì)話框也是向用戶顯示消息的對(duì)話框,但與警告對(duì)話框不同的是,其具有OK與Cancle按鈕,根據(jù)用戶的選擇,該方法返回不同的值(true或false);程序可以根據(jù)不同的值予以不同的響應(yīng),實(shí)現(xiàn)互動(dòng)的效果;通常放在網(wǎng)頁(yè)中,對(duì)用戶進(jìn)行詢問并根據(jù)其選擇而做不同的控制;
if(window.confirm("確定刪除嗎?")){
alert("已經(jīng)刪除");
}else{
alert("未刪除");
}
輸入對(duì)話框window.prompt():
用于提示用戶輸入的對(duì)話框;
語法: window.prompt(提示信息,默認(rèn)值);// 要顯示的文本提示和文本輸入域的默認(rèn)值,該默認(rèn)值可以是一個(gè)空字符串;
prompt("請(qǐng)輸入你的名字","王唯");
如果用戶單擊了OK,則prompt()返回文本域中的值,如果單擊了Cancel或使用其他方式關(guān)閉對(duì)話框,則該方法返回null,如:
var result = prompt("請(qǐng)輸入密碼:","");
if(result == "8888"){
alert("登錄成功");
}
var result = prompt("請(qǐng)輸入你的名字","王唯");
if(result !== null){
document.write("歡迎你:" + result);
}else{
alert("你沒有輸入任何內(nèi)容");
}
綜上所述,這些系統(tǒng)對(duì)話框很適合向用戶顯示消息并由用戶作出決定;由于不涉及HTML、CSS或JS,因此它們是增強(qiáng)Web應(yīng)用程序的一種便捷方式;
do{
var name = prompt("輸入你的名字:");
var correct = confirm("你輸入的是:" + name + ".\n" + "你可以單擊確定或取消");
}while(!correct)
alert("你好," + name);
在彈出對(duì)話框時(shí),還有一個(gè)特性:如果當(dāng)前腳本在執(zhí)行過程中會(huì)打開兩個(gè)或多個(gè)對(duì)話框,那么從第二個(gè)對(duì)話框開始,每個(gè)對(duì)話框中都會(huì)顯示一個(gè)復(fù)選框,以便用戶阻止后續(xù)的對(duì)話框顯示,除非用戶刷新頁(yè)面;后續(xù)被阻止的對(duì)話框包括警告框、確認(rèn)框和顯示輸入框;
該特性最初是由Chrome實(shí)現(xiàn)了,后續(xù)其他瀏覽器也實(shí)現(xiàn)該特性;其工作原理就是使用了一個(gè)叫對(duì)話框計(jì)數(shù)器,可以跟蹤對(duì)話框;但是瀏覽器沒有就對(duì)話框是否顯示向開發(fā)人員提供任何信息;
在實(shí)際的場(chǎng)景中,這三個(gè)方法是很少用的,因?yàn)樗鼈冿@示的文本是純文本,不是HTML格式的文本,只能使用空格、換行符和各種標(biāo)點(diǎn)符號(hào),所以往往滿足不了頁(yè)面設(shè)計(jì)需要,并且有可能會(huì)破壞用戶的瀏覽體驗(yàn);常見的就是使用alert()方法進(jìn)行調(diào)試,用來查看某個(gè)變量的輸出結(jié)果;
這三個(gè)方法都會(huì)產(chǎn)生阻塞,也就是說,在用戶關(guān)掉它們之前,它們不會(huì)返回,后面的代碼不會(huì)執(zhí)行;如果當(dāng)前載入文檔,也會(huì)停止載入,直到用戶要求的輸入進(jìn)行響應(yīng)為止;
可以自定義一個(gè)對(duì)話框:
<style>
#alert_box{
position: absolute; display: none; width: 400px; height:300px; border-radius: 3px;
box-shadow: 0 0 5px rgba(0, 0, 0, .5);
}
#alert_box h1{
margin:0; padding: 0; font-size: 1.5em; line-height: 60px;
height: 60px;
text-align: center; background-color: rgba(255,255,255,1);
}
#alert_box div{
height: 240px;
padding: 1em; line-height: 1.8em; background-color: rgba(255,255,255,.8);
}
#alert_box span{
position: absolute; width: 30px; height: 30px;
top:-15px; right:-15px; background-color:#000; border-radius: 50%;;
}
</style>
<script>
window.alert = function(title,info){
var box = document.createElement("div");
box.id = "alert_box";
box.style.left = ((window.innerWidth - 400) / 2) + "px";
box.style.top = ((window.innerHeight - 300) / 2) + "px";
var h1 = document.createElement("h1");
h1.innerText = title;
box.appendChild(h1);
var innerBox = document.createElement("div");
innerBox.innerHTML = info;
box.appendChild(innerBox);
var closeSpan = document.createElement('span');
box.appendChild(closeSpan);
closeSpan.addEventListener("click",function(e){
document.body.removeChild(box);
},false);
box.style.display = "block";
document.body.appendChild(box);
};
window.alert("零點(diǎn)網(wǎng)絡(luò)","哪些是這樣的?");
</script>
Javascript還有兩個(gè)工具性的對(duì)話框,即查找window.find()和打印window.print();
這兩個(gè)對(duì)話框都是異步顯示的,能夠?qū)⒖刂茩?quán)立即交還給腳本;其與瀏覽器菜單中的查找和打印命令是相同的;
這兩個(gè)方法同樣不會(huì)就用戶對(duì)對(duì)話框中的操作給出任何信息,因此它們的用處有限;另外,既然這兩個(gè)對(duì)話框是異步顯示的,對(duì)話框計(jì)數(shù)器就不會(huì)將它們計(jì)算在內(nèi),所以它們也不會(huì)受用戶禁用后續(xù)對(duì)話框顯示的影響;
狀態(tài)欄:
瀏覽器的狀態(tài)欄通常位于窗口的底部,用于顯示一些任務(wù)狀態(tài)信息等。在通常情況下,狀態(tài)顯示當(dāng)前瀏覽器的工作狀態(tài)或用戶交互提示信息; 具有status和defaultStatus屬性;
默認(rèn)狀態(tài)欄信息:
defaultStatus屬性可以用來設(shè)置在狀態(tài)欄中的默認(rèn)文本,是一個(gè)可讀寫的字符串;
狀態(tài)欄瞬間信息:
status屬性,在默認(rèn)情況下,將鼠標(biāo)放在一個(gè)超鏈接上時(shí),狀態(tài)欄會(huì)顯示該超鏈接的URL,此時(shí)的狀態(tài)欄信息就是瞬間信息;當(dāng)鼠標(biāo)離開超鏈接時(shí),狀態(tài)欄就會(huì)顯示默認(rèn)的狀態(tài)欄信息,瞬間信息消失 。
瀏覽器已經(jīng)關(guān)閉了狀態(tài)欄的功能;這是出于安全的考慮,防止隱藏了超鏈接真正目的的釣魚攻擊;
Web前端開發(fā)之Javascript-零點(diǎn)程序員-王唯
篇文章給大家?guī)淼膬?nèi)容是關(guān)于HTML5 Web Worker的介紹(附示例),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。
瀏覽器中的Web Worker
背景介紹
我們都知道JavaScript這個(gè)語言在執(zhí)行的時(shí)候是采用單線程進(jìn)行執(zhí)行的,也就是說在同一時(shí)間只能做一件事,這也和這門語言有很大的關(guān)系,采用同步執(zhí)行的方式進(jìn)行運(yùn)行,如果出現(xiàn)阻塞,那么后面的代碼將不會(huì)執(zhí)行,HTML5則提出了web Worker標(biāo)準(zhǔn),表示JavaScript允許有多個(gè)線程,但是子線程完全受主線程的控制,子線程不能操作DOM,只有主線程可以操作DOM,所以以主線程為主的單線程執(zhí)行原理成了JavaScript這門語言的核心。
進(jìn)程與線程的區(qū)別
根本區(qū)別:進(jìn)程是操作系統(tǒng)資源分配的基本單位,而線程是任務(wù)調(diào)度和執(zhí)行的基本單位。
在操作系統(tǒng)中能同時(shí)運(yùn)行多個(gè)進(jìn)程(程序);而在同一個(gè)進(jìn)程(程序)中有多個(gè)線程同時(shí)執(zhí)行。
兼容性
web worker是什么?
簡(jiǎn)單來說,其實(shí)就是在Javascript單線程執(zhí)行的基礎(chǔ)上,開啟一個(gè)子線程,進(jìn)行程序處理,而不影響主線程的執(zhí)行,當(dāng)子線程執(zhí)行完畢之后再回到主線程上,在這個(gè)過程中并不影響主線程的執(zhí)行過程。
舉個(gè)栗子
傳統(tǒng)情況下,執(zhí)行下面的代碼后,整個(gè)頁(yè)面都會(huì)被凍結(jié),由于javascript是單線程處理,如下代碼已經(jīng)完全組塞了后續(xù)的執(zhí)行
while(1){}
如果換一種方式,我們通過開啟一個(gè)新的線程來執(zhí)行這段代碼,將他放在一個(gè)單獨(dú)的worker.js文件中,在主線程執(zhí)行以下代碼,則可以避免這種情況。
var worker=new Worker("worker.js")
Web Worker的用法
判斷當(dāng)前瀏覽器是否支持web worker
if (typeof (Worker) !="undefined") { //瀏覽器支持web worker
if (typeof (w)=="undefined") { //w是未定義的,還沒有開始計(jì)數(shù)
w=new Worker("webworker.js"); //創(chuàng)建一個(gè)Worker對(duì)象,利用Worker的構(gòu)造函數(shù)
}
//onmessage是Worker對(duì)象的properties
w.onmessage=function (event) { //事件處理函數(shù),用來處理后端的web worker傳遞過來的消息
// do something
};
}
else { // 瀏覽器不支持web worker
// do something
}
API
①創(chuàng)建新的Worker
var worker=new Worker("worker.js")
②傳遞參數(shù)
worker.postMessage()
③接收消息
worker.onMessage=function(msg){}
④異常處理
worker.onerror=function(err){}
⑤結(jié)束worker
worker.terminate()
⑥載入工具類函數(shù)
importScripts()
Worker作用域
當(dāng)我們創(chuàng)建一個(gè)新的worker時(shí),該代碼會(huì)運(yùn)行在一個(gè)全新的javascript的環(huán)境中(WorkerGlobalScope)運(yùn)行,是完全和創(chuàng)建worker的腳本隔離,這時(shí)我們可以吧創(chuàng)建新worker的腳本叫做主線程,而被創(chuàng)建的新的worker叫做子線程。
WorkerGlobalScope是worker的全局對(duì)象,所以它包含所有核心javascript全局對(duì)象擁有的屬性如JSON等,window的一些屬性,也擁有類似于XMLHttpRequest()等。
但是我們所開啟的新的worker也就是子線程,并不支持操作頁(yè)面的DOM。
線程間的通訊是傳值而不是傳地址
主線程與子線程數(shù)據(jù)通信方式有多種,通信內(nèi)容,可以是文本,也可以是對(duì)象。需要注意的是,這種通信是拷貝關(guān)系,即是傳值而不是地址,子線程對(duì)通信內(nèi)容的修改,不會(huì)影響到主線程。事實(shí)上,瀏覽器內(nèi)部的運(yùn)行機(jī)制是,先將通信內(nèi)容串行化,然后把串行化后的字符串發(fā)給子線程,后者再將它還原。
JavaScript中的數(shù)據(jù)類型存放原理以及傳遞規(guī)則
共享線程(SharedWorker)
共享線程是為了避免線程的重復(fù)創(chuàng)建和銷毀過程,降低了系統(tǒng)性能的消耗,
共享線程SharedWorker可以同時(shí)有多個(gè)頁(yè)面的線程鏈接。
使用SharedWorker創(chuàng)建共享線程,也需要提供一個(gè)javascript腳本文件的URL地址或Blob,該腳本文件中包含了我們?cè)诰€程中需要執(zhí)行的代碼,如下:
var worker=new SharedWorker("sharedworker.js");
共享線程也使用了message事件監(jiān)聽線程消息,但使用SharedWorker對(duì)象的port屬性與線程通信如下:
worker.port.onmessage=function(msg){};
同時(shí)我們也可以使用SharedWorker對(duì)象的port屬性向共享線程發(fā)送消息如下:
worker.port.postMessage(msg);
運(yùn)行原理
生命周期
①當(dāng)一個(gè)web worker的文檔列表不為空的時(shí)候,這個(gè)web worker會(huì)被稱之為許可線程。
②當(dāng)一個(gè)web worker的文檔列表中的任何一個(gè)對(duì)象都是處于完全活動(dòng)狀態(tài)的時(shí)候,這個(gè)web worker會(huì)被稱之為需要激活線程。
③當(dāng)一個(gè)web worker是許可線程并且擁有計(jì)數(shù)器或者擁有數(shù)據(jù)庫(kù)事務(wù)或者擁有網(wǎng)絡(luò)連接或者它的web worker列表不為空的時(shí)候,這個(gè)web worker會(huì)被稱之為受保護(hù)的線程。
④當(dāng)一個(gè)web worker是一個(gè)非需要激活線程同時(shí)又是一個(gè)許可線程的時(shí)候,這個(gè)web worker會(huì)被稱之為可掛起線程。
以webKit為例加載并執(zhí)行worker的過程
應(yīng)用
可以做什么:
1.可以加載一個(gè)JS進(jìn)行大量的復(fù)雜計(jì)算而不掛起主進(jìn)程,并通過postMessage,onmessage進(jìn)行通信
2.可以在worker中通過importScripts(url)加載另外的腳本文件
3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()
4.可以使用XMLHttpRequest來發(fā)送請(qǐng)求
5.可以訪問navigator的部分屬性
不可以做什么:
1.不能跨域加載JS
2.worker內(nèi)代碼不能訪問DOM
3.各個(gè)瀏覽器對(duì)Worker的實(shí)現(xiàn)不大一致,例如FF里允許worker中創(chuàng)建新的worker,而Chrome中就不行
4.不是每個(gè)瀏覽器都支持這個(gè)新特性
以上就是HTML5 Web Worker的介紹(附示例)的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注其它相關(guān)文章!
更多技巧請(qǐng)《轉(zhuǎn)發(fā) + 關(guān)注》哦!
起HTML標(biāo)簽,前端工程師會(huì)非常的有發(fā)言權(quán),因?yàn)樵谄綍r(shí)開發(fā)中一定會(huì)用到,可以說是前端的入門必備知識(shí)。但往往在意更多的是頁(yè)面的渲染效果及交互方式,也就是頁(yè)面可見的部分,比如導(dǎo)航欄,菜單欄,列表,圖文等。
其實(shí)還有一些頁(yè)面上沒有呈現(xiàn)出來卻非常重要的標(biāo)簽,這些標(biāo)簽大部分在頁(yè)面的頭部head標(biāo)簽內(nèi),雖然在頁(yè)面上看不見摸不著,但如果在特定的場(chǎng)景下,會(huì)產(chǎn)生意想不到的效果。下面我將從交互優(yōu)化,性能優(yōu)化,搜索優(yōu)化三個(gè)方面并結(jié)合場(chǎng)景來聊聊被“忽視”的HTML標(biāo)簽。
交互優(yōu)化
meta 標(biāo)簽:自動(dòng)跳轉(zhuǎn)/刷新
假設(shè)要實(shí)現(xiàn)一個(gè)類似自動(dòng)播放的頁(yè)面,首先我們第一反應(yīng)會(huì)想到用js定時(shí)器控制頁(yè)面跳轉(zhuǎn)來完成。但是其實(shí)有更加簡(jiǎn)便的方法,通過meta標(biāo)簽的refresh功能來實(shí)現(xiàn)。
<meta http-equiv="refresh" content="10; url=view2.html">
上面的代碼會(huì)在 10s 之后自動(dòng)跳轉(zhuǎn)到同域下的 view2.html 頁(yè)面。我們要實(shí)現(xiàn)自動(dòng)播放的功能,只需要在每個(gè)頁(yè)面的 meta 標(biāo)簽內(nèi)設(shè)置好下一個(gè)頁(yè)面的地址即可。
如果要實(shí)現(xiàn)定時(shí)刷新的功能,只要去除后面url即可:
<meta http-equiv="refresh" content="10">
注意,用meta標(biāo)簽實(shí)現(xiàn)刷新/跳轉(zhuǎn)的過程是不可取消的,所以需要手動(dòng)取消的還是得老老實(shí)實(shí)使用js的定時(shí)器,但是對(duì)于簡(jiǎn)單的定時(shí)刷新或跳轉(zhuǎn),還是可以去親自實(shí)踐meta的用法。
title 標(biāo)簽:消息提醒
消息提醒功能實(shí)現(xiàn)在HTML5標(biāo)準(zhǔn)發(fā)布之前,瀏覽器還沒有開放圖標(biāo)閃爍、音頻播放,彈出系統(tǒng)消息之類的api,只能借助其他非常規(guī)的手段,比如修改title 標(biāo)簽來達(dá)到類似的效果。
下面的代碼通過定時(shí)修改title標(biāo)簽的內(nèi)容,實(shí)現(xiàn)了消息提醒的功能,可以讓用戶在瀏覽其他頁(yè)面時(shí)候,及時(shí)發(fā)現(xiàn)服務(wù)端返回的消息。
let messageNum=1; // 消息條數(shù)
let count=0; // 計(jì)數(shù)器
const msgInterval=setInterval(()=> {
count=(count + 1) % 2;
if(messageNum===0) {
// 通過DOM修改title
document.title +=`當(dāng)前頁(yè)面`;
clearInterval(msgInterval);
return;
}
const pre=count % 2 ? `新消息(${msgNum})` : '';
document.title=`${pre}當(dāng)前頁(yè)面`;
}, 1000);
當(dāng)然,動(dòng)態(tài)修改title標(biāo)簽的用途不僅僅是消息提醒,還可以顯示一些異步進(jìn)行的任務(wù),比如下載進(jìn)度,上傳進(jìn)度等。
性能優(yōu)化
script 標(biāo)簽:調(diào)整加載順序提升渲染速度
不知道你們有沒有過這樣的體驗(yàn):當(dāng)在瀏覽器打開某個(gè)頁(yè)面時(shí),發(fā)現(xiàn)頁(yè)面一直在loading轉(zhuǎn)圈,或者等了好長(zhǎng)的時(shí)間頁(yè)面才有響應(yīng)。這一現(xiàn)象,除了網(wǎng)絡(luò)網(wǎng)速的原因外,大多數(shù)都是由于頁(yè)面結(jié)構(gòu)設(shè)計(jì)不合理導(dǎo)致加載時(shí)間過長(zhǎng)。因此,如果想要提升頁(yè)面的渲染速度,就需要了解瀏覽器頁(yè)面的渲染過程是怎樣的,從根本上來解決問題。
瀏覽器在加載頁(yè)面的時(shí)候會(huì)用到 GUI 渲染線程和 JavaScript 引擎線程。其中,GUI 渲染線程負(fù)責(zé)渲染瀏覽器界面 HTML 元素,JavaScript 引擎線程主要負(fù)責(zé)處理 JavaScript 腳本程序。由于 JavaScript 在執(zhí)行過程中還可能會(huì)改動(dòng)界面結(jié)構(gòu)和樣式,因此它們之間被設(shè)計(jì)為互斥的關(guān)系。也就是說,當(dāng) JavaScript 引擎執(zhí)行時(shí),GUI 線程會(huì)被掛起,等執(zhí)行完 JavaScript 的腳本程序后又會(huì)切換 GUI 線程繼續(xù)渲染頁(yè)面。
所以我們可以知道頁(yè)面渲染過程中包含了請(qǐng)求腳本文件以及執(zhí)行腳本文件的時(shí)間,但頁(yè)面的首次渲染可能并不需要執(zhí)行完全部的文件,這些請(qǐng)求和執(zhí)行文件的動(dòng)作反而延長(zhǎng)了用戶看到頁(yè)面的時(shí)間,從而降低了用戶體驗(yàn)。
為了快速將內(nèi)容呈現(xiàn)給用戶,減少用戶等待時(shí)間,可以借助script標(biāo)簽的3個(gè)屬性來實(shí)現(xiàn):
async:表示立即請(qǐng)求腳本文件,但不阻塞 GUI 渲染引擎,而是文件加載完畢后阻塞 GUI 渲染引擎并立即執(zhí)行文件內(nèi)容。
defer。立即請(qǐng)求腳本腳本,但不阻塞 GUI 渲染引擎,等到解析完 HTML 之后再執(zhí)行文件內(nèi)容。
HTML5 標(biāo)準(zhǔn) type,對(duì)應(yīng)值為“module”。讓瀏覽器按照 ECMA Script 6 標(biāo)準(zhǔn)將文件當(dāng)作模塊進(jìn)行解析,默認(rèn)阻塞效果同 defer,也可以配合 async 在請(qǐng)求完成后立即執(zhí)行。
所以可以得知,采用defer 屬性以及 type="module" 情況下能保證渲染引擎的優(yōu)先執(zhí)行,從而減少執(zhí)行文件內(nèi)容消耗的時(shí)間,讓用戶更快地看見頁(yè)面(即使這些頁(yè)面內(nèi)容可能并沒有完全地顯示)。除此外還要知道,當(dāng)渲染引擎解析 HTML 遇到 script 標(biāo)簽引入文件時(shí),會(huì)立即進(jìn)行一次渲染,這就是為什么會(huì)把引用JavaScript 代碼的 script 標(biāo)簽放入到 body 標(biāo)簽底部。
link 標(biāo)簽:通過預(yù)處理提升渲染速度
在我們對(duì)中大型項(xiàng)目進(jìn)行性能優(yōu)化時(shí),往往會(huì)對(duì)資源做減法(gzip壓縮,緩存等)或除法(按需打包,按需加載),可是如果能想到 link 標(biāo)簽的 rel 屬性值來進(jìn)行預(yù)加載,也能加快頁(yè)面的渲染速度。
dns-prefetch。當(dāng) link 標(biāo)簽的 rel 屬性值為“dns-prefetch”時(shí),瀏覽器會(huì)對(duì)某個(gè)域名預(yù)先進(jìn)行 DNS 解析并緩存。這樣,當(dāng)瀏覽器在請(qǐng)求同域名資源的時(shí)候,能省去從域名查詢 IP 的過程(DNS查詢),從而減少時(shí)間損耗。(注意:這個(gè)屬性還在實(shí)驗(yàn)階段,部分瀏覽器的部分版本支持)
preconnect。讓瀏覽器在一個(gè) HTTP 請(qǐng)求正式發(fā)給服務(wù)器前預(yù)先執(zhí)行一些操作,這包括 DNS 解析、TLS 協(xié)商、TCP 握手,通過消除往返延遲來為用戶節(jié)省時(shí)間。(注意:這個(gè)屬性還在實(shí)驗(yàn)階段,部分瀏覽器的部分版本支持)
prefetch/preload。兩個(gè)值都是讓瀏覽器預(yù)先下載并緩存某個(gè)資源,但不同的是,prefetch 可能會(huì)在瀏覽器忙時(shí)被忽略,而 preload 則是一定會(huì)被預(yù)先下載。
prerender。瀏覽器不僅會(huì)加載資源,還會(huì)解析執(zhí)行頁(yè)面,進(jìn)行預(yù)渲染。(注意:這個(gè)屬性還在實(shí)驗(yàn)階段,部分瀏覽器的部分版本支持)
搜索優(yōu)化
你所寫的前端代碼,除了要讓瀏覽器更好執(zhí)行,有時(shí)候也要考慮更方便其他程序(如搜索引擎)理解。合理地使用 meta 標(biāo)簽和 link 標(biāo)簽,恰好能讓搜索引擎更好地理解和收錄我們的頁(yè)面。
meta 標(biāo)簽:提取關(guān)鍵信息
通過 meta 標(biāo)簽可以設(shè)置頁(yè)面的描述信息,從而讓搜索引擎更好地展示搜索結(jié)果。
例如,在百度中搜索“淘寶”,就會(huì)發(fā)現(xiàn)網(wǎng)站的描述信息,這些描述信息就是通過 meta 標(biāo)簽專門為搜索引擎設(shè)置的,目的是方便用戶預(yù)覽搜索到的結(jié)果。
為了讓搜索引擎更好地識(shí)別頁(yè)面,除了描述信息description之外還可以使用關(guān)鍵字,這樣即使頁(yè)面其他地方?jīng)]有包含搜索內(nèi)容,也可以被搜索到(當(dāng)然搜索引擎有自己的權(quán)重和算法,如果濫用關(guān)鍵字是會(huì)被降權(quán)的,比如 Google 引擎就會(huì)對(duì)堆砌大量相同關(guān)鍵詞的網(wǎng)頁(yè)進(jìn)行懲罰,降低它被搜索到的權(quán)重)。
當(dāng)我們搜索關(guān)鍵字“安全購(gòu)物”的時(shí)候搜索結(jié)果會(huì)顯示淘寶網(wǎng)的信息,雖然顯示的搜索內(nèi)容上并沒有看到“安全購(gòu)物”字樣,這就是因?yàn)樘詫毦W(wǎng)頁(yè)面中設(shè)置了這個(gè)關(guān)鍵字。
對(duì)應(yīng)代碼如下:
<meta content="淘寶,掏寶,網(wǎng)上購(gòu)物,C2C,在線交易,交易市場(chǎng),網(wǎng)上交易,交易市場(chǎng),網(wǎng)上買,網(wǎng)上賣,購(gòu)物網(wǎng)站,團(tuán)購(gòu),網(wǎng)上貿(mào)易,安全購(gòu)物,電子商務(wù),放心買,供應(yīng),買賣信息,網(wǎng)店,一口價(jià),拍賣,網(wǎng)上開店,網(wǎng)絡(luò)購(gòu)物,打折,免費(fèi)開店,網(wǎng)購(gòu),頻道,店鋪" name="keywords">
在實(shí)際工作中,推薦使用一些關(guān)鍵字工具來挑選,比如
Google Trends
https://trends.google.com/trends
站長(zhǎng)工具
https://data.chinaz.com/keyword/
link 標(biāo)簽:減少重復(fù)
有時(shí)候?yàn)榱擞脩粼L問方便或者出于歷史原因,對(duì)于同一個(gè)頁(yè)面會(huì)有多個(gè)網(wǎng)址,又或者存在某些重定向頁(yè)面,比如:
- https://baidu.com/a.html
- https://baidu.com/detail?id=abcd
那么在這些頁(yè)面中可以這樣設(shè)置:
<link href="https://baidu.com/a.html" rel="canonical">
這樣可以讓搜索引擎避免花費(fèi)時(shí)間抓取重復(fù)網(wǎng)頁(yè)。不過需要注意的是,它還有個(gè)限制條件,那就是指向的網(wǎng)站不允許跨域。
當(dāng)然,要合并網(wǎng)址還有其他的方式,比如使用站點(diǎn)地圖,或者在 HTTP 請(qǐng)求響應(yīng)頭部添加 rel="canonical"。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。