關於HTML5 淺析

HTML5 腳本語言 Chrome 軟件 php疑難雜症鋪 php疑難雜症鋪 2017-09-09

關於HTML5 淺析

前言:

作為一名Web開發者,可能你並沒有對這個“H5”這個字眼投入太多的關注,但實際上它早已不知不覺進入到你的開發中,並且總有一天會讓你不得不正視它,瞭解它並運用它

打個比方:《海賊王》中的主角路飛在“頂上戰爭兩年前”,會在一些危急關頭“不經意”地使用霸王色霸氣,但對”霸氣“的結構體系和具體運用都不太瞭解,這讓他在香波地群島等諸多重大戰役中大吃苦頭。此後, 他不惜花費兩年時間跟隨雷利修煉霸氣。因為,如果不去了解這個嶄新的戰鬥方法的話,他們在殘酷的新世界一天也生存不了。


為什麼學習HTML5?

咳咳, 回到主題,為什麼我們要學HTML5呢?

1. 瞭解HTML5的囊括範圍的一大好處是:當你不小心使用了一個H5的東東的時候(例如你試圖通過百度找到的答案解決一個緊張的需求),你會很及時的關注它的兼容性

2. H5有些新增的特性也許你從沒接觸過,也感覺無需用到它。但就在不久的將來,你可能就會用到,甚至依賴於它(畢竟這就是HTML的未來)


H5中的知識點分佈

在下面, 我將學習H5中的知識點分成兩類:主要知識點和針對特定功能的知識點,其中對主要知識點的部分,從學習成本的角度對其進行了難度分級

(僅屬個人觀點!如有改進意見,歡迎討論)

一.主要知識點

(從需求層面上來說,普及範圍相對較廣)

相對容易的部分:

1.在線和離線事件(Online/Offline) (相對容易)

2. 眾多的新增元素 如<output>, <progress>等 (相對容易)

3. history關於歷史狀態管理的API (相對容易)

4 Storage(localStorage和sessionStorage) (相對容易)

相對較難的部分:

5. Web Worker (相對較難)

6. canvas (相對較難)

7. indexedDB (相對較難)

8. 拖放操作 (相對較難)

9. Web Sockets (相對較難)

二. 針對特定功能的知識點

(對需求來說,主要針對某一方面的特殊需求場景)

1. 對音視頻的支持

2. Camera API (操作攝像頭)

3. WebGL (3D圖像)

4. 地理位置定位 (geolocation對象)

本文主要講述H5中主要知識點中,學習成本相對較高的四個點(僅個人觀點):

一.Web Worker

二.canvas

三.indexedDB

四.拖放操作

【注意】因為下面介紹的H5的特性在一些比較老的瀏覽器裡可能遇到兼容性問題,所以你在使用前必須要能力檢測,例如這樣

關於HTML5 淺析


Web Worker

Web Worker的機制讓你能夠創建一個在後臺線程運行的腳本,這個腳本不會對我們當前執行任務的腳本造成任何干擾(例如阻塞),同時Web Worker提供了一套API使你能夠在當前腳本和後臺腳本間進行數據的互相傳輸(worker)

“一套API, 兩個對象”

我們現在已知的關於Web Worker的機制是: 有一個當前腳本, 和一個在後臺運行的worker腳本,所以我們問題的關鍵就落在了這兩個腳本的通信(數據交互)上

通過

關於HTML5 淺析

