h5新特性

CSDN博客

img Gane_Cheng

HTML5新特性淺談

發表於2016/10/17 21:25:58  7809人閱讀javascript

分類: 前端php

這裏寫圖片描述

轉載請註明出處:css

http://blog.csdn.net/gane_cheng/article/details/52819118html

http://www.ganecheng.tech/blog/52819118.html (瀏覽效果更好)前端

2014年10月29日,W3C宣佈,通過接近8年的艱苦努力,HTML5標準規範終於制定完成。html5

HTML5將會取代1999年制定的HTML 4.0一、XHTML 1.0標準,以期能在互聯網應用迅速發展的時候,使網絡標準達到符合當代的網絡需求,爲桌面和移動平臺帶來無縫銜接的豐富內容。java

做爲2010年入坑IT的程序員來講,能夠說一步一步見證着HTML5的發展。這些年爲了兼容IE6放棄了不少HTML5的新特性。可是今時不一樣以往,移動設備的流行,自然支持HTML5,以及桌面端IE最終被用戶和微軟唾棄,更多支持HTML5瀏覽器的受歡迎,我要從新研究一下HTML5帶來的這些新特性。node

HTML5 的新特性

① 語義特性(Semantic)linux

HTML5賦予網頁更好的意義和結構。css3

② 本地存儲特性(OFFLINE & STORAGE)

基於HTML5開發的網頁APP擁有更短的啓動時間,更快的聯網速度,這些全得益於HTML5 APP Cache,以及本地存儲功能。

③ 設備訪問特性 (DEVICE ACCESS)

從Geolocation功能的API文檔公開以來,HTML5爲網頁應用開發者們提供了更多功能上的優化選擇,帶來了更多體驗功能的優點。HTML5提供了史無前例的數據與應用接入開放接口。使外部應用能夠直接與瀏覽器內部的數據直接相連,例如視頻影音可直接與microphones及攝像頭相聯。

④ 鏈接特性(CONNECTIVITY)

更有效的鏈接工做效率,使得基於頁面的實時聊天,更快速的網頁遊戲體驗,更優化的在線交流獲得了實現。HTML5擁有更有效的服務器推送技術,Server-Sent Event和WebSockets就是其中的兩個特性,這兩個特性可以幫助咱們實現服務器將數據「推送」到客戶端的功能。

⑤ 網頁多媒體特性(MULTIMEDIA)

支持網頁端的Audio、Video等多媒體功能, 與網站自帶的APPS,攝像頭,影音功能相得益彰。

⑥ 三維、圖形及特效特性(3D, Graphics & Effects)

基於SVG、Canvas、WebGL及CSS3的3D功能,用戶會驚歎於在瀏覽器中,所呈現的驚人視覺效果。

⑦ 性能與集成特性(Performance & Integration)

沒有用戶會永遠等待你的Loading——HTML5會經過XMLHttpRequest2等技術,解決之前的跨域等問題,幫助您的Web應用和網站在多樣化的環境中更快速的工做。


下面分別對這七個新特性進行研究。

① 語義特性(Semantic)

這裏寫圖片描述

HTML5增長了新的內容標籤,這些標籤帶有必定的語義,使搜索引擎爬取你的網站信息更高效。

這裏寫圖片描述

HTML4中的內容標籤級別相同,沒法區分各部份內容。而HTML5中的內容標籤互相獨立,級別不一樣,搜索引擎以及統計軟件等都可快速識別各部份內容。

這些標籤在新聞類網站,博客類網站頗有用。

最大的問題就是當使用這些新的語義元素時,那些不支持的瀏覽器如何處理這些元素。

見過的最多的解決方法是這樣的。

<section class="section"> <!-- content --> </section>
  • 1
  • 2
  • 3
  • 4
  • 5
.section { color: blue; }
  • 1
  • 2
  • 3
  • 4

若是還想了解更多語義標籤兼容性問題,能夠參考這篇文章http://html5.group.iteye.com/group/wiki/3293-html5

② 本地存儲特性(OFFLINE & STORAGE)

這裏寫圖片描述

HTML5提供了網頁存儲的API,方便Web應用的離線使用。除此以外,新的API相對於cookie也有着高安全性,高效率,更大空間等優勢。

先看W3C對離線存儲的介紹。

Web Apps can start faster and work even if there is no internet connection, thanks to the HTML5 App Cache, as well as the Local Storage, Indexed DB, and the File API specifications.

HTML5離線存儲包含 應用程序緩存本地存儲索引數據庫文件接口

下面依次展開介紹。

(1)應用程序緩存(Application Cache)

這裏寫圖片描述

使用 HTML5,經過建立 cache manifest 文件,能夠輕鬆地建立 web 應用的離線版本。

HTML5引入了應用程序緩存,這意味着 web 應用可進行緩存,並可在沒有因特網鏈接時進行訪問。

應用程序緩存爲應用帶來三個優點:

  • 離線瀏覽 – 用戶可在應用離線時使用它們
  • 速度 – 已緩存資源加載得更快
  • 減小服務器負載 – 瀏覽器將只從服務器下載更新過或更改過的資源。

甭廢話,先來感覺一下Application Cache的魅力。Shut up,show me the demo!

Demo連接:http://www.ganecheng.tech/welcome_offline.html

1.打開這個網頁,第一次等待加載完成以後,頁面和普通的網頁沒有區別。

2.點擊刷新按鈕,或者強制刷新按鈕,看一下第二次打開的速度。有沒有快到爆。(速度

3.如今我要求你拔掉網線,斷開WiFi,再次點擊刷新按鈕,或者強制刷新按鈕,看一下第三次打開的速度。有沒有快到爆。注意,如今並無聯網,和服務器失去鏈接,依然秒開網頁,還能正常操做網頁。(離線瀏覽,減小服務器負載

看完了效果,看一下App Cache的原理。

這裏寫圖片描述

當咱們第一次正確配置cache manifest後,瀏覽器會將清單文件中的資源緩存下來。當咱們再次訪問該應用時,瀏覽器會直接返回緩存中的資源,而後檢查manifest文件是否有變更,若是有變更就會把相應的變更更新下來,同時改變瀏覽器裏面的app cache。

使用方法

頁面聲明使用App Cache

<!DOCTYPE HTML> <html manifest="index.manifest"> 
  • 1
  • 2

清單文件中寫明資源。

CACHE MANIFEST
theme.css logo.gif main.js NETWORK: login.asp FALLBACK: /html5/ /404.html
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

manifest 文件可分爲三個部分:

CACHE MANIFEST - 在此標題下列出的文件將在首次下載後進行緩存
NETWORK - 在此標題下列出的文件須要與服務器的鏈接,且不會被緩存
FALLBACK - 在此標題下列出的文件規定當頁面沒法訪問時的回退頁面(好比 404 頁面)

CACHE MANIFEST,是必需的
NETWORK 規定文件 「login.asp」 永遠不會被緩存,且離線時是不可用的
FALLBACK 規定若是沒法創建因特網鏈接,則用 「404.html」 替代 /html5/ 目錄中的全部文件

一旦應用被緩存,它就會保持緩存直到發生下列狀況:

  • 用戶清空瀏覽器緩存 ,用戶怎麼作,頁面左右不了,說了等於沒說。
  • manifest 文件被修改,請注意:更新清單中列出的某個文件並不意味着瀏覽器會從新緩存該資源。清單文件自己必須進行更改,通常是加一個註釋,註釋的內容是日期,想更新了,改一下日期。
  • 由程序來更新應用緩存,這個稍微靠譜一點。

須要注意的是,更新後的資源須要下次打開頁面才能生效,本次打開的頁面在更新資源以前就已經從緩存中拿到資源並加載完畢了。

由程序來更新,須要依賴manifest文件被修改這一條,由於調用的是瀏覽器提供的接口,檢測 window.applicationCache.status 的值,若是是 UPDATEREADY,說明瀏覽器比較manifest文件完畢,能夠更新緩存了。window.applicationCache.swapCache()。更新完了,不會當即生效,window.location.reload();從新加載一下頁面。

緩存有這麼多狀態。

var appCache = window.applicationCache; switch (appCache.status) { case appCache.UNCACHED: // UNCACHED == 0 return 'UNCACHED'; break; case appCache.IDLE: // IDLE == 1 return 'IDLE'; break; case appCache.CHECKING: // CHECKING == 2 return 'CHECKING'; break; case appCache.DOWNLOADING: // DOWNLOADING == 3 return 'DOWNLOADING'; break; case appCache.UPDATEREADY: // UPDATEREADY == 4 return 'UPDATEREADY'; break; case appCache.OBSOLETE: // OBSOLETE == 5 return 'OBSOLETE'; break; default: return 'UKNOWN CACHE STATUS'; break; }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

程序更新緩存的方法。

// Check if a new cache is available on page load. window.addEventListener('load', function(e) { window.applicationCache.addEventListener('updateready', function(e) { if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { // Browser downloaded a new app cache. // Swap it in and reload the page to get the new hotness. window.applicationCache.swapCache(); if (confirm('A new version of this site is available. Load it?')) { window.location.reload(); } } else { // Manifest didn't changed. Nothing new to server. } }, false); }, false); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

更多更新緩存的方法,能夠參考這篇文章:http://www.jb51.net/html5/67850.html

總的來講,App Cache的三個優勢很是明顯。可是有幾個坑,卻會致使沒人願意使用這個新特性。

1.使用了App Cache的頁面在清單文件更新以後去更新頁面資源,可是隻在下次打開頁面才能生效,這意味着,咱們須要使用代碼判斷是否是最新版本,不是的話,刷新一次頁面。這種體驗很很差。

2.使用了App Cache的頁面也會被緩存,這對於須要動態更新的頁面來講,幾乎是個噩夢。用戶訪問到的頁面不是最新的,會致使很是多的問題。

3.App cache與browser cache混合在一塊兒會使更新機制變得更加複雜,主要有如下幾個因素:
1) App cache在各瀏覽器平臺實現上存在差別;
2) 各瀏覽器又提供了不一樣的頁面刷新機制;
3) app cache還與傳統的browser cache有着千絲萬縷的聯繫;對於它倆如何協同工做,HTML5的相關規範沒有對app cache的細節給出很是明確的規定; 瀏覽器官方文檔有沒有給出很是明確的說明。
4) browser cache的更新機制自己就已經很複雜。
5) 若是manifest文件自己就有緩存時間,或設置爲永遠均可用,那你的網頁永遠都不會被更新了。

