article元素是可以嵌套使用的,內層的內容再原則上需要與外層的內容相關聯。例如,一篇博文,針對該文章的評論就可以使用嵌套article。(pubdate代表發布時間)
<header>
<hgroup>
<h1>IT 新技術</h1>
<a >
http://blog.sina.com.cn/itnewtech
</a>
<a href="#">[訂閱]</a>
<a href="#">[手機訂閱]</a>
</hgroup>
<nav>
<ul>
<li>首頁</li>
<li><a href="#">博文目錄</a></li>
<li><a href="#">圖片</a></li>
<li><a href="#">關于我</a></li>
</ul>
</nav>
</header>
</div>
</div>
hgroup元素
hgroup元素是將標題及其子標題進行分組的元素。hgroup元素通常會將h1~h6元素進行分組,譬如一個內容區塊的標及其子標題算一組。
<header>
<hgroup>
<h1>主標題</h1>
<h2>子標題</h2>
</hgroup>
</header>
footer元素可以作為其上層父級內容區塊或者根區塊的腳注。footer通常包括其相關區塊的腳注信息,如作者、相關閱讀鏈接及版權信息等。
address元素
address元素用來在文檔呈現聯系信息,包括文檔作者或文檔維護者的名字、他們的網站鏈接、電子郵箱、真實地址、電話號碼等。
<address>
<a href="#">lucy</a>
<a href="#">lily</a>
<a href="#">cecil</a>
</address>
結構元素大體用div也可以實現,只是如果使用結構元素的話,那么網頁代碼的可讀性則會大大加強。純HTML 5結構的網頁實例:
二、表單和文件
1、新增元素和屬性
在HTML4中,表單內的從屬元素必須書寫在表單內部,但是在HTML5中,可以把它們書寫在頁面上任何地方,然后給該元素指定一個form屬性,屬性值為該表單的id,這樣就可以聲明該元素從屬于指定表單了。
<form id="testform">
<input type="text">
</form>
<textarea form="testform"></textarea>
在HTML4中,一個表單內的所有元素都只能通過表單的action屬性統一提交到另一個頁面,而在HTML5中可以給所有的提交按鈕,諸如<input type="submit">、
<input type="image">、<button type="submit">都增加不同的formaction屬性
<form id="testform" action="serve.jsp">
<input type="submit" name="s1" value="v1" formation="s1.jsp">提交到S1
<input type="submit" name="s2" value="v2" formation="s2.jsp">提交到S2
<input type="submit" name="s3" value="v3" formation="s3.jsp">提交到S3
<input type="submit">
</form>
PS: 目前尚沒有瀏覽器支持這一屬性
placeholder是指當文本框(input、textarea)處于未輸入狀態時文本框中顯示的輸入提示。
<input type="text" placeholder="input me"/>
給文本框、選擇框或按鈕控件加上該屬性,當畫面打開時,該控件自動獲得光標焦點
<input type="text" autofocus/>
在HTML5中,為單行文本框(<input type="text">)
增加了一個list屬性,該屬性的值為某個datalist元素的id。datalist元素也是HTML5新增的元素,改元素類似于選擇框,但是當用戶
想要設定的值不在選擇列表之內時,允許其自行輸入。該元素本身并不顯示,而是當文本框獲得焦點時以提示輸入的方式顯示。為了避免在沒有支持該元素的瀏覽器
顯示,可以用CSS將其隱藏。
<input type="text" name="greeting" list="greetings"/>
<!--使用style="display:none;" 將datalist元素設定為不顯示-->
<datalist id="greetings" style="display:none;">
<option value="Good Morning">Good Morning</option>
<option value="Hello">Hello</option>
<option value="Good Afternoon">Good Afternoon</option>
</datalist>
輔助輸入所用的自動完成
<input type="text" name="greeting" list="greetings" autocomplete="on"/>
PS: chrome20不支持
search、tel、url、email等,可參照:
output元素
output元素必須從屬于某個表單,也就是說,必須將它書寫在表單內部,或者對它添加form屬性
<form id="testform">
請選擇一個值
<input name="range1" type=range min=0 max=100 step=5/>
<output onforminput="value=range1.value">50</output>
</form>
PS: 目前只有Opera支持得比較好
2、表單驗證
2.1、自動驗證
<form method="post">
<input name="text" type="text" required pattern="^\w.*$"/>
<input type="submit"/>
</form>
min與max這兩個屬性是數值類型或日期類型的input元素的專用屬性
step屬性控制input元素中的值增加或減少時的步幅
2.2、顯示驗證
form元素與input元素(包括select元素與textarea元素)都具有一個checkValidity方法。調用該方法,可以顯示地對表
單內所有元素內容或單個元素內容進行有效性驗證。checkValidity方法以boolean的形式返回驗證結果。
<script language="javascript">
function check(){
var email = document.getElementById("email");
if(email.value==""){
alert("請輸入Email地址");
return false;
}...
}
</script>
<form id="testform" onsubmit="return check();">
Email:
<input name="email" type="email" id="email"/><br/>
<input type="submit"/>
</form>
3、增強的頁面元素
figure元素用來表示網頁上一塊獨立的內容,可以是圖片、統計圖或代碼示例,甚至是音頻插件、視頻插件等。figcaption元素表示figure元素的標題,從屬figure元素,必須寫在figure元素內部。
<figure>
<img src="lufu.jpg" alt="lufu"/>
<img src="lufu2.jpg" alt="lufu"/>
<figcaption>路飛</figcaption>
</figure>
提供了一種替代JavaScript的、將畫面上局部區域進行展開或收縮的方法。summary元素從屬于details元素,用鼠標點擊
summary元素中的內容文字時,detail元素中的其他從屬元素將會展開或收縮。如果沒有summary元素,瀏覽器也會提供默認的樣式。
details元素還提供了“open”屬性, 使用<details open>,則默認頁面加載時就打開details里面的內容。
<details>
<summary>HTML 5</summary>
This document teaches you everything you have to learn about HTML5
</details>
mark元素表示頁面中需要突出顯示或高亮顯示的,一般可以用于顯示關鍵字高亮,或者是與用戶相關需要提醒用戶的時候使用。
<h1>搜索"<mark>HTML 5</mark>", 找到相關網頁約10,200,000篇,用時0.041秒</h1>
<section id="search-results">
<article>
<h2>
<a href="#">專題:<mark>HTML 5 </mark> 下一代web開發標準</a>
</h2>
<p><mark>HTML 5</mark>近十年XXXXXXXXX</p>
</article>
<article>
<h2>
<a href="#">專題:<mark>HTML 5 </mark> 下一代web開發標準</a>
</h2>
<p><mark>HTML 5</mark>近十年XXXXXXXXX</p>
</article>
</section>
PS:mark元素的作用與em元素、strong元素是有區別的,mark元素的標示目的與原文作者無關,而是在后來引用時添加上去的,目的是為了吸引當前用戶或者給用戶做參考。而em、strong是原文作者用來強調一段文字的重要性添加的。
progress元素代表一個任務的完成進度
meter元素表示規定范圍內的數量值
4、文件API
在HTML5中,通過添加multiple屬性,file控件內允許一次放置多個文件。控件內的每一個用戶選擇的文件都是一個file對象,而FileList對象則為這些file對象的列表,代表用戶選擇的所有文件。
<script language=javascript>
function showFileName(){
var file;
for(var i=0; i < document.getElementById("file").files.length; i++){
file = document.getElementById("file").files[i];
alert(file.name + ": 最后一次修改時間" + file.lastModifiedDate);
}
}
</script>
選擇文件:
<input type="file" id="file" multiple size="80"/><br/>
<input type="button" onclick="showFileName();" value="show File Name"/>
表示二進制原始數據,它提供了一個slice方法,可以通過該方法訪問到字節內部的原始數據塊。file對象繼承了Blog對象。Blob對象有兩個屬
性,size屬性表示一個Blob對象的字節長度,type屬性表示Blob的MIME類型,如果未知類型,返回空字符。
HTML5 對file控件添加了accept屬性,但目前僅支持圖像,其他的設置無效
<input type="file" id="file" multiple size="80" accept="image/*"/>
FileReader接口擁有4個方法,3個用于讀取文件(readAsBinaryString、readAsText、readAsDataURL
【主要是圖片和html文件】),另一個用來將讀取過程中斷(abort)。另外,FileReader接口還提供了一套完整的事件模型。
(onabort、onerror、onloadstart、onprogerss、onload、onloadend)
PS: 需要在服務器上運行才有效
<script language=javascript>
var result = document.getElementById("result");
var file = document.getElementById("file");
if(typeof FileReader == 'undefined'){
result.innerHTML = "<p>抱歉,你的瀏覽器不支持 FileReader</p>";
file.setAttribute('disabled', 'disabled');
}
//將文件以Data URL形式讀入頁面
function readAsDataURL(){
var file = document.getElementById("file").files[0];
if(file == null){
alert("請選擇文件!!");
return false;
}
if(!/image\/\w+/.test(file.type)){
alert("請確保文件為圖像類型");
return false;
}
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e){
var result = document.getElementById("result");
result.innerHTML = '<img src="' + this.result + '" alt=""/>';
}
}
//將文件以二進制形式讀入頁面
function readAsBinaryString(){
var file = document.getElementById("file").files[0];
if(file == null){
alert("請選擇文件!!");
return false;
}
var reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = function(f){
var result = document.getElementById("result");
result.innerHTML = this.result;
}
}
//將文件以文本形式讀入頁面
function readAsText(){
var file = document.getElementById("file").files[0];
if(file == null){
alert("請選擇文件!!");
return false;
}
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function(f){
var result = document.getElementById("result");
result.innerHTML = this.result;
}
}
</script>
<p>
<label>請選擇一個文件: </label>
<input type="file" id="file"/><br/>
<input type="button" value="讀取圖像" onclick="readAsDataURL();"/>
<input type="button" value="讀取二進制數據" onclick="readAsBinaryString();"/>
<input type="button" value="讀取文本文件" onclick="readAsText();"/>
</p>
<div name="result" id="result">
</div>
5、拖放API
5.1 操作:
- 將想要拖放的對象元素的draggable屬性設為true(draggable="true"),另外,img元素與a元素(必須指定href)默認允許拖放
- 編寫與拖放相關的事件處理代碼(dragstart、drag、dragenter、dragover、dragleave、drop、dragend)
<script language=javascript>
function init(){
var source = document.getElementById("dragme");
var dest = document.getElementById("text");
//drag start
source.addEventListener("dragstart", function(ev){
var dt = ev.dataTransfer;
//DataTransfer專門用來存放拖放時要攜帶的數據
dt.effectAllowed = "all";
dt.setData("text/plain", "hello");
}, false);
//drag end
dest.addEventListener("dragend", function(ev){
ev.preventDefault();
}, false);
//drop
dest.addEventListener("drop", function(ev){
var dt = ev.dataTransfer;
var text = dt.getData("text/plain");
dest.textContent += text;
ev.preventDefault();
ev.stopPropagation();
},false);
}
document.ondragover = function(e){e.preventDefault();};
document.ondrop = function(e){e.preventDefault();};
</script>
<body onload="init()">
<h1>simple drag demo</h1>
<div id="dragme" draggable="true" style="width: 200px; border: 1px solid gray;">
please drag
</div>
<div id="text" style="width: 200px; height: 200px; border: 1px solid gray;"></div>
</body>
5.2 DataTransfer對象的屬性與方法
現在支持拖動處理的MIME的類型為text/plain、text/html、text/xml、text/uri-list。
如果DataTransfer對象的屬性和方法使用得好,可以實現定制拖放圖標,讓它只支持特定拖放(譬如拷貝/移動)等。
三、繪制圖形
1、canvas繪制
首先,要指定ID、width、height三個屬性。canvas在頁面放置的時候跟其他元素沒有太大區別。
<canvas id="canvas" width="400" height="300"/>
繪制步驟:
- 取得canvas元素
- 取得上下文,需要使用canvas對象的getContext方法來獲得圖形上下文。
- 填充與繪制邊框
- 設定繪制樣式
- 指定線寬lineWidth
- 指定顏色值
- 繪制矩形
canvas元素繪制圖形,一般有兩種方式——填充(fill) 與繪制邊框 (stroke),
通過filleStyle指定填充樣式,strokeStyle指定圖形邊框樣式。fillRect方法和storkeRect方法來填充矩形和繪制矩形
邊框。
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title> first canvas demo ### </title>
<script type="text/javascript" src="firstCanvas.js"></script>
</head>
<body onload="draw('canvas')">
<h1>canvas元素實例</h1>
<canvas id="canvas" width="400" height="300"/>
</body>
#########firstCanvas.js######
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle="#EEEEFF";
context.fillRect(0, 0, 400, 300);
context.fillStyle = "red";
context.strokeStyle = "blue";
context.lineWidth = 1;
context.fillRect(50, 50, 100, 100);
context.strokeRect(50, 50, 100, 100);
}
另外,還有一個context.clearRect(x, y, width, height)方法, 該方法將擦除指定的矩形區域中的圖形,使得矩形區域中的顏色全部變為透明。
2、使用路徑
除了長方形或正方形,要畫其他的圖形,需要使用路徑,依然是最開始取得上下文,之后步驟:
- 開始創建路徑 context.beginPath()
- 創建圖形的路徑 context.arc(x, y, radius, startAngle, endAngle, anticlockwise)
- 路徑創建完成后,關閉路徑 context.closePath()
- 設定繪制樣式,調用繪制方法,繪制路徑 contex.fillStyle="rgba(255, 0, 0, 0.25)" ;context.fill();
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#EEEEFF';
context.fillRect(0, 0, 400, 300);
var n = 0;
for(var i=0; i < 10; i++){
context.beginPath();
context.arc(i*25, i*25, i*10, 0, Math.PI*2, true);
context.closePath();
context.fillStyle = 'rgba(255, 0, 0, 0.25)';
context.fill();
}
}
繪制直線時,一般會用到moveTo與lineTo。moveTo(x, y)方法是將光標移動到指定坐標點,lineTo(x, y)方法在moveTo方法中指定的直線起點與參數中指定的直線終點之間繪制一條線。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#EEEEFF';
context.fillRect(0, 0, 400, 300);
var n = 0;
var dx = 150;
var dy = 150;
var s = 100;
context.beginPath();
context.fillStyle = 'rgb(100, 255, 100)';
context.strokeStyle = 'rgb(0, 0, 100)';
var x = Math.sin(0);
var y = Math.cos(0);
var dig = Math.PI / 15 * 11;
for(var i=0; i < 30; i++){
var x = Math.sin(i * dig);
var y = Math.cos(i * dig);
context.lineTo(dx + x * s, dy + y * s);
}
context.closePath();
context.fill();
context.stroke();
}
3、繪制漸變圖形
3.1 線性漸變
繪制線性漸變時,需要用到LinearGradient對象。使用圖形上下文對象的createLinearGradient方法創建該對象:
context.createLinearGradient(xStart, yStart, xEnd, yEnd),xStart為漸變起始地點的橫坐標,yStart為漸變起始地點的縱坐標,xEnd為漸變結束點的橫坐標,yEnd為漸變結束點的縱坐標。
在LinearGradient對象后,使用addColorStop方法進行漸變的顏色設定:
context.addColorStop(offset, color),
offset為所設定的顏色離開漸變起始點的偏移量。該參數的值是一個范圍在0到1之間的浮點值。因為是漸變,需要至少使用兩次addColorStop
方法以追加兩個顏色(開始顏色與結束顏色),可以追加多個顏色。例如“從藍色漸變到白色,然后漸變到綠色”。
之后把fillStyle設定為LinearGradient對象,然后執行填充的方法,就可以繪制出漸變圖形。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
var g1 = context.createLinearGradient(0, 0, 0, 300);
g1.addColorStop(0, 'rgb(255, 255, 0)');
g1.addColorStop(1, 'rgb(0, 255, 255)');
context.fillStyle = g1;
context.fillRect(0, 0, 400, 300);
var n = 0;
var g2 = context.createLinearGradient(0, 0, 300, 0);
g2.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
g2.addColorStop(1, 'rgba(255, 0, 0, 0.5)');
for(var i=0; i < 10; i++){
context.beginPath();
context.fillStyle = g2;
context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
context.closePath();
context.fill();
}
}
3.2 徑向漸變
徑向漸變指沿著圓形的半徑方向向外進行擴散的漸變方式,方法定義如下:
context.createRadialGradient(xStart, yStart, radiusStart, xEnd, yEnd,
radiusEnd),xStart為漸變開始圓的圓心橫坐標,yStart為漸變開始圓的圓心縱坐標,radiusStart為開始圓的半徑,xEnd
為漸變結束圓的圓心橫坐標,yEnd為漸變結束圓的圓心縱坐標,radiusEnd為結束圓的半徑。分別指定了兩個圓的大小與位置,從第一個圓的圓心處向
外進行擴散漸變,一直擴散到第二圓的外輪廓處。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
var g1 = context.createRadialGradient(400, 0, 0, 400, 0, 400);
g1.addColorStop(0.1, 'rgb(255, 255, 0)');
g1.addColorStop(0.3, 'rgb(255, 0, 255)');
g1.addColorStop(1, 'rgb(0, 255, 255)');
context.fillStyle = g1;
context.fillRect(0, 0, 400, 300);
var n = 0;
var g2 = context.createLinearGradient(250, 250, 0, 250, 250, 300);
g2.addColorStop(0.1, 'rgba(255, 0, 0, 0.5)');
g2.addColorStop(0.7, 'rgba(255, 255, 0, 0.5)');
g2.addColorStop(1, 'rgba(0, 0, 255, 0.5)');
for(var i=0; i < 10; i++){
context.beginPath();
context.fillStyle = g2;
context.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
context.closePath();
context.fill();
}
}
4、繪制變形圖形
4.1 坐標變換
context.translate(x, y); x表示將坐標軸原點向左移動多少個單位,默認情況下為像素;y表示將坐標軸原點向下移動多少個單位。
context.scale(x, y); x是水平方向的放大倍數,y是垂直方向的放大倍數,如果是縮寫,可以填入0到1之間的小數。
context.rotate(angle); angle指旋轉的角度,旋轉的中心點是坐標軸的原點,旋轉是以順時針進行的,要想逆時針旋轉,則把angle設為負數
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#EEEEFF';
context.fillRect(0, 0, 400, 300);
//繪制圖形
context.translate(200, 50);
context.fillStyle = 'rgba(255, 0, 0, 0.25)';
for(var i=0; i < 50; i++){
context.translate(25, 25);
context.scale(0.95, 0.95);
context.rotate(Math.PI/10);
//畫矩形
context.fillRect(0, 0, 100, 50);
}
}
4.2 坐標變換與路徑的結合使用
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#EEEEFF';
context.fillRect(0, 0, 400, 300);
//繪制圖形
context.translate(200, 50);
context.fillStyle = 'rgba(255, 0, 0, 0.25)';
for(var i=0; i < 50; i++){
context.translate(25, 25);
context.scale(0.95, 0.95);
context.rotate(Math.PI/10);
//畫復雜圖形
create5Star(context);
context.fill();
}
}
function create5Star(context){
var n = 0;
var dx = 100;
var dy = 0;
var s = 50;
//創建路徑
context.beginPath();
context.fillStyle = 'rgba(255, 0 ,0 , 0.5)';
var x = Math.sin(0);
var y = Math.cos(0);
var dig = Math.PI/5 * 4;
for(var i=0; i < 5; i++){
var x = Math.sin(i * dig);
var y = Math.cos(i * dig);
context.lineTo(dx + x * s, dy + y * s);
}
}
4.3 矩陣變換
變換矩陣是專門用來實現圖形變形的,它與坐標一起配合使用,以達到變形的目的。當圖形上下文被創建完畢時,事實上也創建了一個默認的變換矩陣,如果不對
這個變換矩陣進行修改,那么接下來繪制的圖形將以畫布的最左上角為坐標原點繪制圖形,繪制出來的圖形也不經過縮放、變形的處理,但如果對這個變換矩陣進行
修改,那么情況就完全不一樣了。
context.transform(m11, m12, m21, m22, dx, dy);
PS: transform需要一定的矩陣知識,比較難理解。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
var colors = ['red', 'orange', 'yellow', 'green', 'blue', 'navy', 'purple'];
context.lineWidth = 10;
context.transform(1, 0 , 0 , 1, 100, 0);
for(var i=0; i < colors.length; i++){
context.transform(1, 0, 0, 1, 0, 10);
context.strokeStyle = colors[i];
context.beginPath();
context.arc(50, 100, 100, 0, Math.PI, true);
context.stroke();
}
}
4.4 圖形組合
使用上下文對象的globalCompositeOperation屬性能決定圖形的組合方式,使用方法如下:
context.globalCompositeOperation=type
type的值必須是下面幾種字符串之一:
- source-over(默認) 新創建的圖形覆蓋到原有圖形之上
- destination-over 表示原有圖形之下繪制新圖形
- source-in 新圖形與原有圖形做in運算,只顯示重疊部分,新舊圖形其他部分變成透明
- destination-in 原有圖形與新圖形做in運算,只顯示原有圖形中與新圖形重疊部分,其他部分透明
- source-out 新圖形與原有圖形做out運算,只顯示新圖形中與原有圖形不重疊部分,其他部分透明
- destination-out 原有圖形和新圖形做out運算,只顯示原有圖形中與新圖形不重疊的部分,其他部分透明
- source-atop 只繪制新圖形中與原有圖形重疊的部分與未被重疊覆蓋的原有圖形,新圖形的其他部分透明
- destination-atop 只繪制原有圖形中被新圖形重疊的部分與新圖形的其他部分,原有圖形中的其他部門透明
- lighter 原有圖形與新圖形均繪制,重疊部分做加色處理
- xor 只繪制新圖形中與原有圖形不重疊的部分,重疊部分變成透明
- copy 只繪制新圖形,原有圖形中未與新圖形重疊的部分變成透明
如果指定的type不在這幾個字符串當中,則按默認方式組合圖形。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
var oprtns = new Array(
"source-atop",
"source-in",
"source-out",
"source-over",
"destination-atop",
"destination-in",
"destination-out",
"destination-over",
"lighter",
"copy",
"xor"
);
i=8;
context.fillStyle = "blue";
context.fillRect(10, 10, 60, 60);
context.globalCompositeOperation = oprtns[i];
context.beginPath();
context.fillStyle = "red";
context.arc(60, 60, 30, 0, Math.PI*2, false);
context.fill();
}
4.5 給圖形繪制陰影
使用Canvas元素給添加陰影效果時,只需利用圖形上下文對象的幾個關于陰影繪制的屬性就可以了,如下:
shadowOffsetX —— 陰影的橫向位移量
shadowOffsetY —— 陰影的縱向位移量
shadowColor —— 陰影的顏色
shadowBlur —— 陰影的模糊范圍
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#EEEEFF';
context.fillRect(0, 0, 400, 300);
//陰影參數
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowColor = 'rgba(100, 100, 100, 0.5)';
context.shadowBlur = 7.5;
//繪制圖形
context.translate(0, 50);
for(var i=0; i < 3; i++){
context.translate(50, 50);
if(i == 2){
context.shadowColor = 'rgba(0, 0, 0, 0)';
}
create5Star(context);
context.fill();
}
}
shadowBlur屬性可選,它表示圖形陰影邊緣的模糊范圍。如果不希望陰影的邊緣太清晰,可以設定該屬性值。但是必須大于0,否則會被忽略。一般設定在0至10之間。
如果不想每個圖形具有陰影效果,可以在繪制繪制的時候,設置shadowColor為rgba(0, 0, 0, 0)。
4.6 使用圖像
4.6.1 繪制圖像
CanvasAPI不僅可以繪制圖形,還可以讀取磁盤或網絡中的圖像文件,然后使用CanvasAPI將該圖像繪制在畫布中。
繪制圖像時,需要使用drawImage方法,定義如下:
- context.drawImage(image, x, y);
- context.drawImage(image, x, y, w, h);
- context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
第一個方法:image可以是img元素、video元素或者JS中的Image對象,xy為繪制該圖像在畫布中的起始坐標
第二個方法: 前三個參數與上面的一致,w、h是指繪制圖像的寬度與高度
第三個方法: image和第一個方法一樣,sx、sy、sw、sh表示復制圖像的起點寬高,dx、dy、dw、dh表示復制到畫布的起點寬高,該方法可以用于剪切圖像,或者縮放圖像。
因為設定好Image對象的src屬性后,不一定就立刻顯示圖像,所以建議:
image.onload = function(){繪制圖像函數}
在Image對象的onload事件中同步執行繪制圖像的函數,就可以一邊裝載一邊繪制
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#EEEEFF';
context.fillRect(0, 0, 400, 300);
image = new Image();
image.src = 'lufu.jpg';
image.onload = function(){
drawImg(context, image);
}
}
function drawImg(context, image){
for(var i=0; i < 7; i++){
context.drawImage(image, 0 + i * 50, 0 + i * 25, 100, 100);
}
}
//######## 局部方法Demo
function drawImg(context, image){
var i = 0;
context.drawImage(image, 0, 0, 100, 100);
context.drawImage(image, 23, 5, 57, 80, 110, 0, 100, 100);
}
4.6.2 圖像平鋪
圖像平鋪有兩種方法,一種就是上面的drawImage:
function drawImg(canvas, context, image){
//平鋪比例
var scale = 2;
//縮小后圖像寬度
var n1 = image.width/scale;
var n2 = image.height/scale;
//平鋪橫向個數
var n3 = canvas.width/n1;
var n4 = canvas.width/n2;
for(var i=0; i < n3; i++)
for(var j=0; j < n4; j++)
context.drawImage(image, i*n1, j*n2, n1, n2);
}
但是該方法比較復雜,HTML 5提供了一個更簡便的方法,利用上下文對象的createPattern,如下:
context.createPattern(iamge, type);
image為平鋪的圖像,type參數的值必須為下面的字符串之一:
- no-repeat: 不平鋪
- repeat-x: 橫向平鋪
- repeat-y: 縱向平鋪
- repeat: 全方向平鋪
創建image對象并制定圖像文件之后,使用createPattern方法創建填充樣式,然后將該樣式制定給圖形上下文對象的fillStyle屬性。
var context = canvas.getContext('2d');
image = new Image();
image.src = 'pig.gif';
image.onload = function(){
var ptrn = context.createPattern(image, 'repeat');
//填充樣式
context.fillStyle = ptrn;
context.fillRect(0, 0, 400, 300);
}
4.6.2 圖像裁剪
Canvas API的圖像裁剪功能是指,在畫布內使用路徑,只繪制該路徑所包括區域內的圖像,不繪制路徑外部的圖像。首先創建好路徑,之后調用上下文的clip方法設置裁剪區域。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
var gr = context.createLinearGradient(0, 400, 300, 0);
gr.addColorStop(0, 'rgb(255, 255, 0)');
gr.addColorStop(1, 'rgb(0, 255, 255)');
context.fillStyle = gr;
context.fillRect(0, 0, 400, 300);
iamge = new Image();
image.onload = function(){
drawImg(context, image);
}
image.src = 'lufu.jpg';
function drawImg(context, image){
create5StarClip(context);
context.drawImage(image, -50, -150, 300, 300);
}
function create5StarClip(context){
var n = 0;
var dx = 100;
var dy = 0;
var s = 150;
//創建路徑
context.beginPath();
context.translate(100, 150);
var x = Math.sin(0);
var y = Math.cos(0);
var dig = Math.PI/5 * 4;
for(var i=0; i < 5; i++){
var x = Math.sin(i * dig);
var y = Math.cos(i * dig);
context.lineTo(dx + x * s, dy + y * s);
}
context.clip();
}
裁剪區域一旦設置好之后,后面繪制的所有圖片就都可以使用這個裁剪區域,如果需要取消裁剪區域,那就需要使用繪制狀態的保存與恢復功能。這兩個功能保存
與恢復圖形上下文的臨時狀態。在設置圖像裁剪區域時,首先調用save方法保存圖像上下文的當前狀態,在繪制完經過裁剪的圖像后,在調用restore恢
復之前保存的圖形上下文的狀態。
4.6.3 像素處理(chrome不支持,opera和FF支持)
使用Canvas API 能夠獲取圖像中的每一個像素,然后得到該像素顏色的rgb值或rgba值。使用上下文的getImageData方法來獲取圖像中的像素,定義如下:
var imagedata = context.getImageData(sx, sy, sw, sh);
sx、sy、sw、sh分別指起點和寬高,imagedata變量是一個CanvasPixelArray對象,具有
height,width,data等屬性。data屬性是一個保存像素數據的數組,內容類似
“[r1,g1,b1,a1,r2,g2,b2,a2,r3,g3,b3,a3,....]”。
context.putImageData(imagedata, dx, dy[,dirtyX,dirtyY,dirtyWidth,dirtyHeight ]);
putImageData 可以傳入3個或者7個參數,dx, dy 表示重繪圖像的起點橫坐標,起點縱坐標,dirtyX、Y.... 則為起點的坐標和寬高
function draw(id){
var canvas=document.getElementById(id);
if(canvas==null){
return false;
}
var context=canvas.getContext('2d');
image=new Image();
image.src="lufu.jpg";
image.onload=function(){
context.drawImage(image,0,0);
var imagedata=context.getImageData(0,0,image.width,image.height);
for(var i=0,n=imagedata.data.length;i<n;i+=4){
imagedata.data[i+0]=255-imagedata.data[i+0];
imagedata.data[i+1]=255-imagedata.data[i+2];
imagedata.data[i+2]=255-imagedata.data[i+1];
}
context.putImageData(imagedata, 0, 0);
//context.putImageData(imagedata,30,30,10, 10, 50, 50);
};
}
4.7 繪制文字
在HTML
5中,Canvas也可以繪制文字,使用fillText方法或strokeText方法。fillText方法用填充方式繪制字符
串,filleText(text, x, y, [maxWidth]);,第四個是可選參數,表示顯示文字是的最大寬度,防止文字溢出。
strokeText(text, x, y, [maxWidth]);用輪廓的方式繪制字符串。
在繪制之前,要對一些屬性進行設置:
- font屬性:設置文字字體
- textAlign屬性: 設置文字水平對齊方式,屬性值可以為start、end、left、right、center。默認值為start
- textBaseline屬性:設置文字垂直對齊方式,屬性值可以為top、hanging、middle、alphabetic、ideographic、bottom。默認值為alphabetic
meatureText方法可以得到文字的寬度, metrics = context.meatrueText(text)
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = '#00f';
context.font = 'italic 20px sans-serif';
var txt = '字符串的寬度為';
var tm1 = context.measureText(txt);
context.fillText (txt, 10, 30);
context.fillText(tm1.width, tm1.width + 10, 30);
context.font = 'bold 30px sans-serif';
var tm2 = context.measureText(txt);
context.fillText (txt, 10, 30);
context.fillText(tm2.width, tm2.width + 10, 30);
}
4.8 繪制文字
4.8.1 save和restore
之前提過如果裁剪樣式定了之后,之后都會居于裁剪樣式進行繪圖,但是之后可能不要,那么可以采用save當前在狀態,然后繪制了裁剪圖片之后,可以restore回來。
var x, y;
for(var j=1; j < 50; j++){
ctx.save();
ctx.fillStyle = '#fff';
x = 75 - Math.floor(Math.random() * 150);
y = 75 - Math.floor(Math.random() * 150);
ctx.translate(x, y);
drawStar(ctx, Math.floor(Math.random() * 4) + 2);
ctx.restore();
}
4.8.2 保存文件
Canvas API也提供了保存文件的功能,Canvas API保存文件的原理實際上是把當前的繪畫狀態輸出到一個data
URL地址所指向的數據中的過程,所謂data
URL,是指目前大多數瀏覽器能夠識別的一種base64位編碼的URL,主要用于小型的、可以在網頁中直接嵌入,而不需要從外部文件嵌入的數據,譬如
img元素中的圖像文件等。
Canvas API 使用toDataURL方法把繪畫狀態輸出到一個data URL中,然后重新裝載,客戶可直接把裝載后的文件進行保存。
canvas.toDataURL(type); 該方法使用一個參數type,表示要輸出數據的MIME類型。
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
var context = canvas.getContext('2d');
context.fillStyle = 'rgb(0, 0, 255)';
context.fillRect(0, 0, 400, 300);
context.fillStyle = 'rgb(255, 255, 0)';
context.fillRect(10, 20, 50, 50);
window.location = canvas.toDataURL('image/jpeg');
}
4.8.2 簡單動畫制作
實際上就是不斷擦除、重繪、擦除、重繪的過程,具體步驟如下:
預先編寫好用來繪圖的函數,在該函數中先用clearRect方法將畫布整體或局部擦除。
使用setInterval方法設置動畫的間隔時間
var context;
var width, height;
var i;
function draw(id){
var canvas = document.getElementById(id);
if(canvas == null)
return false;
//
if(!!!canvas.getContext){
alert("抱歉,你的瀏覽器不支持canvas!!");
return false;
}
context = canvas.getContext('2d');
width = canvas.width;
height = canvas.height;
i=0;
setInterval(rorate, 100);
}
function rorate(){
context.clearRect(0, 0, width, height);
context.fillStyle = 'red';
context.fillRect(i, 0, 20, 20);
i = i + 20;
if(i == 400){
i = 0;
}
}
四、多媒體播放
HTML 5提供了兩個新元素 —— video元素與audio元素,其中video元素專門用來播放網絡上的視頻或電影,而audio元素專門用來播放網絡上的音頻數據。
PS: 記得加controls="controls",不然不顯示播放控件,默認不會自動播放歌曲
另外,可以通過source元素來為同一個媒體數據指定多個播放格式與編碼格式,以確保瀏覽器可以從中選擇一種自己支持的播放格式進行播放,瀏覽器的選擇順序為代碼中的書寫順序,它會從上往下判斷自己對該播放格式是否支持。
<video controls="controls">
<source src="sample.ogv" type="video/ogg; codecs='theora, vorbis'">
<source src="sample.mov" type="video/quicktime">
</video>
type表示媒體類型,其屬性值為播放文件的MIME類型,該屬性中的codecs參數表示所使用的媒體的編碼格式。
1、屬性
- src 指定媒體數據的URL地址
- autoplay 指定媒體是否在頁面加載后自動播放(IOS不支持),<video src="ddd.mov" autoplay></video>
- preload 指定視頻或音頻數據是否預加載。該屬性有三個可選擇的值,none、metadata與auto,默認值為auto
-
- none表示不行預加載
- metadata表示只預加載媒體的元數據(媒體字節數,第一幀,播放列表、持續時間等)。
- auto表示預加載全部視頻或音頻
- poster(video獨有) 當視頻不可用時,可以使用該元素向用戶展示一幅替代圖片,<video src="ddd.mov" poster="cannotuse.jpg"></video>
- loop 指定是否循環播放
- controls 指定是否為視頻或音頻添加瀏覽器自帶的播放用的控制條 <video src="sample.mov" controls></video>,當然也可以自定義
- width與height(video獨有)
- error屬性 如果在媒體播放出問題時,error屬性將返回一個MediaError對象,該對象的code返回對應的錯誤狀態,錯誤狀態共有4個值:
-
- MEDIA_ERR_ABORTED(數字值為1): 下載過程由于用戶的操作原因而被終止
- MEDIA_ERR_NETWORK(數字值2):確認資源可用,但是在下載時出現網絡錯誤,下載過程被終止
- MEDIA_ERR_DECODE(數字值3):確認資源可用,解碼時發生錯誤
- MEDIA_ERR_SRC_NOT_SUPPORTED(數字值4):媒體資源不可用媒體格式不被支持
error屬性為只讀屬性
var video = document.getElementById("videoElement");
video.addEventListener("error", function(){
var error = video.error;
...
}
- networkState屬性 在媒體數據加載過程中可以使用video元素或audio元素的networkState屬性讀取當前網絡狀態,共有4個值:
-
- NETWORK_EMPTY(數字值為0):元素處于初始狀態
- NETWORK_IDLE(數字值1):瀏覽器已選擇好用什么編碼格式來播放媒體,但尚未建立網絡連接
- NETWORK_LOADING(數字值2):媒體加載中
- NETWORK_NO_SOURCE(數字值為3):沒有支持的編碼格式
var video = document.getElementById("videoElement");
video.addEventListener("progress", function(e){
var networkStateDisplay = document.getElementById("networkState");
if(video.networkState == 2){
//
}
.....
}
- currentSrc屬性 讀取URL地址: video/audio.currentSrc
- buffered屬性 可以使用video元素或audio元素的buffered屬性來返回一個對象,該對象實現TimeRanges接口,以確認瀏覽器是否已緩存媒體數據。
- readyState屬性 返回媒體當前播放位置的就緒狀態,共5個值:
-
- HAVE_NOTHING(數字值為0):沒有獲取到媒體的任何信息,當前播放位置沒有可播放數據
- HAVE_METADATA(數字值為1):獲取到的媒體數據無效,不能播放
- HAVE_CURRENT_DATA(數字值為2):當前媒體位置已經有數據可以播放,但沒有獲取到可以讓播放器前進的數據。
- HAVE_FUTURE_DATA(數字值為3):當前媒體位置已經有數據可以播放,獲取到可以讓播放器前進的數據。
- HAVE_ENOUGH_DATA(數字值為4):當前媒體位置已經有數據可以播放,獲取到可以讓播放器前進的數據,而且加載速度可以確保媒體順利播放
- seeking屬性與seekable屬性 seeking屬性可以返回一個布爾值,表示瀏覽器是否正在請求某一個特定播放位置的數據,seekable屬性返回一個TimeRanges對象,
- currentTime屬性、startTime屬性與duration屬性
currentTime當前播放位置,可以通過修改currentTime屬性來修改當前播放位置。startTime開始時間,通常為0。
duration總的播放時間
- played屬性、paused屬性、ended屬性
- defaultPlaybackRate屬性與playbackRate屬性 播放速率
- volume屬性與muted屬性 播放音量,0到1,1為最大,muted表示靜音狀態,布爾值。
2、方法
- play方法 將元素的paused屬性的值變為false
- pause方法 使用pause方法來暫停播放,自動將元素的paused屬性的值變為true
- load方法 使用load方法來重新載入媒體進行播放
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>video first Demo #######</title>
<script>
var video;
function init(){
video = document.getElementById("video1");
video.addEventListener("ended", function(){
alert("播放結束");
}, true);
video.addEventListener("error", function(){
switch(video.error.code){
case MediaError.MEDIA_ERROR_ABORTED:
alert("視頻的下載過程被中止");
break;
case MediaError.MEDIA_ERROR_NETWORK:
alert("網絡發生故障,視頻的下載過程被中止");
break;
case MediaError.MEDIA_ERROR_DECODE:
alert("解碼失敗");
break;
case MediaError.MEDIA_ERROR_SRC_NOT_SUPPORTED:
alert("不支持的視頻播放格式");
break;
default:
alert("未知錯誤");
}
}, false);
}
function play(){
video.play();
}
function pause(){
video.pause();
}
function next(){
if(video.src.indexOf("ren") > 0){
video.src = "KW7142.mp4";
}else{
video.src = "chonglangnanren.mp4";
}
}
</script>
</head>
<body onload="init()">
<video src="chonglangnanren.mp4" width="320" height="240" id="video1">
Your browser does not support the vedio element.
</video><br/>
<button onclick="play();">播放</button>
<button onclick="pause();">暫停</button>
<button onclick="next();">下一首</button>
</body>
</html>
- canPlayType 測試瀏覽器是否支持指定的媒體類型
var support = videoElement.canPlayType(type);
type值是MIME類型,與source元素的type參數一樣,該方法返回3個可能值:空字符,表示瀏覽器不支持;maybe,表示瀏覽器可能支持;probably,表示瀏覽器確定該類型。
PS:addEventListener,如果capture,兩個嵌套元素同一個事件發生從外元素開始觸發,如果bubbing,則內元素開始觸發
3、事件
3.1 事件介紹
- loadstart 瀏覽器開始在網上尋找媒體數據
- progress 瀏覽器正在獲取媒體數據
- suspend 瀏覽器暫停獲取媒體數據,但是下載過程并沒有結束
- abort 瀏覽器在下載完全部媒體數據之前中止獲取媒體數據,但是并不是有錯誤引起
- error 獲取媒體數據過程中出錯
- emptied video元素或audio元素所在網絡突然變為未初始化狀態,可能的原因有兩個:
-
- 載入媒體過程中突然發生一個致命錯誤
- 在瀏覽器正在選擇支持的播放格式時,又調用了load方法重新載入媒體
- stalled 瀏覽器嘗試獲取媒體數據失敗
- play 即將開始播放,當執行了play方法時觸發,或數據下載后元素被設為autoplay屬性
- pause 播放暫停,當執行了pause方法時觸發
loadedmetadata 瀏覽器獲取完畢媒體的時間長和字節數
loadeddata 瀏覽器加載完畢當前播放位置的媒體數據,準備播放
waiting 播放過程猶豫的得不到下一幀而暫停播放,但很快就能夠得到下一幀
playing 正在播放
canplay 瀏覽器能夠播放媒體,但估計以當前播放速率不能直接將媒體播放完畢
canplaythrough 瀏覽器能夠播放媒體,當前播放速率能直接將媒體播放完畢
seeking seeking屬性變為true,瀏覽器正在請求數據
seeked seeking屬性變為false,瀏覽器停止請求數據
timeupdate 當前播放位置被改變,可能是播放過程中的自然改變,也可能是被認為地改變,或由于播放不能連續而發生的跳變
ended 播放結束后停止播放
ratechange defaultplaybackRate屬性或playbackRate屬性被改變
durationchange 播放時長被改變
volumechange volume屬性被改變或muted屬性被改變
五、本地存儲
1、WebStorage
webstorage
分sessionStorage和localstorage,sessionStorage是臨時保存,localStorage是永久保存。
sessionStorage如果瀏覽器關閉了,數據就沒有了,而localStorage則不會。基本使用方法:
sessionStorage:
保存數據 sessionStorage.setItem(key, value);
讀取數據 sessionStorage.getItem(key);
localStorage:
保存數據 localStorage.setItem(key, value);
讀取數據 localStorage.getItem(key);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Web Storage示例</title>
<script type="text/javascript" src="webStorage.js"></script>
</head>
<body>
<h1>Web Storage 示例</h1>
<p id="msg"></p>
<input type="text" id="input">
<button onclick="saveStorage('input');">保存數據</button>
<button onclick="loadStorage('msg');">讀取數據</button>
</body>
</html>
function saveStorage(id){
var target = document.getElementById(id);
var str = target.value;
sessionStorage.setItem("message", str);
}
function loadStorage(id){
var target = document.getElementById(id);
var msg = sessionStorage.getItem("message");
target.innerHTML = msg;
}
如果使用得好,也可將webStorage作為一個簡易的數據庫,鍵的值采用JSON字符串就可以。當然這只是可以實現,運用的時候,webStorage的空間還是很珍貴的,一般大多數瀏覽器都只提供5M左右的空間。
2、本地數據庫
HTML 5的本地數據庫就是“SQLLite”文件型的SQL數據庫,首先使用openDatabase方法來創建一個訪問數據庫的對象。該方法的使用如下:
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
第一個參數是數據庫名稱,第二個參數為版本號,第三個參數為數據庫的描述,第四個參數為數據庫的大小。該方法返回創建后的數據庫訪問對象,如果該數據庫不
存在,則創建該數據庫。實際訪問數據庫的時候,還需要調用transaction方法,用來執行事務處理,防止在對數據庫操作的時候受外界打擾,組織別的
用戶操作數據庫。
db.transaction(function (tx){
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS(id unique, Log)');
});
transaction使用一個回調函數為參數,這個函數中,執行訪問數據庫的語句。函數里面tx其實就是SQLTransaction(事務),這個事務只有一個
executeSql方法。
executeSql(sqlQuery, [], dataHandler, errorHandler);
第一個參數是執行的語句,第二個是執行語句里面的參數,dataHandler成功執行返回處理,包含兩個參數tx,rs(結果集),errorHandler也包含兩個參數tx,error(錯誤信息)。
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE> HTML 5 SQLLite </TITLE>
<META charset="utf-8">
<SCRIPT type="text/javascript" src="webDB.js"></SCRIPT>
</HEAD>
<BODY onload="init();">
<h1>使用數據庫實現web留言板</h1>
<table>
<tr><td>姓名:</td><td><input type="text" id="name"/></td></tr>
<tr><td>留言:</td><td><input type="text" id="memo"/></td></tr>
<tr><td colspan="2"><button onclick="saveData();">保存</button></td></tr>
</table>
<!--創建一條水平線。 水平分隔線-->
<hr/>
<table id="datatable" border="1"></table>
<p id="msg"></p>
<button onclick="deleteAllData();">刪除所有數據</button>
</BODY>
</HTML>
JS:
var datatable = null;
var db = openDatabase("MyData", "", "My Database", 1024 * 1024);
function init(){
datatable = document.getElementById("datatable");
showAllData();
}
function removeAllData(){
for(var i=datatable.childNodes.length - 1; i>=0; i--){
datatable.removeChild(datatable.childNodes[i]);
}
var tr = document.createElement('tr');
var th1 = document.createElement('th');
var th2 = document.createElement('th');
var th3 = document.createElement('th');
th1.innerHTML = '姓名';
th2.innerHTML = '留言';
th3.innerHTML = '時間';
tr.appendChild(th1);
tr.appendChild(th2);
tr.appendChild(th3);
datatable.appendChild(tr);
}
function showData(row){
var tr = document.createElement('tr');
var td1 = document.createElement('td');
td1.innerHTML = row.name;
var td2 = document.createElement('td');
td2.innerHTML = row.message;
var td3 = document.createElement('td');
var t = new Date();
td3.innerHTML = t.toLocaleDateString() + " " + t.toLocaleTimeString();
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
datatable.appendChild(tr);
}
function showAllData(){
db.transaction(function(tx){
tx.executeSql("CREATE TABLE IF NOT EXISTS MsgData(name TEXT, message TEXT, time INTEGER)", []);
tx.executeSql("SELECT * FROM MsgData", [], function(tx, rs){
removeAllData();
for(var i=0; i < rs.rows.length; i++){
showData(rs.rows.item(i));
}
});
});
}
function addData(name, message, time){
db.transaction(function(tx){
tx.executeSql('INSERT INTO MsgData VALUES(?, ?, ?)'
, [name, message, time], function(tx, rs){
alert("保存數據成功!!");
}, function(tx, error){
alert(error.source + "::" + error.message);
}
);
});
}
function saveData(){
var name = document.getElementById("name").value;
var memo = document.getElementById("memo").value;
var time = new Date().getTime();
addData(name, memo, time);
showAllData();
}
function deleteAllData(){
db.transaction(function(tx){
tx.executeSql('DELETE FROM MsgData'
, [], function(tx, rs){
alert("刪除數據成功!!");
}, function(tx, error){
alert(error.source + "::" + error.message);
}
);
});
showAllData();
}
另外,在chrome里面Web Storage可以通過清理緩存什么的清除,但是SQLLite不可以,也不可以使用“drop
database dbName”語句清除數據庫,因為SQLLite歸根結底只是一個嵌入的數據庫,是一個文件,要到Chrome/User
Data里面去刪除文件。
六、離線Web應用
HTML 5提供了本地緩存,可以Web應用離線的情況下依然可以使用。
Web應用程序的本地緩存是通過每個頁面的manifest文件來管理的。manifest文件是一個簡單文本文件,在該文件以清單的形式列舉需要緩存
和不需要緩存的資源文件的名字,以及這些資源文件的訪問路徑。可以為每個頁面指定一個manifest文件,也可以為整個應用指定一個manifest文
件。
CACHE MANIFEST
#文件的開頭必須要書寫CACHE MANIFEST
#這個manifest文件的版本號
#version 7
CACHE:
other.html
hello.js
images/myphoto.jpg
NETWORK:
http://localhost/NotOffline
NotOffline.php
*
FALLBACK:
online.js locale.js
CACHE:
newhello.html
newhello.js
在manifest文件中,第一行必須是“CACHE MANIFEST”文字,以把本文件的作用告知給瀏覽器。同時,真正運行或測試離線Web應用程序的時候,
需要對服務器進行配置,讓服務器支持text/cache-manifest這個MIME類型(text/cache-manifest)。例如Apache服務器進行配置的時候,需要找到{apache_home}/conf/mine.types這個文件,并在文件最后添加一行代碼:
text/cache-manifest manifest
而在tomcat里面的配置則如下:
在 tomcat根目錄 -> conf -> web.xml 中的<web-app>內添加
<
mime-mapping
>
</div>
<
extension
>manifest</
extension
>
<
mime-type
>text/cache-manifest</
mime-type
>
</
mime-mapping
>
在指定資源文件的時候,可以把資源文件分為三類:分別是CACHE、NETWORK、FALLBACK。在CHACHE類別中指定需要被緩存在本地的資
源文件。NETWORK類別為顯示指定不進行本地緩存的資源文件。“*”為通配符,表示沒有在本manifest文件中指定的資源文件都不進行本地緩存。
FALLBACK類別中的每行中指定兩個資源文件,第一個資源文件為能夠在線訪問時使用的文件,第二個為為不能聯網時使用的資源文件。
允許在同一個manifest文件中重復書寫同一個類別。
為了讓瀏覽器能夠正常閱讀該文本文件,需要在Web應用程序頁面上的html標簽的manifest屬性由指定manifest文件的URL地址。指定方法如下:
<html manifest="hello.manifest">
...
</html>
瀏覽器在與服務器交互時,會檢查manifest文件是否更改,如果更改,則會根據manifest的要求把資源文件緩存。緩存之后,會觸發applicationCache
對象的updateready事件:
applicationCache.addEventListener( "updateready",function(){
alert("本地緩存已經更新,請刷新頁面查看最新應用!");
});
PS:
資源文件修改了,如果manifest文件沒有修改,緩存頁面是不會更新的,也就是用戶不會看到最新的應用,如果你對緩存的要求沒有修改,那么可以通過
修改manifest文件的version版本號來提示瀏覽器更新緩存
另外可以通過applicationCache對象的swapCache手工執行本地緩存的更新,它只能在applicationCache對象的updateReady事件被觸發時調用。
updateReady就是服務器manifest有更新,并且已經把緩存的文件都已經下載到本地了。之后就可以執行swapCache更新。這樣就可以
控制頁面是否立即更新緩存,因為可能用戶正在做一些重要的操作,不想立即更新緩存。可以使用confirm方法讓用戶選擇更新的時機。
applicationCache.addEventListener(</span></span>
"updateready",function(){</span></span> </div>
alert("正在更新本地緩存,請稍等....");
applicationCache.swapCache();
alert("本地緩存已被更新,您可以刷新頁面來得到本程序的最新版本");
});
applicationCache對象的另一個方法applicationCache.update,該方法的作用是檢查服務器上的manifest文件是否有更新。
applicationCache除了一些方法之外當然也有一些事件監聽,
詳細。
七、通信API
1、跨文檔消息傳輸
HTML 5提供了網頁文檔之間互相接受和發送消息的功能。接受消息的網頁需要做監聽:
window.addEventListener("message", function{...}, false);
發送消息的頁面傳輸消息的方法:
window.postMessage(message, targetOrigin);
targetOrigin為接受消息的網頁URL地址
早期做過的一個
Demo,如文所述,IE8的監聽不是message,而是onmessage。
2、Web Sockets
Web Sockets是HTML 5提供的Web應用中客戶端和服務器端
非HTTP 的通信機制。可以實現HTTP不易實現的功能,比如消息推送。這個鏈接是雙向的,實時且永久的,除非顯示關閉。
var websocket = new WebSockets("ws://localhost:8080/socket");
將URL字符串作為參數傳入,通過調用WebSockets對象的構造器實現與服務器端建立通信。 URL字符串必須以“ws”或“wss”(加密通信時)文字作為開頭。
websocket.send(data);
通過send方法發送信息
websocket.onmessage = function(event){
var data = event.data;
...
}
通過onmessage屬性接收服務器傳來的信息
websocket.onopen = function(event){
//開通通信時處理
}
監聽socket打開事件
websocket.onclose = function(event){
//開通通信時處理
}
監聽socket關閉事件
websocket.close();
切斷通信
另外可以通過readyState的屬性值來獲取WebSocket對象的狀態:
CONNECTING(數值為0):表示正在連接
OPEN(數字值為1):表示已建立連接
CLOSING(數字值為2):表示正在關閉
CLOSED(數字值為3):表示已經關閉
<!DOCTYPE HTML>
<html>
<head>
<title>Web Socket Demo -- EchoClient</title>
<meta charset="utf-8">
</head>
<script type="text/javascript">
var websocket = null;
function connect(){
var msg = document.getElementById("msg");
try{
var readyState = new Array("正在連接", "已建立連接", "正在關閉連接"
, "已關閉連接");
var host = "ws://localhost:8000";
websocket = new WebSocket(host);
websocket.onopen = function(){
msg.innerHTML += "<p>Socket狀態: " + readyState[websocket.readyState] + "</p>";
}
websocket.onmessage = function(event){
msg.innerHTML += "<p>接收信息: " + event.data + "</p>";
}
websocket.onclose = function(){
msg.innerHTML += "<p>Socket狀態: " + readyState[websocket.readyState] + "</p>";
}
msg = document.getElementById("msg");
msg.innerHTML += "<p>Socket狀態: " + readyState[websocket.readyState] + "</p>";
}catch(exception){
msg.innerHTML += "<p>有錯誤發生</p>";
}
}
function send(){
var msg = document.getElementById("msg");
var text = document.getElementById("text").value;
if(text == ""){
msg.innerHTML += "<p>請輸入一些文字</p>";
return;
}
try{
websocket.send(text);
msg.innerHTML += "<p>發送數據: " + text + "</p>";
}catch(exception){
msg.innerHTML += "<p>發送數據出錯</p>";
}
document.getElementById("text").value = "";
}
function disconnect(){
websocket.close();
}
</script>
<body>
<h1>WebSocket客戶端實例</h1>
<div id="msg" style="height: 300px;"></div>
<p>請輸入一些文字</p>
<input type="text" id="text"/>
<button id="connect" onclick="connect();">建立連接</button>
<button id="send" onclick="send();">發送數據</button>
<button id="disconnect" onclick="disconnect();">斷開連接</button>
</body>
</html>
服務端:
package socket;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
public class EchoServer {
private int port = 8000;
private ServerSocket serverSocket;
public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
System.out.println("服務器啟動");
}
private void service() {
Socket socket = null;
while (true) {
try {
socket = serverSocket.accept();
Thread workThread = new Thread(new Handler(socket));
workThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Handler implements Runnable {
private Socket socket;
private boolean hasHandshake = false;
Charset charset = Charset.forName("UTF-8");
public Handler(Socket socket) {
this.socket = socket;
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut, true);
}
public String echo(String msg) {
return "echo:" + msg;
}
public void run() {
try {
System.out.println("New connection accepted"
+ socket.getInetAddress() + ":" + socket.getPort());
InputStream in = socket.getInputStream();
PrintWriter pw = getWriter(socket);
//讀入緩存
byte[] buf = new byte[1024];
//讀到字節
int len = in.read(buf, 0, 1024);
//讀到字節數組
byte[] res = new byte[len];
System.arraycopy(buf, 0, res, 0, len);
String key = new String(res);
if(!hasHandshake && key.indexOf("Key") > 0){
key = key.substring(0, key.indexOf("==") + 2);
key = key.substring(key.indexOf("Key") + 4, key.length()).trim();
key+= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(key.getBytes("utf-8"), 0, key.length());
byte[] sha1Hash = md.digest();
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
key = encoder.encode(sha1Hash);
pw.println("HTTP/1.1 101 Switching Protocols");
pw.println("Upgrade: websocket");
pw.println("Connection: Upgrade");
pw.println("Sec-WebSocket-Accept: " + key);
pw.println();
pw.flush();
hasHandshake = true;
//接收數據
byte[] first = new byte[1];
int read = in.read(first, 0, 1);
while(read > 0){
int b = first[0] & 0xFF;
//boolean fin = (b & 0x80) > 0;
// int rsv = (b & 0x70) >>> 4;
byte opCode = (byte) (b & 0x0F);
if(opCode == 8){
socket.getOutputStream().close();
break;
}
b = in.read();
// Client data must be masked
if ((b & 0x80) == 0) {
//NO-DO
}
int payloadLength = b & 0x7F;
if (payloadLength == 126) {
byte[] extended = new byte[2];
in.read(extended, 0, 2);
int shift = 0;
payloadLength = 0;
for (int i = extended.length - 1; i >= 0; i--) {
payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
shift += 8;
}
} else if (payloadLength == 127) {
byte[] extended = new byte[8];
in.read(extended, 0, 8);
int shift = 0;
payloadLength = 0;
for (int i = extended.length - 1; i >= 0; i--) {
payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
shift += 8;
}
}
//掩碼
byte[] mask = new byte[4];
in.read(mask, 0, 4);
int readThisFragment = 1;
ByteBuffer byteBuf = ByteBuffer.allocate(payloadLength + 10);
byteBuf.put("echo: ".getBytes("UTF-8"));
while(payloadLength > 0){
int masked = in.read();
masked = masked ^ (mask[(int) ((readThisFragment - 1) % 4)] & 0xFF);
byteBuf.put((byte) masked);
payloadLength--;
readThisFragment++;
}
byteBuf.flip();
responseClient(byteBuf, true);
printRes(byteBuf.array());
in.read(first, 0, 1);
}
}
in.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 方法說明:
* @開發:linrb
* @創建時間:2012-8-14
* @param byteBuf
* @throws IOException
*/
private void responseClient(ByteBuffer byteBuf, boolean finalFragment) throws IOException {
OutputStream out = socket.getOutputStream();
int first = 0x00;
//是否是輸出最后的WebSocket響應片段,默認
if (finalFragment) {
first = first + 0x80;
first = first + 0x1;
}
out.write(first);
if (byteBuf.limit() < 126) {
out.write(byteBuf.limit());
} else if (byteBuf.limit() < 65536) {
out.write(126);
out.write(byteBuf.limit() >>> 8);
out.write(byteBuf.limit() & 0xFF);
} else {
// Will never be more than 2^31-1
out.write(127);
out.write(0);
out.write(0);
out.write(0);
out.write(0);
out.write(byteBuf.limit() >>> 24);
out.write(byteBuf.limit() >>> 16);
out.write(byteBuf.limit() >>> 8);
out.write(byteBuf.limit() & 0xFF);
}
// Write the content
out.write(byteBuf.array(), 0, byteBuf.limit());
out.flush();
}
/**
* 方法說明:
* @開發:linrb
* @創建時間:2012-8-14
* @param array
*/
private void printRes(byte[] array) {
ByteArrayInputStream byteIn = new ByteArrayInputStream(array);
InputStreamReader reader = new InputStreamReader(byteIn, charset.newDecoder());
int b = 0;
String res = "";
try {
while((b = reader.read()) > 0){
res += (char)b;
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(res);
}
}
public static void main(String[] args) throws IOException {
new EchoServer().service();
}
}
八、Web Workers
Web Worker是HTML 5提供的一種后臺線程,線程下面可以有子線程。但是線程不能調用document和頁面的元素。但是,頁面交互其實可以讓前臺處理。并且前后可以進行數據交互。這樣可以避免,猶豫前臺JS處理時間過長導致頁面奔潰。
1、數據交互
創建對象:
var worker = new Worker("腳本路徑");
可以在前臺里面持有worker對象,然后通過:
worker.onmessage = function(event){
//處理后臺線程傳過來的數據
}
worker.postMessage(message);
進行數據交互,當然如果要傳對象的話,把對象通過JSON對象的stringify方法轉成文本傳入就行。后臺的js腳本里面也通過調用onmessage 和 postMessage與前臺交互。
<!DOCTYPE HTML>
<html>
<head>
<title>Worker Demo 1 ###1</title>
<meta charset="utf-8">
</head>
<script type="text/javascript">
var worker = new Worker("js/SumCalculate.js");
worker.onmessage = function(event){
alert("結果為:" + event.data);
}
function calculate(){
var val = document.getElementById("inputVal").value;
if(val != null && !isNaN(val) && parseInt(val) > 1){
worker.postMessage(parseInt(val));
}else{
alert("請輸入大于1的整數!!");
}
}
</script>
<body>
<hgroup>
<h1>Worker Demo 1</h1>
<h2>運算1到輸入指定數字遞增數列的值</h2>
</hgroup>
<section>
<input type="text" id="inputVal" placeholder="請輸入大于1的整數"/>
<button onclick="calculate();">提交</button>
</section>
</body>
</html>
JS:
onmessage = function(event){
var data = event.data;
var result = 0;
for(var i=0; i <= data; i++){
result += i;
}
postMessage(result);
}
PS: Chrome需要服務器才能運行,Opera和FF則不用
當然也可以使用線程嵌套,主線程下面創建子線程。只是
Chrome,WebKit內核的目前不支持,線程下面創建子線程。
2、線程可用變量、函數與類
2.1 self
self關鍵詞用來表示本線程范圍內的作用域
2.2 postMessage(message)
向線程的源窗口發送消息
2.3 onmessage
獲取接受消息的事件句柄
2.4 importScripts(url)
導入其他JavaScript腳本文件,需保證同域同端口。
2.5 navigator對象
與window.navigator對象類似,具有appName、platform、userAgent、appVersion這些屬性。
2.6 sessionStorage/localStorage
可以在線程中使用Web Storage
2.7 XMLHttpRequest
可以在線程中處理Ajax請求
2.8 setTimeout()/setInterval()
可以在線程中實現定時處理
2.9 close
可以結束本線程
2.10 eval()、isNaN()、escape()等
可以使用所有JS核心函數
2.11 object
可以創建和使用本地對象
2.12 WebSocket
可以使用WebSocket API來想服務器發送和接受信息
九、Geolocation API
PS: 這章不怎么詳記,限制比較多,使用起來諸多問題
在HTML 5中,提供了Geolocation API,不過通過《HTML 5 揭秘》這本書了解到。獲取地理位置,PC主要是通過你使用的運營商分給的IP地址,手機是通過信號基站和GPS,另外
PC獲取地址還是得需要用戶授權。HHTML 5 中,為window.navigator對象新增了一個geolocation屬性,可以使用Geolocation API來對該屬性進行訪問。
1、取得當前位置
navigator.geolocation.getCurrentPosition(onSuccess, onError, options);
第一個參數為獲取當前位置信息成功時所執行的回調函數,第二個是失敗的回調函數,第三個是可選屬性的列表,第二、三個參數是可選的。可選屬性有(列舉部分):
- enableHighAccuracy: 是否要求高級毒的地理位置(很多設備沒有)
- timeout: 獲取地址超時限制
- maximumage: 獲取地理信息進行緩存下來的有效時間
</ul>
</div>
2、持續監視
navigator.geolocation.watchCurrentPosition(onSuccess, onError, options);
該方法有點類似JS的setInterval方法,可以通過clearWatch方法停止當前位置監視。
demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Geolocation</title>
<style>
body {background-color:#fff;}
</style>
</head>
<body>
<p id="geo_loc"><p>
<script>
function getElem(id) {
return typeof id === 'string' ? document.getElementById(id) : id;
}
function show_it(lat, lon) {
var str = '您當前的位置,緯度:' + lat + ',經度:' + lon;
getElem('geo_loc').innerHTML = str;
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
show_it(position.coords.latitude, position.coords.longitude);
}, function(err) {
getElem('geo_loc').innerHTML = err.code + "\n" + err.message;
});
} else {
getElem('geo_loc').innerHTML = "您當前使用的瀏覽器不支持Geolocation服務";
}
</script>
</body>
</html>
google Map:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Geolocation</title>
<style>
body {background-color:#fff;}
</style>
</head>
<body>
<p id="map_canvas"><p>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script>
function getElem(id) {
return typeof id === 'string' ? document.getElementById(id) : id;
}
function success(position) {
var mapcanvas = document.createElement('div');
mapcanvas.id = 'mapcanvas';
mapcanvas.style.height = '400px';
mapcanvas.style.width = '560px';
getElem("map_canvas").appendChild(mapcanvas);
var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var myOptions = {
zoom: 15,
center: latlng,
mapTypeControl: false,
navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("mapcanvas"), myOptions);
var marker = new google.maps.Marker({
position: latlng,
map: map,
title:"你在這里!"
});
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success);
} else {
alert("您當前使用的瀏覽器不支持geolocation服務");
}
</script>
</body>
</html>
本文由用戶
openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!