生成了“兩個對象”(你可能會問:為什麼是兩個不是一個呢?請往下看

“第一個”對象是我們在當前腳本中通過構造函數顯式創建出來的worker對象,它擁有一套API:postMessage和onmessage,通過postMessage方法可以向worker腳本(上文worker.js)發送數據, 通過onmessage方法可以從worker腳本接收數據

“第二個”對象是在Web Worker腳本(上文的worker.js)中隱式創建出來的全局變量對象它叫DedicatedWorkerGlobalScope(這個時候在work.js全局變量對象是它而不是Window!!),而它也擁有一套API:postMessage和onmessage,通過postMessage方法可以向當前執行任務的腳本發送數據, 通過onmessage方法可以從當前執行任務的腳本接收數據

【注意】關於DedicatedWorkerGlobalScope

1. 它是在Web Worker腳本中生成的特殊的全局變量對象,也就是在全局執行環境中使用this指向的不是Window而是它

2. 它不能像Windows那樣通過變量名直接訪問,但在Web Worker腳本中你能通過this取到它

所以現在數據傳遞方向有兩條:

1. 調用當前腳本中worker對象的postMessage方法, 然後在Web Worker腳本(上文的worker.js)中通過onmessage這個回調方法接收數據

2. 調用Web Worker腳本中的this.postMessage方法(this指向DedicatedWorkerGlobalScope),然後在當前腳本中worker對象的onmessage回調方法接收數據

看到這裡可能有點懵,來讓我們通過一個例子看看1中的數據傳遞:

先看示例吧,這是我們的目錄結構

關於HTML5 淺析

index.html:

關於HTML5 淺析

main.js:

關於HTML5 淺析

worker.js:

關於HTML5 淺析

點擊按鈕後,在main.js中調用worker對象的postMessage方法, 這個數據就被髮給了work.js中的全局變量對象DedicatedWorkerGlobalScope, 所以我們在work,js中通過this.onmessage接收數據並輸出

關於HTML5 淺析


postMessage中的參數會“原封不動”傳遞給onmessage中的event.data

【注意】postMessage傳遞的參數會被“原封不動”地傳遞給onmessage中event對象的data屬性

例如:

postMessage([1,2,3]) ——> this.onmessage = function (e) { } 中 e.data === [1,2,3]

postMessage({a:1,b: 2}) ——> this.onmessage = function (e) { } 中 e.data === {a:1,b: 2}


當前任務腳本和worker腳本完整的通信流程

我們上面的例子展現的是從當前任務腳本向worker腳本傳遞數據,那麼同樣的道理,我們也能從work腳本向當前任務腳本傳遞數據(方式相同)

例子:

關於HTML5 淺析

index.html:

同上

main.js:

關於HTML5 淺析

worker.js:

關於HTML5 淺析

demo如下

點擊傳遞數據輸出:

關於HTML5 淺析

canvas

cancas是H5新增的一個標籤,把canvas翻譯過來就是畫布,顧名思義,這是用來”畫畫的“,畫畫的”畫筆“是什麼呢? 它就是和canvas元素對象對應的一個”上下文對象“(context),這裡的這個上下文對象可能和你印象中的”上下文“有較大的差異,它只是個單純的包含了一系列“繪畫”方法的對象,下面我們介紹的關於canvas的內容都要圍繞這個"canvas上下文對象"展開

我們可以通過這種方式取得canvas上下文對象:

假設這是我們的HTML:

關於HTML5 淺析

這樣取得上下文對象:

關於HTML5 淺析


繪製基本形狀

下面展現的是上下文對象的一些繪製圖形的方法(它們都可以被ctx調用)

關於HTML5 淺析

上面的x,y代表相對於canvas畫布左上角的橫縱座標:

關於HTML5 淺析

例子:

html部分:

關於HTML5 淺析

JS部分:

關於HTML5 淺析

【注意】. canvas標籤內的內容(例如上面的文本)是否呈現取決於瀏覽器是否支持canvas,如果支持,則不出現,如果不支持,則會呈現出來

demo:

關於HTML5 淺析


給畫筆添加顏色和樣式

我們以上面的為基礎稍作修改:

關於HTML5 淺析

demo:

關於HTML5 淺析


繪製文本

關於HTML5 淺析

demo:

關於HTML5 淺析

這裡要稍微提一下, 也許上面的那些繪製圖形,繪製文本的操作對你來說都沒有觸動,因為它們離我們的直接需求似乎還有一定的距離,但我想接下來的這幾個上下文API你或許有些興趣。

例如我們可能有一個需求是載入已有的圖片,對它截圖(裁剪)後保存為一張新的圖片,這個時候我們就可以使用到canvas的繪製圖片,裁剪圖片,保存圖片的API了


直接繪製已有圖片

通過canvas上下文對象的drawImage方法可直接繪製圖片

關於HTML5 淺析

我們可以通過下面的一段代碼動態獲取img元素對象

關於HTML5 淺析

廢話不多說,直接上demo!

在相同目錄下有這麼一張圖片

關於HTML5 淺析

JS代碼:

關於HTML5 淺析

demo:

我們發現, 圖片加載完成後被寫入了畫布當中!

關於HTML5 淺析


圖片裁剪功能

canvas上下文對象的clip方法可根據路徑對canvas畫布進行裁剪

讓我們在原來的基礎上添加一點東西:

關於HTML5 淺析

關於HTML5 淺析

【注意】clip方法的調用要在drawImage方法之前,否則不能成功! 也就是說要“先裁剪,再畫圖”

canvas的保存和導出

我們通過document.getElementById("canvas")取得的畫布對象,有一個toDataURL()方法,可將當前畫布作為一張圖片,並返回其base64編碼格式的數據,這在保存圖片的時候非常有用

toDataURL接受兩個參數:圖片類型和質量參數

canvas.toDataURL(圖片類型,質量參數)

關於HTML5 淺析

看下面的例子

關於HTML5 淺析

控制檯輸出了base64格式的數據:

關於HTML5 淺析

我們通過網上的還原軟件看看會把這個base64數據還原成什麼圖片:

關於HTML5 淺析

正是我們想要的圖片

indexedDB — — H5的“瀏覽器數據庫”

indexedDB是存在於瀏覽器中的數據庫,它和一般的數據庫一樣有寫改刪查的功能,不同之處在於:常見的數據庫一般是在服務器上,並且要求我們的應用在線時才可以工作,而indexedDB使得在離線的時候讀取數據成為了可能。下面,我就給大家介紹一下這個“駐紮”在瀏覽器上的特殊的數據庫吧

使用open方法創建/打開數據庫

我們首先要做的事情,當然是創建(或打開)一個數據庫,這要用到indexedDB對象的open方法

它接收兩個參數: 數據庫名稱和數據庫版本(第二個參數是可選的)

關於HTML5 淺析

調用open方法時候,如果對應名稱的數據庫不存在,則創建一個新的數據庫,如果已存在,則打開已存在的那個數據庫

需要說明的是, indexedDB裡面絕大多數操作都是異步的, 上述的indexedDB.open並不會立即創建一個數據庫, 你需要在異步的回調裡面判斷數據庫是否創建成功,並對可能出現的錯誤做判斷和處理

只有在onsuccess回調中,你才能通過request.result取得創建成功的數據庫

關於HTML5 淺析

通過open返回的request對象有三個回調:

onsuccess 每次創建/打開數據庫時候都會調用

onerror 創建/打開數據庫發生錯誤的時候調用

onupgradeneeded 數據庫版本變化的時候調用 (onupgradeneeded 是我們唯一可以修改數據庫結構的地方)

open一個indexedDB數據庫後,一般在onupgradeneeded回調中初始化(或修改)數據庫結構(劃重點!!)

這包括兩個方面的操作:

1. 通過db.createObjectStore創建對象存儲空間,並取得ObjectStore對象(類似於SQL數據庫中的建表操作)

2. 通過調用ObjectStore.createIndex創建該存儲空間內的索引( 以便於提高查詢時候的速度)

具體的可看下面的例子:

關於HTML5 淺析

關於HTML5 淺析

運行一下, 然後讓我們看看效果:

關於HTML5 淺析

打開chrome的Application面板,點擊左欄的Storage下的indexedDB使其展開

就可以看到我們新創建的phwDataBase數據庫, 以及它內部的people數據存儲空間了

(右邊展示的是people數據存儲空間的具體內容,因為現在什麼數據都還沒添加,所以key和value兩列下是沒有內容的)

看了上面的代碼你可能會有些疑惑

onupgradeneeded 和onsuccess回調的關係是怎樣的? 為什麼我們必須在.onupgradeneeded中初始化數據庫的結構,而不是在onsuccess中?

這主要是由兩個回調調用的時機決定的:

1.對 onsuccess回調,在每次數據庫創建/打開的時候都會調用(不僅是第一次創建的時候會調用,每次打開的時候也都會調用)

2. 對onupgradeneeded回調,在open提供第二個版本參數的前提下:

2.1 第一次調用open方法創建一個新的數據庫的時候,onupgradeneeded一定會被調用

2.2 第二次或以後open該數據庫,只在版本參數改變的時候, onupgradeneeded才會被調用

【注意】在缺少第二個版本參數的情況下,onupgradeneeded永遠不會被調用!!

所以說:

1.open數據庫的時候,最(yi)好(ding)要帶上第二個參數(版本參數)

2. 修改數據庫結構(例如創建和刪除對象存儲空間以及構建和刪除索引。)要在onupgradeneeded回調中運行

(很顯然每次打開都會被調用的onsuccess並不適合用於初始化數據庫結構)

indexedDB的具體操作

首先說一下,在下面的展示例子中,我們的HTML是這樣的

關於HTML5 淺析

demo:

關於HTML5 淺析

這裡要說明一下的是,indexedDB的操作是以事務為基礎的。 所以,對存儲空間(objectStore)的操作都要基於事務來進行。 具體點說,就是需要先通過db.transaction()方法取得transaction對象,然後再通過transaction.objectStore()方法取得目標objectStore,再然後才能調用objectStore的API進行“寫改刪查”

打個比方, 如果說我們存儲的數據是糧食的話, objectStore就是一個個並排的糧倉,你可以往裡面運糧食,也可以把糧食運出去, 但你對“糧食”做任何行為前, 都要和糧倉門前的守衛—— transaction(事務)“打聲招呼”,得到准許才能進入糧倉

有兩個方法要說一下

1. transaction方法

transaction 方法 一般接受兩個參數,並返回一個事務對象。

1.1第一個參數是一個數組, 一個我們希望事務能夠操作的objectStore所組成的數組,如果你希望這個事務能夠操作所有的objectStore,那麼傳入空數組[]即可

1.2 第二個參數是一個字符串, 默認是“onlyread”, 如果我們有需要對數據進行寫操作的需求的話可傳入“readwrite”

例如我們下面的一行代碼:

關於HTML5 淺析

2. transaction.objectStore方法

這個方法接受一個參數: 指定的objectStore的名稱, 方法返回的是獲取到的objectStore

例如我們下面的一行代碼:

關於HTML5 淺析

寫操作

寫操作的關鍵在於objectStore.add(XXX);方法,其中XXX是我們初始化objectStore時候寫入的“主鍵”

也就是 var objectStore = db.createObjectStore("people", { keyPath: "id" }); (這段代碼在上面)中keyPath的值——id

關於HTML5 淺析

關於HTML5 淺析

demo:

點擊“增加數據”後彈出

關於HTML5 淺析

再看看application面板下的indexedDB:

關於HTML5 淺析

我們已經成功添加了三條數據進去了

刪操作

刪操作的關鍵在於objectStore.delete(XXX);方法,其中XXX是我們初始化objectStore時候寫入的“主鍵”

也就是 var objectStore = db.createObjectStore("people", { keyPath: "id" }); 中keyPath的值——id

關於HTML5 淺析

點擊上面的“刪除數據”按鈕(刪除id = 1的數據)

關於HTML5 淺析

再來看看, id為1的那一行已經被刪除了

關於HTML5 淺析

查操作

刪操作的關鍵在於objectStore.get(XXX);方法

關於HTML5 淺析

demo:

點擊“獲取數據”按鈕,彈出

關於HTML5 淺析

(這裡固定查找id為2的數據)

遍歷全部數據

遍歷數據需要用到遊標

通過 objectStore.openCursor()可創建一個遊標對象(cursor), 這個cursor對象包含兩個屬性值: key和value

key就是我們一直說的那個“主鍵”, 而value是我們存入的時候的那個對象,通過 cursor.continue方法可以使得遊標向下移動

關於HTML5 淺析

點擊“遍歷全部數據”按鈕,看看控制檯

關於HTML5 淺析

通過索引查找

我們通過objectStore.get方法,通過查找主鍵的方式查找對應的對象數據的方式是很快的。

但如果我們通過非主鍵的數據去查找對應的那個對象就非常慢了,這個時候我們需要創建一個索引並通過索引來查找, 從而獲得較快的速度:

關於HTML5 淺析

點擊“通過索引獲取數據”按鈕:

關於HTML5 淺析

好! 現在讓我們對indexedDB做一個小小的總結:

1. indexedDB是面向對象的, 與傳統的以二維表為基礎的數據庫不同

2. IndexedDB是一個事務型數據庫系統

3. indexedDB大多數API都是異步的,這意味著調用一個方法你不能馬上得到關鍵的那個對象,而在對應的success回調中才能取得


拖放事件

一個典型的拖放操作是這樣開始的:用戶用鼠標選中一個可拖動的(draggable)元素,移動鼠標到一個可放置的(droppable)元素,然後釋放鼠標。 在操作期間,會觸發一系列的拖放類型的事件

其中我們主要關心的事件有三個:

1. ondragstart 發生在可拖拽(draggable)的元素上, 在元素被拖動的時候調用

2. ondragover 發生在可放置(droppable)的元素上, 當某被拖動的對象在可放置對象範圍內(上方)時觸發此事件

3. ondrop 發生在可放置(droppable)的元素上,當釋放鼠標使可拖拽元素“放進”可放置元素內的瞬間觸發。

需思考的問題:

1. 如何使得被拖拽元素可拖拽?(因為元素默認的行為是不可拖拽的),以及如何使得被放置的容器元素可放置? (因為元素默認是不可放置的)

對前者, 我們可以為元素設置draggable屬性,並且設置為true

對後者, 我們可以在被放置的容器元素中的ondragover事件裡通過event.preventDefault();阻止默認行為——禁止放置

2.如何實現“脫 — 放”過程的數據傳遞?

這裡首先需要知道的是,當我們拖動一個圖片到另一個地方的時候,我們是不能“直接把圖片拖拽進去”的,也就是說,我們還是要通過以下的思路實現拖放:

在被放置的元素中取得被拖拽元素的相關數據(如id),然後通過appendChild之類的API實現添加被拖拽的元素,從而模擬整個拖拽的過程

也就是說, 拖拽其實可分為三個過程: 拖動—傳遞被拖動元素的數據(如id)—在容器元素中添加該元素

關鍵在於如何在被拖動元素和被放置元素中傳遞數據,這可以通過event.dataTransfer對象來實現

dataTransfer可以通過setData方法添加拖動數據,並通過getDate方法取得拖動數據,我們可以在

ondragstart事件和ondrop事件中調用這兩個方法, 實現關鍵性的數據傳遞。

具體請看下面的例子:

關於HTML5 淺析

關於HTML5 淺析

拖拽前

關於HTML5 淺析

拖拽後

關於HTML5 淺析

參考資料:

HTML5-MDN https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/HTML5

【完】

相關推薦

推薦中...