App Cache更多的坑,能夠參考這篇文章:http://dreclo.blog.163.com/blog/static/528789512014111675023409/ , 而後再決定要不要使用這一新特性。

從驚歎於App Cache的強大,到填坑,W3C花了這麼長時間,就弄出來這麼個東西,真是使人失望。學會使用App Cache只用了不到一小時,填坑填了一下午。每一個頁面都要有manifest,每一個頁面都要加代碼去判斷去更新緩存,我能夠罵人嗎。


(2)本地存儲(Local Storage)

這裏寫圖片描述

本地存儲發展歷史.

這裏寫圖片描述

最先的Cookies天然是你們都知道,問題主要就是過小,大概也就4KB的樣子,並且IE6只支持每一個域名20個cookies,太少了。優點就是你們都支持,並且支持得還蠻好。很早之前那些禁用cookies的用戶也都慢慢的不存在了,就好像之前禁用javascript的用戶不存在了同樣。

userData是IE的東西,垃圾。如今用的最多的是Flash吧,空間是Cookie的25倍,基本夠用。再以後Google推出了Gears,雖然沒有限制,但不爽的地方就是要裝額外的插件(沒具體研究過)。到了HTML5把這些都統一了,官方建議是每一個網站5MB,很是大了,就存些字符串,足夠了。比較詭異的是竟然全部支持的瀏覽器目前都採用的5MB,儘管有一些瀏覽器可讓用戶設置,但對於網頁製做者來講,目前的形勢就5MB來考慮是比較穩當的。

首先天然是檢測瀏覽器是否支持本地存儲。在HTML5中,本地存儲是一個window的屬性,包括localStorage和sessionStorage,從名字應該能夠很清楚的辨認兩者的區別,前者是一直存在本地的,後者只是伴隨着session,窗口一旦關閉就沒了。兩者用法徹底相同,這裏以localStorage爲例。

