1、主体结构元素
<article>
<header>
<h1>苹果</h1>
<p>发表日期:<time pubdate="pubdate">2010/10/09</time></p>
</header>
<p><b>苹果</b>, 植物类水果,多次花果.....("苹果"文章正文)</p>
<footer>
<p><small>著作版权###公司所有。</small></p>
</footer>
</article> article元素是可以嵌套使用的,内层的内容再原则上需要与外层的内容相关联。例如,一篇博文,针对该文章的评论就可以使用嵌套article。(pubdate代表发布时间)
....
<p><b>苹果</b>, 植物类水果,多次花果.....("苹果"文章正文)</p>
<section>
<h2>评论</h2>
<article>
<header>
<h3>发表者:lucy</h3>
<p>
<time pubdate datetime="2010-10-10T19:00-08:00">
1小时前
</time>
</p>
<header>
</article>
<article>...</article>
</section>
</article>
article元素也可以用来表示插件,它的作用是使插件看起来好像内嵌在页面中。
<article>
<h1>My Fruit Spinner</h1>
<object>
<param name="allowFullScreen" value="true">
<embed src="#" width="600" height="395"></embeb>
</object>
</article>
section元素用于对网站或应用程序中页面上的内容进行分块。section元素由内容和标题组成。但section元素是一个特殊的容器元素,当一 个容器需要被直接定义样式或通过脚本定义行为时,推荐使用div而非section元素。通常不推荐位那些没有标题的内容使用section元素。
<body>
<h1>技术资料</h1>
<nav>
<ul>
<li><a href="/">主页</a></li>
<li><a herf="/events">开发文档</a></li>
</ul>
</nav>
<article>
<header>
<h1> HTML 5 与 CSS 3的历史</h1>
<nav>
<ul>
<li><a href="#HTML 5">HTML 5的历史</a></li>
<li><a href="#CSS 3">CSS 3的历史</a></li>
</ul>
</nav>
</header>
<section id="HTML 5">
<h1>HTML 5的历史</h1>
<p>讲述HTML 5的历史的正文</p>
</section>
<section id="CSS 3">
<h1>CSS 3的历史</h1>
<p>讲述CSS 3的历史的正文</p>
</section>
..。
<footer>
<p>
<a href="?edit">编辑</a> |
<a href="?delete">删除</a> |
<a href="?rename">重命名</a>
</p>
</footer>
</article>
<footer>
<p><small>版权所有...</small></p>
</footer>
</body>
nav元素可以用于以下这些场合
传统导航条
侧边栏导航
页内导航
翻页操作
aside元素用来表示当前页面或文章的附属信息部分,它可以包含与当前页面或主要内容相关的引用、侧边栏、广告、导航条
有些机器编码过程会对时间产生歧义,HTML 5增加了一个新的元素来无歧义地、明确地对机器的日期和时间进行编码,并且以让人易读的方式来展示它
<time datetime="2010-11-13">2010年11月13日</time>
<time datetime="2010-11-13T20:00">我生日的晚上8点</time>
编码时机器读到的部分在datetime属性里,而元素的开始标记和结束标记中间的部分显示在网页上。
<header>
<hgroup>
<h1>IT 新技术</h1>
<a href="http://blog.sina.com.cn/itnewtech">
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> 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>内添加
<
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( "updateready",function(){ 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: 获取地理信息进行缓存下来的有效时间
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>