if(window.localStorage) { alert('This browser supports localStorage'); } else { alert('This browser does NOT support localStorage'); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

存儲數據的方法就是直接給window.localStorage添加一個屬性,例如:window.localStorage.a 或者 window.localStorage[「a」]。它的讀取、寫、刪除操做方法很簡單,是以鍵值對的方式存在的,以下:

localStorage.a = 3;//設置a爲"3" localStorage["a"] = "sfsf";//設置a爲"sfsf",覆蓋上面的值 localStorage.setItem("b","isaac");//設置b爲"isaac" var a1 = localStorage["a"];//獲取a的值 var a2 = localStorage.a;//獲取a的值 var b = localStorage.getItem("b");//獲取b的值 localStorage.removeItem("c");//清除c的值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

這裏最推薦使用的天然是getItem()和setItem(),清除鍵值對使用removeItem()。若是但願一次性清除全部的鍵值對,能夠使用clear()。另外,HTML5還提供了一個key()方法,能夠在不知道有哪些鍵值的時候使用,以下:

var storage = window.localStorage; function showStorage() { for(var i=0;i<storage.length;i++) { //key(i)得到相應的鍵,再用getItem()方法得到對應的值 document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>"); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

寫一個最簡單的,利用本地存儲的計數器:

var storage = window.localStorage; if (!storage.getItem("pageLoadCount")) { storage.setItem("pageLoadCount",0); } storage.pageLoadCount = parseInt(storage.getItem("pageLoadCount")) + 1;//必須格式轉換 document.getElementById("count").innerHTML = storage.pageLoadCount; showStorage();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

不斷刷新就能看到數字在一點點上漲,以下圖所示:

這裏寫圖片描述

須要注意的是,HTML5本地存儲只能存字符串,任何格式存儲的時候都會被自動轉爲字符串,因此讀取的時候,須要本身進行類型的轉換。這也就是上一段代碼中parseInt必需要使用的緣由。

想要對localStorage瞭解更多請參考這篇文章:http://www.cnblogs.com/xiaowei0705/archive/2011/04/19/2021372.html

(3)索引數據庫(Indexed DB)

這裏寫圖片描述

從本質上說,IndexedDB容許用戶在瀏覽器中保存大量的數據。任何須要發送大量數據的應用均可以得益於這個特性,能夠把數據存儲在用戶的瀏覽器端。當前這只是IndexedDB的其中一項功能,IndexedDB也提供了強大的基於索引的搜索api功能以得到用戶所須要的數據。

用戶可能會問:IndexedDB是和其餘之前的存儲機制(如cookie,session)有什麼不一樣?

Cookies是最經常使用的瀏覽器端保存數據的機制,但其保存數據的大小有限制而且有隱私問題。Cookies而且會在每一個請求中來回發送數據,徹底沒辦法發揮客戶端數據存儲的優點。

再來看下Local Storage本地存儲機制的特色。Local Storage在HTML 5中有不錯的支持,但就總的存儲量而言依然是有所限制的。Local Storage並不提供真正的「檢索API」,本地存儲的數據只是經過鍵值對去訪問。Local Storage對於一些特定的須要存儲數據的場景是很適合的,例如,用戶的喜愛習慣,而IndexedDB則更適合存儲如廣告等數據(它更象一個真正的數據庫)。

通常來講,有兩種不一樣類型的數據庫:關係型和文檔型(也稱爲NoSQL或對象)。關係數據庫如SQL Server,MySQL,Oracle的數據存儲在表中。文檔數據庫如MongoDB,CouchDB,Redis將數據集做爲個體對象存儲。IndexedDB是一個文檔數據庫,它在徹底內置於瀏覽器中的一個沙盒環境中(強制依照(瀏覽器)同源策略)。

對數據庫的每次操做,描述爲經過一個請求打開數據庫,訪問一個object store,再繼續。

打開數據庫的請求生命週期

這裏寫圖片描述

IndexedDB是否適合個人應用程序?

如今最關鍵的問題:「IndexedDB是否適合個人應用程序?「像往常同樣,答案是確定的:「視狀況而定。「首先當你試圖在客戶端保存數據時,你會考慮HTML5本地存儲。本地存儲獲得普遍瀏覽器的支持,有很是易於使用的API。簡單有其優點,但其劣勢是沒法支持複雜的搜索策略,存儲大量的數據,並提供事務支持。

IndexedDB是一個數據庫。因此,當你想爲客戶端作出決定,考慮你如何在服務端選擇一個持久化介質的數據庫。你可能會問本身一些問題來幫助決定客戶端數據庫是否適合您的應用程序,包括:

  • 你的用戶經過瀏覽器訪問您的應用程序,(瀏覽器)支持IndexedDB API嗎 ?
  • 你須要存儲大量的數據在客戶端?
  • 你須要在一個大型的數據集合中快速定位單個數據點?
  • 你的架構在客戶端須要事務支持嗎?

    若是你對其中的任何問題回答了「是的」,頗有可能,IndexedDB是你的應用程序的一個很好的候選。

IndexedDB用法

如今,你已經有機會熟悉了一些的總體概念,下一步是開始實現基於IndexedDB的應用程序。第一個步驟須要統一IndexedDB在不一樣瀏覽器的實現。您能夠很容易地添加各類廠商特性的選項的檢查,同時在window對象上把它們設置爲官方對象相同的名稱。下面的清單展現了window.indexedDB,window.IDBTransaction,window.IDBKeyRange的最終結果是如何都被更新,它們被設置爲相應的瀏覽器的特定實現。

window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

如今,每一個數據庫相關的全局對象持有正確的版本,應用程序能夠準備使用IndexedDB開始工做。

打開數據庫

// 打開咱們的數據庫,數據庫名稱,版本號 var request = indexedDB.open("MyTestDatabase", 3);
  • 1
  • 2

indexedDB的三個事件

//數據庫打開成功執行 request.onsuccess = function (event) { // Better use "this" than "req" to get the result to avoid problems with // garbage collection. // db = request.result; db = this.result; console.debug("initDb DONE"); }; //數據庫打開失敗執行 request.onerror = function (event) { console.error("initDb:", evt.target.errorCode); }; //在數據庫第一次被打開時或者當指定的版本號高於當前被持久化的數據庫的版本號時,觸發此事件,能夠在這個地方建立對象存儲空間結構,更新結構,加索引等. request.onupgradeneeded = function (event) { console.debug("initDb.onupgradeneeded"); var store = event.currentTarget.result.createObjectStore( DB_STORE_NAME, { keyPath: 'id', autoIncrement: true }); };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

添加數據或更新數據

// 咱們的客戶數據看起來像這樣。 const customerData = [ { ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" }, { ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" } ]; var transaction = db.transaction(["customers"], "readwrite"); // 當全部的數據都被增長到數據庫時執行一些操做 transaction.oncomplete = function(event) { alert("All done!"); }; transaction.onerror = function(event) { // 不要忘記進行錯誤處理! }; var objectStore = transaction.objectStore("customers"); for (var i in customerData) { var request = objectStore.add(customerData[i]); request.onsuccess = function(event) { // event.target.result == customerData[i].ssn }; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

刪除數據

var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .delete("444-44-4444"); request.onsuccess = function(event) { // 刪除數據成功! };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

獲取數據

var transaction = db.transaction(["customers"]); var objectStore = transaction.objectStore("customers"); var request = objectStore.get("444-44-4444"); request.onerror = function(event) { // 錯誤處理! }; request.onsuccess = function(event) { // 對 request.result 作些操做! alert("Name for SSN 444-44-4444 is " + request.result.name); };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

對於一個「簡單」的提取這裏的代碼有點多了。下面看咱們怎麼把它再縮短一點,假設你在數據庫的級別上來進行的錯誤處理:

db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess = function(event) { alert("Name for SSN 444-44-4444 is " + event.target.result.name); };
  • 1
  • 2
  • 3
  • 4

使用遊標獲取數據

使用 get() 要求你知道你想要檢索哪個鍵。若是你想要遍歷對象存儲空間中的全部值,那麼你能夠使用遊標。看起來會像下面這樣:

var customers = []; var objectStore = db.transaction("customers").objectStore("customers"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { customers.push(cursor.value); cursor.continue(); } else { alert("Got all customers: " + customers); } };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這裏有一個封裝好的完整的例子,簡化了這些操做。

<script type="text/javascript"> window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; (function(window){  'use strict'; var db = { version: 1, // important: only use whole numbers! objectStoreName: 'tasks', instance: {}, upgrade: function (e) { var _db = e.target.result, names = _db.objectStoreNames, name = db.objectStoreName; if (!names.contains(name)) { _db.createObjectStore( name, { keyPath: 'id', autoIncrement: true }); } }, errorHandler: function (error) { window.alert('error: ' + error.target.code); debugger; }, open: function (callback) { var request = window.indexedDB.open( db.objectStoreName, db.version); request.onerror = db.errorHandler; request.onupgradeneeded = db.upgrade; request.onsuccess = function (e) { db.instance = request.result; db.instance.onerror = db.errorHandler; callback(); }; }, getObjectStore: function (mode) { var txn, store; mode = mode || 'readonly'; txn = db.instance.transaction( [db.objectStoreName], mode); store = txn.objectStore( db.objectStoreName); return store; }, save: function (data, callback) { db.open(function () { var store, request, mode = 'readwrite'; store = db.getObjectStore(mode), request = data.id ? store.put(data) : store.add(data); request.onsuccess = callback; }); }, getAll: function (callback) { db.open(function () { var store = db.getObjectStore(), cursor = store.openCursor(), data = []; cursor.onsuccess = function (e) { var result = e.target.result; if (result && result !== null) { data.push(result.value); result.continue(); } else { callback(data); } }; }); }, get: function (id, callback) { id = parseInt(id); db.open(function () { var store = db.getObjectStore(), request = store.get(id); request.onsuccess = function (e){ callback(e.target.result); }; }); }, 'delete': function (id, callback) { id = parseInt(id); db.open(function () { var mode = 'readwrite', store, request; store = db.getObjectStore(mode); request = store.delete(id); request.onsuccess = callback; }); }, deleteAll: function (callback) { db.open(function () { var mode, store, request; mode = 'readwrite'; store = db.getObjectStore(mode); request = store.clear(); request.onsuccess = callback; }); } }; window.app = window.app || {}; window.app.db = db; }(window)); //將數據顯示在頁面上的方法 var bindData = function (data) { $("#IndexedDB").html(''); if(data.length === 0){ $("#IndexedDB").html("沒有數據"); return; } data.forEach(function (note) { $("#IndexedDB").append(note.id+","+note.title+","+note.text); }); }; //一個新數據 var note = { id:1, title: "數據1", text: "數據1的另外一個字段" }; //又一個新數據 var note2 = { id:2, title: "數據2", text: "數據2的另外一個字段" }; //插入或更新數據(insert or update) window.app.db.save(note,function() { //window.app.db.getAll(bindData); }); window.app.db.save(note2); //獲取數據 window.app.db.get(1,function(item) { //alert("window.app.db.get:"+item.id+","+item.title+","+item.text); }); //刪除數據 window.app.db.delete(1,function() { //alert("window.app.db.get:"+item.id+","+item.title+","+item.text); }); //刪除全部 window.app.db.deleteAll(function() { //alert("window.app.db.get:"+item.id+","+item.title+","+item.text); }); </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241

想對IndexedDB更多用法進行了解的能夠參考這兩篇文章。

https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB

http://web.jobbole.com/81793/


除了IndexedDB之外,還有一種已經被W3C放棄的Web SQL。

瀏覽器支持本地數據庫並非從IndexedDB纔開始實現,它是在Web SQL實現以後的一種新方法。相似IndexedDB,Web SQL是一個客戶端數據庫,但它做爲一個關係數據庫的實現,使用結構化查詢語言(SQL)與數據庫通訊。Web SQL的歷史充滿了曲折,但底線是沒有主流的瀏覽器廠商對Web SQL繼續支持。

若是Web SQL其實是一個廢棄的技術,爲何還要提它呢?有趣的是,Web SQL在瀏覽器裏獲得穩固的支持。Chrome, Safari, iOS Safari, and Android 瀏覽器都支持。另外,並非這些瀏覽器的最新版本才提供支持,許多這些最新最好的瀏覽器以前的版本也能夠支持。有趣的是,若是你爲Web SQL添加支持來支持IndexedDB,你忽然發現,許多瀏覽器廠商和版本成爲支持瀏覽器內置數據庫的某種化身。

所以,若是您的應用程序真正須要一個客戶端數據庫,你想要達到的最高級別的採用可能,當IndexedDB不可用時,也許您的應用程序可能看起來須要選擇使用Web SQL來支持客戶端數據架構。雖然文檔數據庫和關係數據庫管理數據有鮮明的差異,但只要你有正確的抽象,就能夠使用本地數據庫構建一個應用程序。

Web SQL的用法相似於操做SQLite數據庫,在這裏不展開介紹了。
想對Web SQL瞭解更多,能夠參考這篇文章:http://www.ibm.com/developerworks/cn/web/1210_jiangjj_html5db/

(4)文件接口(File API)

這裏寫圖片描述

在以前咱們操做本地文件都是使用flash、silverlight或者第三方的activeX插件等技術,因爲使用了這些技術後就很難進行跨平臺、或者跨瀏覽器、跨設備等狀況下實現統一的表現,從另一個角度來講就是讓咱們的web應用依賴了第三方的插件,而不是很獨立,不夠通用。在HTML5標準中,默認提供了操做文件的API讓這一切直接標準化。有了操做文件的API,讓咱們的Web應用能夠很輕鬆的經過JS來控制文件的讀取、寫入、文件夾、文件等一系列的操做。

先看一個demo。以前咱們操做一個圖片文件,都是先將圖片上傳到服務器端,而後再使用一個img標籤指向到服務器的url地址,而後再進行一個使用第三方插件進行圖片處理,而如今這一切都不須要服務器端了,由於FileReader對象提供的幾個讀取文件的方法變得異常簡單,並且所有是客戶端js的操做。

http://html5demos.com/file-api/

如今咱們本身來使用這些API。

先寫好咱們的HTML頁面。

<input type="file" multiple="multiple" name="fileDemo" id="fileDemo" /> <br /> <input type="button" value="獲取文件的名字" id="btnGetFile" /> <input type="button" value="readAsDataURL" id="readAsDataURL" onclick="showDataByURL();" /> <input type="button" value="readAsBinaryString" id="readAsBinaryString" onclick="showDataByBinaryString();" /> <input type="button" value="readAsText" id="readAsText" onclick="showDataByText();" /> <div id="result"></div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

獲取文件名

$("#btnGetFile").click(function(e) { var fileList = document.getElementById("fileDemo").files; for (var i = 0; i < fileList.length; i++) { if (!(/image\/\w+/.test(fileList[i].type))) { $("#result").append("<span>type:" + fileList[i].type + "--******非圖片類型*****--name:" + fileList[i].name + "--size:" + fileList[i].size + "</span><br />"); } else { $("#result").append("<span>type:" + fileList[i].type + "--name:" + fileList[i].name + "--size:" + fileList[i].size + "</span><br />"); } } });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

readAsDataURL()

開始讀取指定的Blob對象或File對象中的內容. 當讀取操做完成時,readyState屬性的值會成爲DONE,若是設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容.

這個方法頗有用,好比,能夠實現圖片的本地預覽.

function showDataByURL() { var resultFile = document.getElementById("fileDemo").files[0]; if (resultFile) { var reader = new FileReader(); reader.readAsDataURL(resultFile); reader.onload = function(e) { var urlData = this.result; document.getElementById("result").innerHTML += "<img src='" + urlData + "' alt='" + resultFile.name + "' />"; }; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

readAsBinaryString()

開始讀取指定的Blob對象或File對象中的內容. 當讀取操做完成時,readyState屬性的值會成爲DONE,若是設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含所讀取文件的原始二進制數據.

function showDataByBinaryString() { var resultFile = document.getElementById("fileDemo").files[0]; if (resultFile) { var reader = new FileReader(); //異步方式,不會影響主線程 reader.readAsBinaryString(resultFile); reader.onload = function(e) { var urlData = this.result; document.getElementById("result").innerHTML += urlData; }; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

readAsText()

開始讀取指定的Blob對象或File對象中的內容. 當讀取操做完成時,readyState屬性的值會成爲DONE,若是設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個字符串以表示所讀取的文件內容.

function showDataByText() { var resultFile = document.getElementById("fileDemo").files[0]; if (resultFile) { var reader = new FileReader(); reader.readAsText(resultFile, 'gb2312'); reader.onload = function(e) { var urlData = this.result; document.getElementById("result").innerHTML += urlData; }; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

事件處理程序

onabort
當讀取操做被停止時調用.
onerror
當讀取操做發生錯誤時調用.
onload
當讀取操做成功完成時調用.
onloadend
當讀取操做完成時調用,無論是成功仍是失敗.該處理程序在onload或者onerror以後調用.
onloadstart
當讀取操做將要開始以前調用.
onprogress
在讀取數據過程當中週期性調用.


在文件上傳時,HTML5還支持拖拽功能。

這裏寫圖片描述

<div id="holder"></div> var holder = document.getElementById('holder'); holder.ondrop = function (e) { e.preventDefault(); var file = e.dataTransfer.files[0], reader = new FileReader(); reader.onload = function (event) { console.log(event.target); holder.style.background = 'url(' + event.target.result + ') no-repeat center'; }; console.log(file); reader.readAsDataURL(file); return false; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

想對HTML5文件接口操做文件瞭解更多請參考下面的文章:

https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications

https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader

http://blog.csdn.net/testcs_dn/article/details/8695532

http://www.cnblogs.com/fly_dragon/archive/2012/06/02/2532035.html

③ 設備訪問特性 (DEVICE ACCESS)

這裏寫圖片描述

來一段W3C對這個特性的介紹。

Beginning with the Geolocation API, Web Applications can present rich, device-aware features and experiences. Incredible device access innovations are being developed and implemented, from audio/video input access to microphones and cameras, to local data such as contacts & events, and even tilt orientation.

大體包含 地理位置API媒體訪問API訪問聯繫人及事件設備方向

下面分別進行研究。

(1)地理位置API(Geolocation API)

這裏寫圖片描述

HTML5 Geolocation API 用於得到用戶的地理位置。
鑑於該特性可能侵犯用戶的隱私,除非用戶贊成,不然用戶位置信息是不可用的。通常網頁在調用此信息時,會彈出權限申請窗口。

先上Demo:http://www.w3school.com.cn/tiy/t.asp?f=html5_geolocation_error

若是電腦獲取不到位置信息的話,就在手機上試一下吧。

getCurrentPosition()

getCurrentPosition() 方法來得到用戶的位置。

標準用法以下:

<script> var x=document.getElementById("demo"); function getLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition); } else { x.innerHTML="Geolocation is not supported by this browser."; } } function showPosition(position) { x.innerHTML="Latitude: " + position.coords.latitude + "<br />Longitude: " + position.coords.longitude; } </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

-檢測是否支持地理定位
-若是支持,則運行 getCurrentPosition() 方法。若是不支持,則向用戶顯示一段消息。
-若是getCurrentPosition()運行成功,則向參數showPosition中規定的函數返回一個coordinates對象
-showPosition() 函數得到並顯示經度和緯度

上面的例子是一個很是基礎的地理定位腳本,不含錯誤處理。

完整的處理應該是這樣的.

<script> var x = document.getElementById("demo"); function getLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition, showError); } else { x.innerHTML = "Geolocation is not supported by this browser."; } } function showPosition(position) { x.innerHTML = "Latitude: " + position.coords.latitude + "<br />Longitude: " + position.coords.longitude; } function showError(error) { switch (error.code) { case error.PERMISSION_DENIED: x.innerHTML = "User denied the request for Geolocation." break; case error.POSITION_UNAVAILABLE: x.innerHTML = "Location information is unavailable." break; case error.TIMEOUT: x.innerHTML = "The request to get user location timed out." break; case error.UNKNOWN_ERROR: x.innerHTML = "An unknown error occurred." break; } } </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

錯誤代碼:
-Permission denied - 用戶不容許地理定位
-Position unavailable - 沒法獲取當前位置
-Timeout - 操做超時
-Unknown error - 未知錯誤

若是想對地理位置API瞭解更多,能夠參考這個網址。http://www.w3school.com.cn/html5/html_5_geolocation.asp

(2)媒體訪問API(media API)

這裏寫圖片描述

先上demo。麥克風和攝像頭也涉及到用戶隱私,因此瀏覽器會向用戶申請訪問權限。

https://www.ganecheng.tech/html5/media.html

getUserMedia()

以上的效果,都是經過getUserMedia()方法實現的。

<video id="video" autoplay="autoplay" style='width: 640px; height: 480px'></video> <button id='picture'>PICTURE</button> <canvas id="canvas" width="640" height="480"></canvas>
  • 1
  • 2
  • 3
var video = document.getElementById("video"); var context = canvas.getContext("2d"); var errocb = function(code) { console.log(code); }; if (navigator.getUserMedia) { // 標準的API navigator.getUserMedia( { "video" : true }, function(stream) { video.src = stream; video.play(); }, errocb); } else if (navigator.webkitGetUserMedia) { // WebKit 核心的API console.log(navigator.webkitGetUserMedia); navigator.webkitGetUserMedia( { "video" : true }, function(stream) { video.src = window.webkitURL.createObjectURL(stream); video.play(); }, errocb); } // 將拍好的照片顯示在畫布上 document.getElementById("picture").addEventListener("click", function() { context.drawImage(video, 0, 0, 640, 480); });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

視頻獲取就是這個樣子,音頻獲取添加"audio" : true便可。

想對媒體API瞭解更多,參考文章:http://blog.csdn.net/u010359143/article/details/50326981

http://blog.csdn.net/renfufei/article/details/21168239

http://www.jb51.net/html5/81028.html

(3)聯繫人管理API(Contacts Manager API)

這個純屬於W3C的美好設想,尚未正式歸入標準。目前沒有搜到靠譜的資料。

當初的提議能夠參考這裏。http://contacts-manager-api.sysapps.org/

可是有兩個相似的變通實現。

FirefoxOS(已結束生命)示例代碼。

var request = window.navigator.contacts.getAll(); var count = 0; request.onsuccess = function () { if(this.result) { count++; // Display the name of the contact console.log(this.result.givenName + ' ' + this.result.familyName); // Move to the next contact which will call the request.onsuccess with a new result this.continue(); } else { console.log(count + 'contacts found.'); } } request.onerror = function () {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

想要對這個已無生命氣息的web操做系統瞭解更多的參考這裏 https://developer.mozilla.org/en-US/docs/Mozilla/B2G_OS/API/ContactManager

Cordova(Hybrid App)實現方式參考這裏https://cordova.apache.org/docs/en/3.0.0/cordova/contacts/contacts.html

(4)設備方向和運動API(DeviceOrientation & DeviceMotion API)

這裏寫圖片描述

DeviceOrientation經常使用於檢測重力感應方向,DeviceMotion經常使用於搖一搖功能。

① DeviceOrientation

重力感應也是原生APP中常常見到的一個功能,在Web App中的應用多見於判斷屏幕的旋轉方向,以及在此基礎上實現的場景應用,如控制頁面上物體的左右移動,加減速等。

在Web App中實現以上的功能,須要實時獲取屏幕的旋轉方向參數,這些參數能夠從瀏覽器的利用HTML5的DeviceOrientation API得到。

當瀏覽器的Orientation發生變化時,觸發DeviceOrientation事件,並返回一個DeviceOrientationEvent對象,其屬性列表以下:

屬性 釋義
alpha 設備指示的方向,根據指南針的設定狀況而定
beta 設備繞x軸旋轉的角度
gamma 設備繞y軸旋轉的角度

注:不一樣版本的手機操做系統和瀏覽器,以及不一樣的應用程序中內置的瀏覽器對deviceorientation事件的支持不盡相同。尤爲在Android平臺上,可能會出現有的設備正常工做,有的則毫無反應的狀況。

工做原理

根據event對象的三個方向的參數來肯定設備的旋轉角度。其中,alpha的取值範圍是0-360,這個須要根據設備的指南針設定狀況而定,通常來講,設備指向正北方向時爲0.beta值爲設備繞x軸旋轉的角度,取值範圍爲-180-180。gamma取值範圍-90-90.

這裏面alpha值的意義並不大,主要參考beta和gamma值。
當屏幕從水平沿y軸向左傾斜時gamma值變爲負值,向右傾斜變爲正值。
檔屏幕從水平沿x軸向前傾斜時beta值變爲正值,向後傾斜時變爲負值。
因此,若是咱們設定一個閾值,當beta和gamma的絕對值大於這個閾值時,咱們就認爲設備發生了旋轉。另外根據beta和gamma的值來判斷向左傾斜仍是向右傾斜,以及傾斜的程度。

實現方式和示例

首先是爲瀏覽器綁定deviceorientation事件和處理程序。

//add deviceorientation event listener if(window.DeviceOrientationEvent) { window.addEventListener('deviceorientation',DeviceOrientationHandler,false); }else { alert("您的瀏覽器不支持DeviceOrientation"); } function DeviceOrientationHandler(event) { var alpha = event.alpha, beta = event.beta, gamma = event.gamma; if(alpha != null || beta != null || gamma != null) { dataContainerOrientation.innerHTML = "alpha:" + alpha + "<br />beta:" + beta + "<br />gamma:" + gamma; //判斷屏幕方向 var html = ""; if( Math.abs(gamma) < GAMMA_MIN && Math.abs(beta) > BETA_MAX ){ html = "屏幕方向:Portrait"; } if( Math.abs(beta) < BETA_MIN && Math.abs(gamma) > GAMMA_MAX ){ html = "屏幕方向:Landscape"; } var gamma_html = ""; if( gamma > 0 ){ gamma_html = "向右傾斜"; }else{ gamma_html = "向左傾斜"; } html += "<br />"+gamma_html stage.innerHTML = html; }else { dataContainerOrientation.innerHTML = "當前瀏覽器不支持DeviceOrientation"; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

這個示例中展現瞭如何利用beta和gamma值來展現屏幕的旋轉方向和側翻方向。要實現更精確的物體判斷,還須要複雜的算法來計算。

擴展應用

使用DeviceOrientation API接口能夠實如今web中獲取手機設備的屏幕旋轉方向參數,在示例的基礎上進行改進,能夠擴展到在屏幕上控制頁面元素的移動,實現動畫或遊戲的目的。例如經過調整屏幕的方向控制頁面上的小球走迷宮,控制小車的移動躲避障礙等。

② DeviceMotion

搖一搖功能是不少原生APP均可以實現的功能,如微信中的搖一搖找好友,QQ音樂中的搖一搖換歌等。它們都是利用了手機加速傳感器提供的API,當監聽到手機加速變化的事件時,根據獲取的加速值來執行不一樣的動做。

在Web APP中HTML5 也提供了相似的接口,就是DeviceMotionEvent。DeviceMotion封裝了運動傳感器數據的事件,能夠獲取手機運動狀態下的運動加速度等數據。

DeviceMotionEvent對象屬性列表:

屬性 釋義
event.accelaration x(y,z):設備在x(y,z)方向上的移動加速度值
event.accelarationIncludingGravity x(y,z):考慮了重力加速度後設備在x(y,z)方向上的移動加速度值
event.rotationRate alpha,beta,gamma:設備繞x,y,z軸旋轉的角度

event.accelarationIncludingGravity與event.accelaration的區別在於前者加入了重力加速度,即在z軸方向加了9.8,在x,y方向上的值二者相同。

旋轉速度rotationRate:alpha、beta、gamma的概念與DeviceOrientationEvent一致。
區別在於:
DeviceOrientationEvent的值是相對於初始狀態的差值,只要設備方向不變,怎麼動都不會影響數值;
DeviceMotionEvent是相對於以前的某個瞬間值的差值時間比,即變化的速度,一旦設備靜止則會恢復爲0。

實現搖一搖

function Shake(threshold, callback) { //定義閾值 this.SHAKE_THRESHOLD = threshold ? threshold : 2000; this.last_update = 0; this.x = this.y = this.z = this.last_x = this.last_y = this.last_z = 0; this.init = function() { if (window.DeviceMotionEvent) { window.addEventListener('devicemotion', this.deviceMotionHandler, false); } else { alert('您的瀏覽器不支持DeviceMotion'); } }; var that = this; this.deviceMotionHandler = function(eventData) { var acceleration = eventData.accelerationIncludingGravity; var curTime = new Date().getTime(); if ((curTime - that.last_update) > 100) { var diffTime = curTime - that.last_update; that.last_update = curTime; that.x = acceleration.x; that.y = acceleration.y; that.z = acceleration.z; var speed = Math.abs(that.x + that.y + that.z - that.last_x - that.last_y - that.last_z) / diffTime * 10000; if (speed > that.SHAKE_THRESHOLD) { if (window.console && console.log) { console.log("shaked"); } if (callback != undefined) { callback(that); } } that.last_x = that.x; that.last_y = that.y; that.last_z = that.z; } } }; window.onload = function() { var shake1 = new Shake(2000, function(obj) { alert("shaked"); var r = document.getElementById("result"); r.innerHTML = "x:" + obj.x + ""; r.innerHTML += "y:" + obj.y + ""; r.innerHTML += "z:" + obj.z + ""; }); shake1.init(); };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

設備方向和運動API涉及到一些數學知識。想要對這一API瞭解更多,能夠參考下面兩篇文章。

http://www.jianshu.com/p/5769075e9885

http://w3c.github.io/deviceorientation/spec-source-orientation.html

④ 鏈接特性(CONNECTIVITY)

這裏寫圖片描述

先看W3C的定義。

More efficient connectivity means more real-time chats, faster games, and better communication. Web Sockets and Server-Sent Events are pushing (pun intended) data between client and server more efficiently than ever before.

HTTP是無鏈接的,一次請求,一次響應。想要實現微信網頁版掃一掃登陸,網頁版微信聊天的功能,須要使用輪詢的方式達到長鏈接的效果,輪詢的大部分時間是在作無用功,浪費網絡,浪費資源。如今HTML5爲咱們帶來了更高效的鏈接方案 Web SocketsServer-Sent Events

下面對這兩種鏈接方式分別進行研究。

(1)網頁Sockets(Web Sockets)

這裏寫圖片描述

運行原理

這裏寫圖片描述

瀏覽器端示例

var wsServer = 'ws://localhost:8888/Demo'; //服務器地址 var websocket = new WebSocket(wsServer); //建立WebSocket對象 websocket.send("hello");//向服務器發送消息 alert(websocket.readyState);//查看websocket當前狀態 websocket.onopen = function (evt) { //已經創建鏈接 }; websocket.onclose = function (evt) { //已經關閉鏈接 }; websocket.onmessage = function (evt) { //收到服務器消息,使用evt.data提取 }; websocket.onerror = function (evt) { //產生異常 }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

服務器端

握手協議的客戶端數據已經由瀏覽器代勞了,服務器端須要咱們本身來實現,目前市場上開源的實現也比較多如:

Kaazing WebSocket Gateway(一個 Java 實現的 WebSocket Server);
mod_pywebsocket(一個 Python 實現的 WebSocket Server);
Netty(一個 Java 實現的網絡框架其中包括了對 WebSocket 的支持);
node.js(一個 Server 端的 JavaScript 框架提供了對 WebSocket 的支持);
WebSocket4Net(一個.net的服務器端實現);

其實在目前的.net4.5框架中已經實現了WebSocket,不用官方實現,咱們本身來寫個簡單的。服務器端須要根據協議來握手、接收和發送。

握手

/// <summary> /// 生成Sec-WebSocket-Accept /// </summary> /// <param name="handShakeText">客戶端握手信息</param> /// <returns>Sec-WebSocket-Accept</returns> private static string GetSecKeyAccetp(byte[] handShakeBytes,int bytesLength) { string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength); string key = string.Empty; Regex r = new Regex(@"Sec-WebSocket-Key:(.*?)rn"); Match m = r.Match(handShakeText); if (m.Groups.Count != 0) { key = Regex.Replace(m.Value, @"Sec-WebSocket-Key:(.*?)rn", "$1").Trim(); } byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); return Convert.ToBase64String(encryptionString); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

若是握手成功,將會觸發客戶端的onopen事件。

解析接收的客戶端信息

/// <summary> /// 解析客戶端數據包 /// </summary> /// <param name="recBytes">服務器接收的數據包</param> /// <param name="recByteLength">有效數據長度</param> /// <returns></returns> private static string AnalyticData(byte[] recBytes, int recByteLength) { if (recByteLength < 2) { return string.Empty; } bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最後一幀 if (!fin){ return string.Empty;// 超過一幀暫不處理 } bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩碼 if (!mask_flag){ return string.Empty;// 不包含掩碼的暫不處理 } int payload_len = recBytes[1] & 0x7F; // 數據長度 byte[] masks = new byte[4]; byte[] payload_data; if (payload_len == 126) { Array.Copy(recBytes, 4, masks, 0, 4); payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]); payload_data = new byte[payload_len]; Array.Copy(recBytes, 8, payload_data, 0, payload_len); } else if (payload_len == 127) { Array.Copy(recBytes, 10, masks, 0, 4); byte[] uInt64Bytes = new byte[8]; for (int i = 0; i < 8; i++) { uInt64Bytes[i] = recBytes[9 - i]; } UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); payload_data = new byte[len]; for (UInt64 i = 0; i < len; i++) { payload_data[i] = recBytes[i + 14]; } }else { Array.Copy(recBytes, 2, masks, 0, 4); payload_data = new byte[payload_len]; Array.Copy(recBytes, 6, payload_data, 0, payload_len); } for (var i = 0; i < payload_len; i++) { payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]); } return Encoding.UTF8.GetString(payload_data); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

發送數據至客戶端

/// <summary> /// 打包服務器數據 /// </summary> /// <param name="message">數據</param> /// <returns>數據包</returns> private static byte[] PackData(string message) { byte[] contentBytes = null; byte[] temp = Encoding.UTF8.GetBytes(message); if (temp.Length < 126) { contentBytes = new byte[temp.Length + 2]; contentBytes[0] = 0x81; contentBytes[1] = (byte)temp.Length; Array.Copy(temp, 0, contentBytes, 2, temp.Length); }else if (temp.Length < 0xFFFF) { contentBytes = new byte[temp.Length + 4]; contentBytes[0] = 0x81; contentBytes[1] = 126; contentBytes[2] = (byte)(temp.Length & 0xFF); contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF); Array.Copy(temp, 0, contentBytes, 4, temp.Length); }else { // 暫不處理超長內容 } return contentBytes; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Web Sockets 是一個很是棒的設計,想要了解更多,參考這裏。

http://www.javashuo.com/article/p-zfliclhu-kc.html

(2)服務器發送事件(Server-Sent Events)

這裏寫圖片描述

運行原理

這裏寫圖片描述

瀏覽器經過HTTP向服務器發送請求,服務器端拿出數據庫中的最新的信息,當即返回給客戶端,客戶端等待三秒後再次發出下一個請求。

客戶端示例

<script> if(typeof(EventSource)!=="undefined") { var source=new EventSource("/example/html5/demo_sse.php"); source.onmessage=function(event) { document.getElementById("result").innerHTML+=event.data + "<br />"; }; } else { document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events..."; } </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

服務器端示例

<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); $time = date('r'); echo "data: The server time is: {$time}\n\n"; flush(); ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

想要對Server-Sent Events瞭解更多的,能夠參考這兩篇文章。

http://www.w3school.com.cn/html5/html_5_serversentevents.asp

http://www.ibm.com/developerworks/cn/web/1307_chengfu_serversentevent/


服務器負載

-Long-polling佔一小部分CPU資源,可是建立空的進程將浪費系統的內存
-Server-Sent Events工做的方式有不少,除非Server-Sent Events沒必要在每一次響應發出後都關閉鏈接。
-WebSockets,服務器只須要一個進程處理全部的請求,沒有循環,沒必要爲每一個客戶端都分配cpu和內存。

客戶端負載

-Long-polling取決於實現方式,但終究是一個異步的方式
-Server-Sent Events採用瀏覽器的內置的實現方式,只花費不多的一部分資源。
-WebSockets跟Server-Sent Events同樣,採用瀏覽器的內置的實現方式,只花費不多的一部分資源。

時間線

-Long-polling接近實時,可是發送新的請求和發送相應會有必定的時延。
-Server-Sent Events默認延時3秒,可是能夠調整。
-WebSockets真正的實時

實現方式複雜度

-Long-polling實現起來很是簡單
-Server-Sent Events甚至比Long-polling更簡單
-須要一個WebSockets服務器處理事件,並開放一個端口


想要對輪詢,Web Sockets,Server-Sent Events三者的區別有所瞭解的,能夠參考這篇文章。

https://www.oschina.net/question/82993_63312

⑤ 網頁多媒體特性(MULTIMEDIA)

這裏寫圖片描述

看一下W3C的定義。

Audio and video are first class citizens in the HTML5 web, living in harmony with your apps and sites. Lights, camera, action!

看的出來HTML5原生支持音視頻讓W3C很興奮。也是廣大開發者多年的期待。終於能夠將Flash踹入茅坑了。

Audio 和 Video 標籤

這裏寫圖片描述

這裏寫圖片描述

雖然支持音視頻很強大,可是確實沒有什麼好說的,就是兩個標籤。

<audio controls="controls"> <source src="song.ogg" type="audio/ogg"> <source src="song.mp3" type="audio/mpeg"> Your browser does not support the audio tag. </audio>
  • 1
  • 2
  • 3
  • 4
  • 5
<video width="320" height="240" controls="controls"> <source src="movie.ogg" type="video/ogg"> <source src="movie.mp4" type="video/mp4"> Your browser does not support the video tag. </video>
  • 1
  • 2
  • 3
  • 4
  • 5

可是因爲音視頻相對於其餘新特性來講會被更多的使用,各個瀏覽器的兼容問題應該引發開發者的重視。統一各平臺的播放器ckplayer值得借鑑。能夠參考此網頁http://www.ckplayer.com/

Audio API

這裏寫圖片描述

HTML5 音頻處理接口與Audio標籤是不同的。頁面上的Audio標籤只是HTML5更語義化的一個表現,而HTML5提供給JavaScript編程用的Audio API則讓咱們有能力在代碼中直接操做原始的音頻流數據,對其進行任意加工再造。

先上demo,http://wayou.github.io/HTML5_Audio_Visualizer/,打開頁面以後,打開一首本地歌曲。而後能夠顯示可視化效果。

原理

一段音頻到達揚聲器進行播放以前,半路對其進行攔截,因而咱們就獲得了音頻數據了,這個攔截工做是由window.AudioContext來作的,咱們全部對音頻的操做都基於這個對象。經過AudioContext能夠建立不一樣各種的AudioNode,即音頻節點,不一樣節點做用不一樣,有的對音頻加上濾鏡好比提升音色(好比BiquadFilterNode),改變單調,有的音頻進行分割,好比將音源中的聲道分割出來獲得左右聲道的聲音(ChannelSplitterNode),有的對音頻數據進行頻譜分析。

全部的操做都是基於AudioContext這個對象進行的。

獲得AudioContext對象。

window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; try { var audioContext = new window.AudioContext(); } catch (e) { Console.log('!Your browser does not support AudioContext'); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

後續的操做,都是與音頻解碼相關的。想要了解更多HTML5 Audio API。能夠參考下面的文章。

http://www.cnblogs.com/Wayou/p/3543577.html

https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext

搜索了一下,並無找到與Audio API這麼強大的功能同一級別的Video API。

⑥ 三維、圖形及特效特性(3D, Graphics & Effects)

這裏寫圖片描述

來看W3C的介紹。

Between SVG, Canvas, WebGL, and CSS3 3D features, you’re sure to amaze your users with stunning visuals natively rendered in the browser.

大體包含SVG, Canvas, WebGL, 和 CSS3 3D,下面分別進行研究。

(1)可縮放矢量圖形(SVG)

這裏寫圖片描述

SVG是用於描述二維矢量圖形的一種圖形格式。

先上demo,http://www.ganecheng.tech/html5/svg.html

與其餘圖像格式相比,使用 SVG 的優點在於:
-SVG 可被很是多的工具讀取和修改(好比記事本)
-SVG 與 JPEG 和 GIF 圖像比起來,尺寸更小,且可壓縮性更強。
-SVG 是可伸縮的
-SVG 圖像可在任何的分辨率下被高質量地打印
-SVG 可在圖像質量不降低的狀況下被放大
-SVG 圖像中的文本是可選的,同時也是可搜索的(很適合製做地圖)
-SVG 能夠與 Java 技術一塊兒運行
-SVG 是開放的標準
-SVG 文件是純粹的 XML

SVG有三種用法。

① 把SVG直接當成圖片放在網頁上

<img style="width: 250px;" alt="kiwi" src="./kiwi.svg">
  • 1

② SVG動畫

畫一個五角星

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="190"> <polygon points="100,10 40,180 190,60 10,60 160,180" style="fill:red;stroke:blue;stroke-width:3;fill-rule:evenodd;" /> </svg>
  • 1
  • 2
  • 3
  • 4

③ SVG圖片的交互和濾鏡效果

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174" xml:space="preserve" class="logo99"> <style> .kiwi { fill: #94d31b; // stroke: #909; // stroke-width: 10; // not sure which of these is correct // stroke-linejoin : butt | round | square; // stroke-linecap: butt| round| square; // stroke-dasharray: 5, 5, 10; // filter: url(#pictureFilter); // mask: url(#f1); // clip-path: url(); } .kiwi:hover { fill: #ace63c; } .ground { fill: #787f6a; } .ground:hover { filter: url(#pictureFilter); fill: #896d3d; } </style> <ellipse class="ground" cx="283.5" cy="487.5" rx="259" ry="80"></ellipse> <path class="kiwi" d="M210.333,65.331C104.367,66.105-12.349,150.637,1.056,276.449c4.303,40.393,18.533,63.704,52.171,79.03 c36.307,16.544,57.022,54.556,50.406,112.954c-9.935,4.88-17.405,11.031-19.132,20.015c7.531-0.17,14.943-0.312,22.59,4.341 c20.333,12.375,31.296,27.363,42.979,51.72c1.714,3.572,8.192,2.849,8.312-3.078c0.17-8.467-1.856-17.454-5.226-26.933 c-2.955-8.313,3.059-7.985,6.917-6.106c6.399,3.115,16.334,9.43,30.39,13.098c5.392,1.407,5.995-3.877,5.224-6.991 c-1.864-7.522-11.009-10.862-24.519-19.229c-4.82-2.984-0.927-9.736,5.168-8.351l20.234,2.415c3.359,0.763,4.555-6.114,0.882-7.875 c-14.198-6.804-28.897-10.098-53.864-7.799c-11.617-29.265-29.811-61.617-15.674-81.681c12.639-17.938,31.216-20.74,39.147,43.489 c-5.002,3.107-11.215,5.031-11.332,13.024c7.201-2.845,11.207-1.399,14.791,0c17.912,6.998,35.462,21.826,52.982,37.309 c3.739,3.303,8.413-1.718,6.991-6.034c-2.138-6.494-8.053-10.659-14.791-20.016c-3.239-4.495,5.03-7.045,10.886-6.876 c13.849,0.396,22.886,8.268,35.177,11.218c4.483,1.076,9.741-1.964,6.917-6.917c-3.472-6.085-13.015-9.124-19.18-13.413 c-4.357-3.029-3.025-7.132,2.697-6.602c3.905,0.361,8.478,2.271,13.908,1.767c9.946-0.925,7.717-7.169-0.883-9.566 c-19.036-5.304-39.891-6.311-61.665-5.225c-43.837-8.358-31.554-84.887,0-90.363c29.571-5.132,62.966-13.339,99.928-32.156 c32.668-5.429,64.835-12.446,92.939-33.85c48.106-14.469,111.903,16.113,204.241,149.695c3.926,5.681,15.819,9.94,9.524-6.351 c-15.893-41.125-68.176-93.328-92.13-132.085c-24.581-39.774-14.34-61.243-39.957-91.247 c-21.326-24.978-47.502-25.803-77.339-17.365c-23.461,6.634-39.234-7.117-52.98-31.273C318.42,87.525,265.838,64.927,210.333,65.331 z M445.731,203.01c6.12,0,11.112,4.919,11.112,11.038c0,6.119-4.994,11.111-11.112,11.111s-11.038-4.994-11.038-11.111 C434.693,207.929,439.613,203.01,445.731,203.01z"> </path> <filter id="pictureFilter"> <feGaussianBlur stdDeviation="15"></feGaussianBlur> </filter> </svg>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

如何用SVG畫出一條會動的線

先看demo,http://www.ganecheng.tech/html5/svg_animate_line.html

<path fill="none" stroke="deeppink" stroke-width="14" stroke-miterlimit="0" d="M11.6 269s-19.7-42.4 6.06-68.2 48.5-6.06 59.1 12.1l-3.03 28.8 209-227s45.5-21.2 60.6 1.52c15.2 22.7-3.03 47-3.03 47l-225 229s33.1-12 48.5 7.58c50 63.6-50 97-62.1 37.9" stroke-dasharray="988.0 988.0" stroke-dashoffset="988.0" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
var path = document.querySelector('.squiggle-animated path'); var length = path.getTotalLength(); // 清除以前的動做 path.style.transition = path.style.WebkitTransition = 'none'; // 設置起始點 path.style.strokeDasharray = length + ' ' + length; path.style.strokeDashoffset = length; // 獲取一個區域,獲取相關的樣式,讓瀏覽器尋找一個起始點。 path.getBoundingClientRect(); // 定義動做 path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 2s ease-in-out'; // Go! path.style.strokeDashoffset = '0';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

原理:使用d屬性獲得一條貝塞爾曲線,使每段線段間距值爲線段的1倍長度,慢慢下降偏移值,獲得正向的移動效果。

屬性stroke-dasharray是讓你指定畫出的線段每段的長度,第二個值是各段之間空隙的長度。
屬性stroke-dashoffset是讓你指定每一個小段的起始偏移量。

想對SVG瞭解更多的,能夠參考下面的網址。

http://www.w3school.com.cn/svg/svg_examples.asp

http://www.w3school.com.cn/svg/svg_reference.asp

http://www.webhek.com/svg

http://www.webhek.com/animated-line-drawing-in-svg/

http://www.webhek.com/demo/svg/

(2)畫布(Canvas)

這裏寫圖片描述

Canvas也是前端工程師炫技的最熱門的陣地。有許多demo。

http://www.17sucai.com/pins/demoshow/9386
http://www.17sucai.com/pins/demoshow/12676
http://www.17sucai.com/pins/demoshow/5937
http://www.html5tricks.com/demo/html5-canvas-waterful/index.html
http://www.html5tricks.com/demo/html5-canvas-loader/index.html
http://www.html5tricks.com/demo/html5-canvas-particle-effect/index.html
http://www.html5tricks.com/demo/html5-cool-fire-effect/index.html

HTML5 的 canvas 元素使用 JavaScript 在網頁上繪製圖像。
畫布是一個矩形區域,您能夠控制其每一像素。
canvas 擁有多種繪製路徑、矩形、圓形、字符以及添加圖像的方法。

建立 Canvas 元素

<canvas id="myCanvas" width="200" height="100"></canvas>
  • 1

經過 JavaScript 來繪製

canvas 元素自己是沒有繪圖能力的。全部的繪製工做必須在 JavaScript 內部完成:

<script type="text/javascript"> var c=document.getElementById("myCanvas"); var cxt=c.getContext("2d"); cxt.fillStyle="#FF0000"; cxt.fillRect(0,0,150,75); </script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Canvas 與 SVG 對比

Canvas 和 SVG 都容許您在瀏覽器中建立圖形,可是它們在根本上是不一樣的。

SVG

SVG 是一種使用 XML 描述 2D 圖形的語言。
SVG 基於 XML,這意味着 SVG DOM 中的每一個元素都是可用的。您能夠爲某個元素附加 JavaScript 事件處理器。
在 SVG 中,每一個被繪製的圖形均被視爲對象。若是 SVG 對象的屬性發生變化,那麼瀏覽器可以自動重現圖形。

Canvas

Canvas 經過 JavaScript 來繪製 2D 圖形。
Canvas 是逐像素進行渲染的。
在 canvas 中,一旦圖形被繪製完成,它就不會繼續獲得瀏覽器的關注。若是其位置發生變化,那麼整個場景也須要從新繪製,包括任何或許已被圖形覆蓋的對象。

Canvas 與 SVG 的比較

Canvas
-依賴分辨率
-不支持事件處理器
-弱的文本渲染能力
-可以以 .png 或 .jpg 格式保存結果圖像
-最適合圖像密集型的遊戲,其中的許多對象會被頻繁重繪

SVG
-不依賴分辨率
-支持事件處理器
-最適合帶有大型渲染區域的應用程序(好比谷歌地圖)
-複雜度高會減慢渲染速度(任何過分使用 DOM 的應用都不快)
-不適合遊戲應用

想對Canvas瞭解更多的,能夠參考下面連接。

http://www.w3school.com.cn/html/html5_canvas.asp

http://www.w3school.com.cn/tags/html_ref_canvas.asp

https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API

http://blog.csdn.net/clh604/article/details/8536059

(3)網頁圖形庫(WebGL)

這裏寫圖片描述

先上demo。

https://www.cubeslam.com/ncokau

http://labs.gooengine.com/pearl-boy/indexBelow.html

http://www.cnblogs.com/lhb25/p/9-mind-blowing-webgl-demos.html

http://www.open-open.com/news/view/9d8136/

http://www.oschina.net/news/26547/webgl-chrome/

WebGL(全寫Web Graphics Library)是一種3D繪圖標準,這種繪圖技術標準容許把JavaScript和OpenGL ES 2.0結合在一塊兒,經過增長OpenGL ES 2.0的一個JavaScript綁定,WebGL能夠爲HTML5 Canvas提供硬件3D加速渲染,這樣Web開發人員就能夠藉助系統顯卡來在瀏覽器裏更流暢地展現3D場景和模型了,還能建立複雜的導航和數據視覺化。顯然,WebGL技術標準免去了開發網頁專用渲染插件的麻煩,可被用於建立具備複雜3D結構的網站頁面,甚至能夠用來設計3D網頁遊戲等等。

WebGL 基本原理

WebGL 的出現使得在瀏覽器上面實時顯示 3D 圖像成爲現實,WebGL 本質上是基於光柵化的 API ,而不是基於 3D 的 API。

WebGL對象獲取

WebGL也是基於Canvas畫布作的,下面看一下WebGL獲取方法。

// Get A WebGL context var canvas = document.getElementById("canvas"); var gl = canvas.getContext("experimental-webgl");
  • 1
  • 2
  • 3

WebGL 只關注兩個方面,即投影矩陣的座標和投影矩陣的顏色。使用 WebGL 程序的任務就是實現具備投影矩陣座標和顏色的 WebGL 對象便可。能夠使用「着色器」來完成上述任務。頂點着色器能夠提供投影矩陣的座標,片斷着色器能夠提供投影矩陣的顏色。

不管要實現的圖形尺寸有多大,其投影矩陣的座標的範圍始終是從 -1 到 1 。下面是一個關於實現 WebGL 對象的一個簡單例子。

// Get A WebGL context
var canvas = document.getElementById("canvas"); var gl = canvas.getContext("experimental-webgl"); // setup a GLSL program var program = createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]); gl.useProgram(program); // look up where the vertex data needs to go. var positionLocation = gl.getAttribLocation(program, "a_position"); // Create a buffer and put a single clipspace rectangle in // it (2 triangles) var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array([ -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0]), gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); // draw gl.drawArrays(gl.TRIANGLES, 0, 6); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

下面是兩個着色器。

<script id="2d-vertex-shader" type="x-shader/x-vertex"> attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0, 1); } </script> <script id="2d-fragment-shader" type="x-shader/x-fragment"> void main() { gl_FragColor = vec4(0, 1, 0, 1); // green } </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

它將繪出一個綠色的長方形來填充整個畫板。

這裏寫圖片描述

再日後面實在是太過專業了,須要掌握圖形圖像學的知識,經過demo確實能看出來很是強大,可是須要更專業的人才能搞了。

想對WebGL瞭解更多,參考這裏。

https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API

http://blog.csdn.net/column/details/webgl.html

http://www.w3cschool.cn/webgl/i4gf1oh1.html

http://blog.163.com/hongshaoguoguo@126/blog/static/18046981201311310510380/

(4)CSS3 3D(CSS3 3D)

這裏寫圖片描述

先上demo。

http://www.ganecheng.tech/html5/css33d.html

CSS3容許元素以3D的形式顯示。

下面講解一下這個demo是怎樣顯示出來的。

<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style type="text/css"> *{margin: 0;padding: 0;} html,body{height: 80%;background: black;} .wrap { height: 100%;position: relative; -webkit-transform-style:preserve-3d; -webkit-perspective:0px; -moz-transform-style:preserve-3d; -moz-perspective:0px; -webkit-animation:mydhua 5s ease infinite; -moz-animation:mydhua 5s ease infinite; } .box { width: 200px; height: 200px; position: absolute; top: 50%; left: 50%; margin:-100px 0 0 -100px; line-height: 200px; text-align: center; font-size: 48px; color: white; } .box1{ -webkit-transform:rotatey(90deg) translatez(-100px); -moz-transform:rotatey(90deg) translatez(-100px); background: rgba(128,0,128,.5); } .box2{ -webkit-transform:rotatey(90deg) translatez(100px); -moz-transform:rotatey(90deg) translatez(100px); background: rgba(255,0,255,.5); } .box3{ -webkit-transform:rotatex(90deg) translatez(100px); -moz-transform:rotatex(90deg) translatez(100px); background: rgba(255,153,204,.5); } .box4{ -webkit-transform:rotatex(90deg) translatez(-100px); -moz-transform:rotatex(90deg) translatez(-100px); background: rgba(0,204,255,.5); } .box5{ -webkit-transform: translatez(-100px); -moz-transform:translatez(-100px); background: rgba(153,204,255,.5); } .box6{ -webkit-transform: translatez(100px); -moz-transform:translatez(100px); background: rgba(0,255,255,.5); } @-webkit-keyframes mydhua{ 0%{-webkit-transform:rotateX(0deg) rotateY(0deg) rotateZ(0deg);-webkit-transform-origin: center center;} 100%{-webkit-transform:rotateX(180deg) rotateY(180deg) rotateZ(180deg);-webkit-transform-origin: center center; } } @-moz-keyframes mydhua{ 0%{-moz-transform:rotateX(0deg) rotateY(0deg) rotateZ(0deg);-webkit-transform-origin: center center;} 100%{-moz-transform:rotateX(180deg) rotateY(180deg) rotateZ(180deg); -webkit-transform-origin: center center;} } </style> </head> <body style="width:960px;margin:0px auto;"> <div class="wrap"> <div class="box1 box">1</div> <div class="box2 box">2</div> <div class="box3 box">3</div> <div class="box4 box">4</div> <div class="box5 box">5</div> <div class="box6 box">6</div> </div> <script type="text/javascript"> </script> </body> </html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

首先是使子元素能夠以3D的效果顯示出來。

.wrap { height: 100%;position: relative; -webkit-transform-style:preserve-3d; -webkit-perspective:0px; -moz-transform-style:preserve-3d; -moz-perspective:0px; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

接下來規定6個div的初始位置。
rotateX()表示沿 X 軸的 3D 旋轉角度。
rotateY()表示沿 Y 軸的 3D 旋轉角度。
translateZ() 表示 3D 轉化,僅使用用於 Z 軸的值。表示在Z軸的移動位置,值越大,離屏幕越近,值越小,離屏幕越遠。在此網址感覺一下translateZ()的效果。http://www.zhangxinxu.com/study/201209/transform-perspective-translateZ.html

<div class="box1 box">1</div> <div class="box2 box">2</div> <div class="box3 box">3</div> <div class="box4 box">4</div> <div class="box5 box">5</div> <div class="box6 box">6</div> .box { width: 200px; height: 200px; position: absolute; top: 50%; left: 50%; margin:-100px 0 0 -100px; line-height: 200px; text-align: center; font-size: 48px; color: white; } .box1{ -webkit-transform:rotatey(90deg) translatez(-100px); -moz-transform:rotatey(90deg) translatez(-100px); background: rgba(128,0,128,.5); } .box2{ -webkit-transform:rotatey(90deg) translatez(100px); -moz-transform:rotatey(90deg) translatez(100px); background: rgba(255,0,255,.5); } .box3{ -webkit-transform:rotatex(90deg) translatez(100px); -moz-transform:rotatex(90deg) translatez(100px); background: rgba(255,153,204,.5); } .box4{ -webkit-transform:rotatex(90deg) translatez(-100px); -moz-transform:rotatex(90deg) translatez(-100px); background: rgba(0,204,255,.5); } .box5{ -webkit-transform: translatez(-100px); -moz-transform:translatez(-100px); background: rgba(153,204,255,.5); } .box6{ -webkit-transform: translatez(100px); -moz-transform:translatez(100px); background: rgba(0,255,255,.5); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

如今定義關鍵幀動畫。
用@keyframes定義一個關鍵幀動畫,0%表示起始狀態,100%表示結束狀態,還能夠根據須要定義50%等等。動畫的名稱叫mydhua。

@-webkit-keyframes mydhua{ 0%{-webkit-transform:rotateX(0deg) rotateY(0deg) rotateZ(0deg);-webkit-transform-origin: center center;} 100%{-webkit-transform:rotateX(180deg) rotateY(180deg) rotateZ(180deg);-webkit-transform-origin: center center; } } @-moz-keyframes mydhua{ 0%{-moz-transform:rotateX(0deg) rotateY(0deg) rotateZ(0deg);-webkit-transform-origin: center center;} 100%{-moz-transform:rotateX(180deg) rotateY(180deg) rotateZ(180deg); -webkit-transform-origin: center center;} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

接下來就是使用動畫。

.wrap { -webkit-animation:mydhua 5s ease infinite; -moz-animation:mydhua 5s ease infinite; }
  • 1
  • 2
  • 3
  • 4
  • 5

這樣咱們就獲得了一個CSS3 3D旋轉的效果。

只要涉及到3D,都和空間立體幾何相關。若是想往這方面更進一步發展,桌前要常備這一類的書籍。

想要對CSS3 3D瞭解更多的,能夠參考下面網址。

http://www.javashuo.com/article/p-pdfieeia-kr.html

http://www.w3school.com.cn/css3/css3_3dtransform.asp

http://www.cnblogs.com/duanhuajian/archive/2012/08/30/2664026.html

⑦ 性能與集成特性(Performance & Integration)

這裏寫圖片描述

看看W3C的介紹。

Make your Web Apps and dynamic web content faster with a variety of techniques and technologies such as Web Workers and XMLHttpRequest 2. No user should ever wait on your watch.

性能與集成特性主要包括兩個東西,Web WorkersXMLHttpRequest 2

下面依次介紹。

(1)網頁後臺任務(Web Workers)

這裏寫圖片描述

先上demo,http://www.w3school.com.cn/tiy/t.asp?f=html5_webworker

當在 HTML 頁面中執行腳本時,頁面的狀態是不可響應的,直到腳本已完成。

Ajax向服務器端發送請求,是異步接收響應的。否則頁面會卡住。

Web Workers 是運行在瀏覽器後臺的 JavaScript,獨立於其餘腳本,不會影響頁面的性能。您能夠繼續作任何願意作的事情:點擊、選取內容等等,而此時 Web Workers 在後臺運行。

setInterval和setTimeout是單線程執行的。

雖然在JavaScript中有setInterval和setTimeout函數使javaScript看起來好像使多線程執行,單實際上JavaScript是單線程的,一次只能作一件事情。

看一個例子。

<!DOCTYPE html> <html> <head> <title>Web Workers</title> </head> <body> <h1>Web Workers</h1> <script type="text/javascript"> setTimeout(function(){ console.log('timeout function'); },1000); alert('do not close'); </script> </body> </html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

頁面一運行就會彈出一個對話框,若是setTimeout是在另一個線程運行,那麼過一秒鐘控制檯就會打印「timeout function」,事實是隻要不關閉對話框,控制檯永遠不會輸出文字,這兩句話確實是在一個線程內運行的。

這樣的設計使JavaScript比較簡單,但有時候也很使人煩惱,由於單線程的設計意味着JavaScript代碼必須很快運行完,常見的問題就是一段複雜的JavaScript腳本會中斷頁面其它腳本執行,甚至會出現頁面失去響應,這也就是爲何Ajax的API要設計成異步的。

Web Workers 用法

在html5規範中引入了web workers概念,解決客戶端JavaScript沒法多線程的問題,其定義的worker是指代碼的並行線程,不過web worker處於一個自包含的環境中,沒法訪問主線程的window對象和document對象,和主線程通訊只能經過異步消息傳遞機制。

咱們須要把但願單獨執行的javascript代碼放到一個單獨的js文件中,而後在頁面中調用Worker構造函數來建立一個線程,參數是該文件路徑,參數存放若是是相對地址,那麼要以包含調用Worker構造函數語句所在腳本爲參照,若是是絕對路徑,須要保證同源(協議+主機+端口)。這個文件不須要咱們在頁面使用script標籤顯示引用

w=new Worker("/example/html5/demo_workers.js");
  • 1

worker對象只有兩個屬性,實際上是兩個回調函數句柄。

onerror:當worker運行出現錯誤,而且沒有在worker中被捕獲,會在此捕獲
onmessage:當worker向主線程發送消息是調用
在其prototype內有兩個重要方法

postMessage:很熟悉的趕腳,以前咱們介紹過window對象的postMessage()方法,woker的postMessage方法和window的比較相似,但參數略有不一樣,只須要傳遞消息內容就能夠,並且支持全部JavaScript原生數據類型,固然不放心的話一樣也能夠序列化爲字符串傳遞
terminate:終止worker執行,有些worker執行比較慢,主線程能夠主動終止其執行

demo_workers.js

var i=0; function timedCount() { i=i+1; postMessage(i); setTimeout("timedCount()",500); } timedCount();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

demo.html

<!DOCTYPE html> <html> <body> <p>計數: <output id="result"></output></p> <button onclick="startWorker()">開始 Worker</button> <button onclick="stopWorker()">中止 Worker</button> <br /><br /> <script> var w; function startWorker() { if(typeof(Worker)!=="undefined") { if(typeof(w)=="undefined") { w=new Worker("/example/html5/demo_workers.js"); } w.onmessage = function (event) { document.getElementById("result").innerHTML=event.data; }; } else { document.getElementById("result").innerHTML="Sorry, your browser does not support Web Workers..."; } } function stopWorker() { w.terminate(); } </script> </body> </html> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

想對 Web Workers 瞭解更多的,參考下面連接。

http://www.w3school.com.cn/html5/html_5_webworkers.asp

http://www.cnblogs.com/dolphinX/p/3452684.html

https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers

(2)新的Ajax(XMLHttpRequest 2)

這裏寫圖片描述

XMLHttpRequest是一個瀏覽器接口,使得Javascript能夠進行HTTP(S)通訊。也就是Ajax。

上一代Ajax有如下缺點。

  • 只支持文本數據的傳送,沒法用來讀取和上傳二進制文件。
  • 傳送和接收數據時,沒有進度信息,只能提示有沒有完成。
  • 受到」同域限制」(Same Origin Policy),只能向同一域名的服務器請求數據,不能跨域。

XMLHttpRequest 2也就是新的Ajax。針對老版本的缺點,作出了大幅改進,有下面的特色。

  • 能夠設置HTTP請求的時限。
  • 能夠使用FormData對象管理表單數據。
  • 能夠上傳文件。
  • 能夠請求不一樣域名下的數據(跨域請求)。
  • 能夠獲取服務器端的二進制數據。
  • 能夠得到數據傳輸的進度信息。

XMLHttpRequest 2示例

前臺代碼.

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>第二代XmlHttpRequest異步上傳</title> <script type="text/javascript"> function upload(){ if (!window.FormData){ alert('您的瀏覽器不支持第二代XmlHttpRequest'); return; } // HTML5 新增對象 var formData = new FormData(document.getElementById('uploadForm')); //添加其餘表單域 formData.append('user', 'haolin'); formData.append('pass', '111111'); var xhr = new XMLHttpRequest(); xhr.open('POST', 'upload'); //請求url //上傳完成回調函數 xhr.onload = function(event) { if (xhr.status === 200) { alert("上傳成功"); } else { alert('出錯了'); } }; xhr.send(formData); } </script> </head> <body> <h1>第二代XmlHttpRequest對象實現異步上傳</h1> <form id="uploadForm" action="" method="post" enctype="multipart/form-data"> <input id="upfile" type="file" name="upfile"/> <input type="button" value="上傳" onclick="upload()"/> </form> </body> </html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

後臺代碼

PrintWriter out = new PrintWriter(response.getOutputStream()); FileItemFactory factory = new DiskFileItemFactory();// 爲該請求建立一個DiskFileItemFactory對象,經過它來解析請求。執行解析後,全部的表單項目都保存在一個List中。 ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> items; try { items = upload.parseRequest(request); Iterator<FileItem> itr = items.iterator(); while (itr.hasNext()) { FileItem item = (FileItem) itr.next(); System.out.println("是不是FormField: " + item.isFormField()); System.out.println("接收到域: " + item.getFieldName()); System.out.println("接收到值: " + item.getString("utf-8")); // 檢查當前項目是普通表單項目仍是上傳文件。 if (item.isFormField()) {// 若是是普通表單項目,顯示錶單內容。 String fieldName = item.getFieldName(); out.println("the field name is " + fieldName);// 顯示錶單域名稱。 } else {// 若是是上傳文件,顯示文件名。 out.println("the upload file name is " + item.getName()); } } out.flush(); out.close(); } catch (FileUploadException e) { e.printStackTrace(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

對XMLHttpRequest 2進行封裝。

var AjaxForm = function(cfg){ if (!window.FormData){ alert("Sorry, your browser doesn't supoort FormData!"); } /** * null or undefined 返回true, 不然false */ this.isNullOrUndefined = function(v, errMsg){ if (!v){ alert(errMsg); return true; } return false; }; var cfg = cfg || {}; if (this.isNullOrUndefined(cfg.id, "id can't be empty")) return; if (this.isNullOrUndefined(cfg.url, "url can't be empty")) return; this.id = cfg.id; // 表單id this.method = cfg.method || "POST"; //默認POST方法 this.url = cfg.url; this.async = !cfg.sync; //同步否 this.resultType = cfg.resultType || "text"; //返回結果類型 json對象或text this.formData = new FormData(document.getElementById(this.id)); //form數據 this.xhr = new XMLHttpRequest(); //當前請求對象 /** * 超時事件 * 配置格式: * timeout : xxx, * onTimeout: function(event){} */ if (cfg.timeout){ this.xhr.timeout = cfg.timeout; this.xhr.ontimeout = cfg.onTimeout; } /** * 發送過程事件 * 配置格式: * onProgress: function(loaded, total){} */ if (cfg.onProgress){ //發送數據過程 this.xhr.upload.onprogress = function(e){ if (e.lengthComputable) { cfg.onProgress(e.loaded, e.total); } }; } /** * 上傳完成事件 */ if (cfg.onComplete){ this.xhr.onload = function(event){ var res = event.target.responseText; if (this.resultType === 'json'){ if ((typeof JSON) === 'undefine'){ res = eval("("+res+")"); } else{ res = JSON.parse(res); } } cfg.onComplete(res); }; } /** * 發出請求 */ this.request = function(){ this.xhr.open(this.method, this.url, this.async); this.xhr.send(this.formData); }; }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

調用

var af = new AjaxForm({ id: "uploadForm", url: 'upload', method: 'POST', timeout: 5000, onTimeout: function(event){ alert('It is timeout.'); }, onProgress: function(loaded, total){ var complete = (loaded / total * 100 | 0); var progress = document.getElementById('uploadProgress'); progress.value = complete; progress.innerHTML = complete; }, onComplete: function(result){ alert(result); } }); af.request();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

能夠看出,雖然是XMLHttpRequest 2,可是仍是XMLHttpRequest對象。使用新的特性,須要先判斷是否支持window.FormData。

若是想對XMLHttpRequest 2瞭解更多,能夠參考下面文章。

https://www.w3.org/TR/XMLHttpRequest2

https://my.oschina.net/indestiny/blog/215472

http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html

http://blog.csdn.net/hills/article/details/41246939


後記

以前一直在作web開發。可是歷來沒有對HTML5仔細研究過,寫這篇文章,前先後後花了4天時間,從驚歎於HTML5的強大,到目擊有這麼多的坑,瀏覽器的性能也跟不上。

可是咱們不該該悲觀,解決方法總比困難多,Chrome和Firefox也一直在推進瀏覽器性能提高。前端不再是切個圖,調調顏色,改改字體大小,放個Flash的時代了。HTML5會給咱們一個更加美好的將來,前端開發者也有一個提高技術含量,迎接各類機遇的機會了。

祝願前端愈來愈好。


參考文獻

https://www.w3.org/html/logo/

http://caniuse.com/

1 0

評論(1)

1

寫的太好了

2017-03-24 15:23 回覆

個人熱門文章

相關博文

百度智薦
img
img即便是一小步
也想與你分享
打開
img
相關文章
相關標籤/搜索