HTML5 基础知识,第 3 部分 HTML5 API 之应用-介绍HTML5 API 的用法和价值,Canvas 提供的创造性,以及Web storage的离线应用
HTML5 集设计者和开发者于一身,其主要任务就是构建高效的丰富 Internet 应用程序之富网络应用
(Rich Internet Application,简称RIA),尤其是富 UI(User Interface,用户界面)。所说的高效是指进行系统的、全面的改进,以数字的方式为站点所有者、所有者代理和站点使用者之间的对话提供便利。
RIA 是满足用户体验的本源和工具,因此也是任何以网络为中心的成功企业的关键组成部分。实质上,以网络为中心的活动在某种程度上是协作性的活动。当机构想在各个级别(包括市场营销和管理)上取得成功时,实现数字协作的成功方法至关重要。站点的成功主要取决于站点满足访问用户的质量要求的效率。
如您所见,HTML5 是专门为实现具有跨平台功能、融合电信、统一语言、广泛计算和开源系统的协作式 “网络世界” 而量身定制的。符合逻辑的 RIA 是丰富用户体验的创建和管理,对于实现站点目标是重要的。HTML5 API 在开发高效 RIA 的过程中扮演重要角色。
一、什么是 API?
API是Application Programming Interface(应用程序编程接口)的缩写,它是编程指令集合和访问软件应用程序的标准。通过调用一个 API,可以利用 API 提供的服务设计出强大的产品。
HTML5 提供了一些 API:
- 用于渲染图形或其他可视图像的新 canvas 元素所使用的 2D 绘图 API
- 支持离线 Web 应用程序的缓存 API
- 使用新 video 和 audio 元素来播放视频和音频的 API
- 支持浏览历史访问和添加页面的历史 API
- draggable 属性支持的拖放 API
- contenteditable 属性支持的编辑 API
- 使用 JavaScript API 进行键-值对存储的客户端存储及嵌入式 SQL 数据库
二、什么是 Canvas?
HTML5 Canvas 是一个极其有用的绘制和动画元素。Canvas 使用 JavaScript 直接在页面上绘制图形。Canvas 能够定义和控制矩形区域,并允许以动态方式或通过脚本呈现 2D 形状和位图。
对于生成能够增强 UI、图表、相册、图形、动画和嵌入式绘制应用程序的出色视觉材料而言,HTML5 Canvas 非常完美。Canvas 元素可以通过几种方法来绘制路径、矩形、圆形和字符。
1. Canvas 坐标
在画布上进行绘制的前提条件是熟悉网格和坐标空间。空间区域的长度和宽度的单位为像素。用户可以围绕 x 和 y 坐标构建画布。当坐标为 x=0, y=0
时,画布原点位于左上角
。 如图1所示。
图 1. x、y坐标
矩形画布区域的默认宽度为 300 像素,高度为 150 像素
,但您可以通过修改这两个属性来获得所需的画布大小。图2 显示了如何实现 x 和 y 坐标。
图 2. 画布坐标
图 2 显示了长宽都为 100 像素的画布区域:
- 左上角的坐标为 x=0, y=0。
- x 值在水平方向增加,而 y 值在垂直方向增加。
- 右下角的坐标为 x=100, y=100。
- 中心点的坐标为 x=50, y=50。
2. 起步
在向画布添加内容之前,必须先在 HTML 文件中定义画布,必须创建 JavaScript 代码,用它来访问 标记并与 HTML5 Canvas API 通信,这样就可以绘制图形。
标记的基本结构为:
canvas 标记有两个专有的属性:width 和 height。此外,Canvas 还拥有所有关键的 HTML5 属性,比如 class、id 和 name。在上面显示的代码中就用到了 id 属性。JavaScript 代码使用这里创建的画布 id 来识别要绘制内容的画布。
JavaScript代码使用 document.getElementById()
方法来确定正确的画布:
var canvas = document.getElementById("myCanvas");
每个画布都必须有一个上下文对象定义。到目前为止,官方的规范仅识别 2D 环境(3D绘图通过“webgl”参数创建上下文对象,仅对支持WebGL的浏览器有效):
var context = canvas.getContext("2d");
在识别画布并指定其上下文之后,就可以在其上绘制内容了。
3. 绘制工具、效果和变形
讨论描述HTML5 Canvas 将用到的各种绘制工具、效果和变形。
这些绘制工具包括:
- 线条
- 矩形
- 弧形
- 贝塞尔曲线和二次方曲线
- 圆形和半圆形
将使用的画布效果包括:
- 填充和笔触
- 线性渐变和辐射渐变
要讨论的变形包括:
- 缩放
- 旋转
- 转换
绘制线条
要在画布上绘制线条,使用到的方法:
- context.beginPath();
- context.moveTo(x,y);
- context.lineTo(x,y);
- context.stroke(x,y);
beginPath()
方法将启用一个新路径。在使用不同的子路径绘制新的线条之前,必须使用 beginPath()
来表明绘制的新起点。首次绘制线条时没有必要调用 beginPath()
方法。
moveTo()
方法会声明新的子路径的开始点。lineTo()
方法用于创建子路径。可以通过lineWidth
和 strokeStyle
改变线条的外观。lineWidth
元素用于改变线条的粗细,而 strokeStyle
则用于改变线条的颜色。
方法moveTo()和lineTo()实际上并不画线,而是在结束canvas操作的时候,通过调用stroke()
方法完成线条的绘制。
对上下文的很多操作都不会立即反映页面上。beginPath()
、moveTo()
、lineTo()
这些函数都不会直接修改canvas
的展示结果。canvas
中很多用于设置样式和外观的函数也同样不会直接修改显示结果。只有当对上下文对象应用绘制方法stroke()
或填充方法fill()
时,结果才会显示出来。
在图 3 中,分别绘制了蓝色、绿色和紫色的线条。
图 3. 画布线条
图 3 中的线条是通过 '清单 1' 中的代码创建的。
清单 1. 在画布上创建 3 个颜色不同的线条
<!DOCTYPE HTML>
<html>
<head>
<title>线条示例</title>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// 圆形端的蓝色线
context.beginPath();
context.moveTo(50, 50);
context.lineTo(300,50);
context.lineWidth = 10;
context.strokeStyle = "#0000FF";
context.lineCap = "round";
context.stroke();
// 方形端的绿色线
context.beginPath();
context.moveTo(50, 100);
context.lineTo(300,100);
context.lineWidth = 20;
context.strokeStyle = "#00FF00";
context.lineCap = "square";
context.stroke();
// 平头端的紫色线
context.beginPath();
context.moveTo(50, 150);
context.lineTo(300, 150);
context.lineWidth = 30;
context.strokeStyle = "#FF00FF";
context.lineCap = "butt";
context.stroke();
};
</script>
</head>
<body>
<canvas id="myCanvas" width="400" height="200">
</canvas>
</body>
</html>
蓝色的线条两端是圆角的,创建它的时候,首先要确定一个新路径即将开始:context.beginPath()
。其创建过程如下所示:
- context.moveTo(50, 50),将路径的开始点置于 (x=50, y=50)
- context.lineTo(300,50),识别线条的结束点
- context.lineWidth = 10,线条的宽度
- context.strokeStyle = "#0000FF",线条的颜色
- context.lineCap = "round",使线条的两端变圆
- context.stroke(),真实地将线条绘制在画布上
上面的 3 个线条的长度都是 50 像素,但它们看起来不一样长,这是由线条两端套盖 (cap) 引起的视觉混淆。有 3 种可用的末端套盖:
- context.round(圆形)
- context.square(方形)
- context.butt(平头形,默认)
butt 套盖是默认值。使用 round 或 square 套盖样式时,线条的长度将增加,增加的量为线条自身的宽度。例如,如果长度为 200 像素、宽度为 10 像素的线条采用 round 或 square 套盖样式,那么将导致线条的长度变为 210 像素,因为将在线条的两端各增加一个长度为 5 像素的套盖。如果长度为 200 像素、宽度为 20 像素的线条采用 round 或 square 套盖样式,那么将导致线条的长度变为 220 像素,因为将在线条的两端各增加一个长度为 10 像素的套盖。
绘制矩形
在画布上绘制矩形区域有 3 种方法:
- fillRect(x,y,width,height),绘制已填充的矩形
- strokeRect(x,y,width,height),绘制矩形框线
- clearRect(x,y,width,height),擦除矩形的给定区域使之完全透明
对于这 3 种方法而言,x 和 y 表示矩形在画布上相对于左上角的位置(x=0, y=0),而 width 和 height 分别是矩形的宽度和高度。
图 4 显示了由 清单 2 中的代码创建的 3 个矩形区域。
图 4. 矩形画布
fillRect()
方法创建了一个矩形并使用默认的黑色填充它。clearRect()
方法在第一个矩形的中心擦除一块矩形区域,该区域位于 fillRect() 方法所创建的矩形的中心。strokeRect()
方法创建一个仅黑色边框可见的矩形。
清单 2. 矩形画布代码
<!DOCTYPE HTML>
<html>
<head>
<title>Rectangle Example</title>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #000000;
background-color: #ffff00;
}
</style>
<script type="text/javascript">
function drawShape(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.fillRect(25,25,50,50);
context.clearRect(35,35,30,30);
context.strokeRect(100,100,50,50);
}
</script>
</head>
<body onload="drawShape();">
<canvas id="myCanvas" width="200" height="200"></canvas>
</body>
</html>
绘制弧形、曲线、圆形和半圆形
绘制圆形和半圆形都使用 arc() 方法。arc() 方法接收 6 个参数:
context.arc(centerX, centerY, radius, startingAngle, endingAngle, antiClockwise);
centerX 和 centerY 参数是圆心的坐标。radius 的含义和其数学上半径的含义一样:表示从圆心到圆周的直线距离。所创建的弧形将作为圆形的一部分。startAngle 和 endAngle 参数分别为弧形的起点和终端,单位为弧度。anticlockwise 参数是一个布尔值。当其值为 true 时,弧形就逆时针绘制;当为 false 时,弧形就顺时针绘制。
要使用 arc() 方法绘制圆形,将起始角度定义为 0,结束角度为 2*PI,如下所示:
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
要使用 arc() 方法绘制半圆形,将结束角度定义为 startingAngle + PI,如下所示:
context.arc(centerX, centerY, radius, startingAngle, startingAngle + Math.PI, false);
二次方曲线
使用 quadraticCurveTo() 方法创建二次方曲线 ,如下所示。二次方曲线由上下文点、控制点和结束点定义。控制点确定线条的曲度。
context.moveTo(x, y);
context.quadraticCurveTo(controlX, controlY, endX, endY);
贝塞尔曲线
与二次方曲线一样,贝塞尔(Bezier)曲线也有一个起始点和一个结束点;但与二次方曲线不同的是,它有两个控制点:
context.moveTo(x, y);
context.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
使用 bezierCurveTo() 方法来创建贝塞尔曲线。因为贝塞尔曲线通过两个而不是一个控制点来定义,所以可以创建更加复杂的曲线。
图 5 从左到右分别显示了弧形、二次方曲线、贝塞尔曲线、半圆形和圆形。
图 5. 弧形、曲线和圆形
清单 3. 弧形、曲线和圆形的代码
<!DOCTYPE HTML>
<html>
<head>
<title>圆弧,曲线,圆和半圆</title>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script>
function drawArc(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var centerX = 100;
var centerY = 160;
var radius = 75;
var startingAngle = 1.1 * Math.PI;
var endingAngle = 1.9 * Math.PI;
var counterclockwise = false;
context.arc(centerX, centerY, radius, startingAngle,
endingAngle, counterclockwise);
context.lineWidth = 10;
context.strokeStyle = "black";
context.stroke();
};
function drawQuadratic(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.moveTo(200, 150);
var controlX = 288;
var controlY = 0;
var endX = 388;
var endY = 150;
context.quadraticCurveTo(controlX, controlY, endX, endY);
context.lineWidth = 10;
context.strokeStyle = "black";
context.stroke();
};
function drawBezier(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.moveTo(350, 350);
var controlX1 = 440;
var controlY1 = 10;
var controlX2 = 550;
var controlY2 = 10;
var endX = 500;
var endY = 150;
context.bezierCurveTo(controlX1, controlY1, controlX2,
controlY2, endX, endY);
context.lineWidth = 10;
context.strokeStyle = "black";
context.stroke();
};
function drawCircle(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var centerX = 450;
var centerY = 375;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = "#800000";
context.fill();
context.lineWidth = 5;
context.strokeStyle = "black";
context.stroke();
};
function drawSemicircle(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var centerX = 100;
var centerY = 375;
var radius = 70;
var lineWidth = 5;
context.beginPath();
context.arc(centerX, centerY, radius, 0, Math.PI, false);
context.closePath();
context.lineWidth = lineWidth;
context.fillStyle = "#900000";
context.fill();
context.strokeStyle = "black";
context.stroke();
};
window.onload = function (){
drawArc();
drawQuadratic();
drawBezier();
drawCircle();
drawSemicircle()
}
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="500">
</canvas>
</body>
</html>
变形、缩放和旋转
变形、缩放和旋转
translate()、scale() 和 rotate() 方法都用于修改当前的图形。translate(x, y)
方法将画布上的元素移动到网格上的不同点。在 translate(x,y) 方法中,(x,y)
坐标表明图像在 x 轴和 y 轴方向上应该移动的像素数。
如果使用 drawImage()
方法在 (15,25) 位置上绘制图形,那么可以使用参数为 (20,30) 的 translate() 方法,将图形放在 (15+20, 25+30) = (35, 55) 的位置上。
scale(x,y)
方法可改变图形的大小。x 参数指定水平缩放因素,而 y 参数指定垂直缩放因素。例如,scale(1.5, .75) 创建的图形比当前图形在 x 轴方向上大 50%,在 y 轴上大 75%。rotate(angle)
方法可根据指定的角度来选择对象。
图 6 展示了可以使用 translate()、scale() 和 rotate() 方法呈现的内容。
图 6. 使用变形
清单 4. 创建变形的代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>转换示例</title>
<script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var rectWidth = 250;
var rectHeight = 75;
// 将上下文对象移到画布中心
context.translate(canvas.width / 2, canvas.height / 2);
// y分量的一半
context.scale(1, 0.5);
// 顺时针旋转45度
context.rotate(-Math.PI / 4);
context.fillStyle = "blue";
context.fillRect(-rectWidth / 2, -rectHeight / 2, rectWidth, rectHeight);
// 水平翻转上下文
context.scale(-1, 1);
context.font = "30pt Calibri";
context.textAlign = "center";
context.fillStyle = "#ffffff";
context.fillText("镜像转换", 3, 10);
}
</script>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
</body>
</html>
4. 渐变
渐变就是从一种颜色过渡到另一种颜色的填充过程,两种颜色相交时会进行混合。可在画布中创建的渐变有两种:线性和辐射性的。
可以使用createLinearGradient()
方法创建线性渐变。createLinearGradient(x0,y0,x1,y1)
沿着由两个点识别到的直线生成渐变:(x0,y0)
和 (x1,y1)
分别是渐变的起点和终点。该方法返回一个对象。
彩色渐变可以使用多种颜色。addcolorStop(offset, color)
方法根据给定的偏移量指定颜色停止点。addColorStop()
方法允许指定介于 0 和 1 之间的偏移量,在该偏移量后将开始渐变到另一种颜色。值 0
是渐变的一端的偏移量;1
是渐变的另一端的偏移量。在定义了颜色渐变之后,就可以将渐变对象分配给 fillStyle()
。还可以通过 fillText() 方法使用渐变绘制文本。
辐射渐变可以使用 createradialGradient(x0,y0,r0,x1,y1,r1)
来实现,用六个参数将两种或多种颜色以圆形或锥形的图案融合在一起:
- (x0,y0) 圆锥的第一个圆形的中心
- r0 第一个圆形的半径
- (x1,y1) 圆锥的第二个圆形的中心
- r1 第二个圆形的半径
图 7 包含 4 个渐变:一个线性渐变、一个文本渐变、一个对角线性渐变和一个辐射渐变。
图 7. 渐变示例
清单 5. 渐变示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>渐变示例</title>
<script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
//让我们尝试矩形上的渐变
// 创建线性渐变
var fillColor = context.createLinearGradient(50, 50, 150, 50);
// 设置渐变颜色
fillColor.addColorStop(0.15, "red");
fillColor.addColorStop(0.35, "black");
fillColor.addColorStop(0.65, "green");
fillColor.addColorStop(0.87, "yellow");
// 将渐变对象分配给fillstyle
context.fillStyle = fillColor;
// 画矩形
context.fillRect(50, 50, 100, 100);
// 带文字
var fillColorText = context.createLinearGradient(300, 50, 600, 50);
fillColorText.addColorStop(0.2, "red");
fillColorText.addColorStop(0.4, "black");
fillColorText.addColorStop(0.6, "green");
fillColorText.addColorStop(0.8, "yellow");
context.fillStyle = fillColorText;
context.font = "40px verdana";
context.textBaseline = "top";
context.fillText("With text too!", 300, 50)
// 对角线上的渐变
var fillColordiagonal = context.createLinearGradient(50, 200, 100, 450);
// 渐变色
fillColordiagonal.addColorStop(0.2, "red");
fillColordiagonal.addColorStop(0.4, "black");
fillColordiagonal.addColorStop(0.6, "green");
fillColordiagonal.addColorStop(0.75, "yellow");
// 将渐变对象分配给fillstyle
context.fillStyle = fillColordiagonal;
// 画矩形
context.fillRect(50, 225, 100, 250);
// 绘制径向渐变
fillColorRadial = context.createRadialGradient(450, 300, 0, 450, 300, 200);
fillColorRadial.addColorStop(0, "red");
fillColorRadial.addColorStop(0.2, "black");
fillColorRadial.addColorStop(0.4, "green");
fillColorRadial.addColorStop(0.7, "yellow");
context.fillStyle = fillColorRadial;
context.rect(300, 200, 500, 400);
context.fill();
}
</script>
</head>
<body>
<div>
<p><canvas id="myCanvas" width="600" height="400"></canvas></p>
</div>
</body>
</html>
5.图像裁剪
可以通过裁剪选中的区域来改变图像。要在画布上进行裁剪,则需要重载 drawImage()
方法。drawImage() 方法有 3 个选项。您可以使用 3 个、5 个或 9 个参数。
3 个参数配置,即 drawImage(image, dx, dy)
,可将图像绘制在画布的目标坐标 (dx, dy) 上。该坐标构成图像的左上角。
5 个参数配置,即drawImage(image, dx, dy, dw, dh)
,可为目标坐标提供宽度和高度。将缩放图像以适合目标宽度和高度。
9 个参数配置,即 drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
,可从一个图像中剪切一个矩形区域,该区域的原坐标为 (sx,sy),宽度和高度为 (sw,sh),然后缩放该区域使之适合于目标宽度和高度 (dw,dh),并将其放置到画布的 (dx,dy) 位置上。
图 8 显示了要剪切的图像。
图 8. 剪切图像
以图 8 中的图像为背景将一组图像放到画布上。选用与画布大小相同的图像作为背景。另一个要创建的图像则应更小一些,将插入画布的右下角。第三个图像是拿破仑头部的剪切,放置于画布的左上角。图 9 显示了裁剪之后的图像。
图 9. 裁剪之后的图像
清单 6. 裁剪实例图像的代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图像裁剪示例</title>
<script type="text/javascript">
window.onload = function() {
var canvas = document.getElementById("myImage");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function() {
// 绘制图像以覆盖整个画布
context.drawImage(imageObj, 0, 0, 600, 400);
// 在右下角绘制小图像
var sourceX = 0;
var sourceY = 0;
var sourceWidth = 1200;
var sourceHeight = 801;
var destX = 300;
var destY = 200;
var destWidth = sourceWidth - 900;
var destHeight = sourceHeight - 600;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth,
sourceHeight, destX, destY, destWidth, destHeight);
// 只画拿破仑的头
var sourceNapoleanX = 460;
var sourceNapoleanY = 25;
var sourceNapoleanWidth = 250;
var sourceNapoleanHeight = 175;
var destNapoleanX = 0;
var destNapoleanY = 0;
var destNapoleanWidth = sourceNapoleanWidth - 150;
var destNapoleanHeight = sourceNapoleanHeight - 100;
context.drawImage(imageObj, sourceNapoleanX, sourceNapoleanY,
sourceNapoleanWidth, sourceNapoleanHeight,
destNapoleanX, destNapoleanY,
destNapoleanWidth, destNapoleanHeight);
}
imageObj.src = "img/canvas_image0.png";
}
</script>
</head>
<body>
<div>
<p><canvas id="myImage" width="600" height="400"></canvas></p>
</div>
</body>
</html>
6.动画和多个画布
在处理动画时,层是经常遇到问题的地方。层允许隔离组件,使编写和调试代码变得更容易、更高效。Canvas API 没有层,但它可以创建多个画布。
必须通过时间来控制动画。因此,要创建动画必须实现动画的每个帧。Canvas API 在动画方面有一个主要的局限性:一旦在画布上创建了图形,将无法再改变它。要移动该图形,就必须重新绘制它。
创建动画的流程:
- 清除先前在画布上绘制的所有形状。
- 保存画布状态,确保每次绘制帧是使用的都是最初状态。
- 执行呈现帧的步骤。
- 如果已保存了状态,请在绘制新的帧之前恢复它。
可以通过两种方式来控制动画:使用 setInterval 或 setTimeout 函数,两个函数均可在固定的时间段内调用函数。setInterval 函数重复执行所提供的代码。setTimeout 函数仅在所提供的时间段到达时调用一次。
图 10 显示了游泳者的多画布动画中的一帧。水在一个画布上,而游泳者在另一个画布上。
图 10. 使用图像的动画
使用清单 7 中的代码来创建游泳者 (swimmer)。游泳者使用线性渐变来创建水 (water)。水有 4 种蓝色阴影,这就产生了类似水的视觉。然后可以使用 positionX 和 positionY 值来创建游泳者的动画,这将改变图像的姿势。使用 arc() 方法来创建游泳者的头部。通过绘制直线创建游泳者的胳膊和腿,然后在改变它们的 lineTo() 位置。再通过改变 moveTo() 的位置来改变躯干。由于这是动画,所以必须运行代码才能看到游泳者的游泳动作。
清单 7. 动画示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动画和多画布示例</title>
<script>
// 水画布
function drawWater() {
var canvasWater = document.getElementById("myWaterCanvas");
var contextWater = canvasWater.getContext("2d");
contextWater.globalAlpha = .50;
// 创建线性渐变填充
var linearGrad = contextWater.createLinearGradient(0, 0, 400, 400);
linearGrad.addColorStop(0, '#0000ff'); // sets the first color
linearGrad.addColorStop(.25, '#0099ff'); // sets the second color
linearGrad.addColorStop(.50, '#00ccff'); // sets the third color
linearGrad.addColorStop(.75, '#00ffff'); // sets the fourth color
contextWater.fillStyle = linearGrad;
contextWater.fillRect(0, 0, 400, 400);
}
// 游泳者画布
setInterval(drawSwimmer, 30);
var positionX = 0;
var positionY = 0;
function drawSwimmer() {
var canvasSwimmer = document.getElementById("mySwimmerCanvas");
var contextSwimmer = canvasSwimmer.getContext("2d");
contextSwimmer.clearRect(0, 0, 400, 400);
if(positionX < 30) {
positionX += 1;
positionY += 1;
} else {
positionX = 0;
positionY = 0;
}
contextSwimmer.save();
// 为头画圆
var centerX = 200;
var centerY = 50;
var radius = 20;
contextSwimmer.beginPath();
contextSwimmer.arc(centerX, centerY + positionY,
radius, 0, 2 * Math.PI, false);
contextSwimmer.fillStyle = "#000000";
contextSwimmer.fill();
contextSwimmer.lineWidth = 5;
// 躯干
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 70 + positionY);
contextSwimmer.lineTo(200, 175);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 图像右臂
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 100);
contextSwimmer.lineTo(175 - positionX, 140 - positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 图像左臂
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 100);
contextSwimmer.lineTo(225 + positionX, 140 - positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 图像右腿
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 175);
contextSwimmer.lineTo(190 - positionX, 250 - positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
// 图像左腿
contextSwimmer.beginPath();
contextSwimmer.moveTo(200, 175);
contextSwimmer.lineTo(210 + positionX, 250 - positionY);
contextSwimmer.lineWidth = 10;
contextSwimmer.strokeStyle = "#000000";
contextSwimmer.lineCap = "round";
contextSwimmer.stroke();
contextSwimmer.restore();
};
</script>
</head>
<body onload="drawWater();">
<canvas id="myWaterCanvas" width="400" height="400" style="z-index: 2;
position:absolute;left:0px;top:0px;">
</canvas>
<canvas id="mySwimmerCanvas" width="400" height="400" style="z-index: 1;
position:absolute;left:0px;top:0px;">
</canvas>
</body>
</html>
7.Canvas综合案例:林间小路
林间小路的美景如图11所示:
图 11. 林间小路
清单 8. 林间小路示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>林间小路</title>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
<script>
// 加载砾石背景图
var gravel = new Image();
gravel.src = "img/gravel.jpg";
// 加载图像后,在画布上绘制
gravel.onload = function() {
drawTrails();
}
function createCanopyPath(context) {
// 绘制树冠
context.beginPath();
context.moveTo(-25, -50);
context.lineTo(-10, -80);
context.lineTo(-20, -80);
context.lineTo(-5, -110);
context.lineTo(-15, -110);
// 树顶
context.lineTo(0, -140);
context.lineTo(15, -110);
context.lineTo(5, -110);
context.lineTo(20, -80);
context.lineTo(10, -80);
context.lineTo(25, -50);
// 关闭路径回到起点
context.closePath();
}
//创建树对象绘制函数,将树图绘制移到自己的函数中以供重用
function drawTree(context) {
// 保存当前画布状态以供后续使用
context.save();
// 借助拉伸变换创建一棵用作阴影的倾斜的树,
// 改变X值为随Y值增加而增加,
// 应用了变换以后,所有坐标都与矩阵相乘
// context.transform(a,b,c,d,e,f)
// a:水平缩放,b:水平倾斜,c:垂直倾斜,
// d:垂直缩放,e:水平移动,f:垂直移动
context.transform(1, 0, -0.5, 1, 0, 0);
// 将阴影缩小到Y尺寸的60%高度
context.scale(1, 0.6);
// 使用透明度为20%的黑色填充树干
context.fillStyle = 'rgba(0, 0, 0, 0.2)';
context.fillRect(-5, -50, 10, 50);
// 重绘具有阴影效果的树
createCanopyPath(context);
context.fill();
// 恢复画布状态
context.restore();
//在整个树干上水平创建一个3级渐变
var trunkGradient = context.createLinearGradient(-5, -50, 5, -50);
// 树干的开头是中棕色
trunkGradient.addColorStop(0, '#663300');
// 树干的左中颜色较浅
trunkGradient.addColorStop(0.4, '#996600');
// 树干的右边颜色最暗
trunkGradient.addColorStop(1, '#552200');
// 将渐变作为填充样式,并绘制树干
context.fillStyle = trunkGradient;
// 为树干填充一个矩形
context.fillRect(-5, -50, 10, 50);
// 第二个垂直渐变从树干上的树冠创建阴影
var canopyShadow = context.createLinearGradient(0, -50, 0, 0);
// 阴影渐变的开头是黑色,但透明度为50%
canopyShadow.addColorStop(0, 'rgba(0, 0, 0, 0.5)');
// 稍微向下一点,渐变完全消失为完全透明。 其余的树干没有阴影。
canopyShadow.addColorStop(0.2, 'rgba(0, 0, 0, 0.0)');
// 在渐变树干之上绘制渐变阴影
context.fillStyle = canopyShadow;
context.fillRect(-5, -50, 10, 50);
createCanopyPath(context);
context.lineWidth = 4;
context.lineJoin = 'round';
//以棕色笔划绘制路径
context.strokeStyle = '#663300';
context.stroke();
context.fillStyle = '#339900';
context.fill();
}
function drawTrails() {
// 获取canvas元素及其绘图上下文
var canvas = document.getElementById('trails');
var context = canvas.getContext('2d');
// 在X = 130,Y = 250处绘制第一棵树
// 保存当前画布状态以供后续使用
context.save();
//将绘图上下文向右和向下移动
context.translate(130, 250);
//调用树对象绘制函数
drawTree(context);
// 恢复画布状态
context.restore();
// 在X = 260,Y = 500处绘制第二棵树
context.save();
context.translate(260, 500);
// 将此树在两个维度上均缩放两次
context.scale(2, 2);
drawTree(context);
context.restore();
//保存画布状态并绘制路径
context.save();
context.translate(-10, 350);
context.beginPath();
//第一条曲线向右上方弯曲
context.moveTo(0, 0);
context.quadraticCurveTo(170, -50, 260, -190);
//第二条曲线继续向右下方弯曲
context.quadraticCurveTo(310, -250, 410, -250);
//用背景图替代棕色粗线条,用重复的背景图案替换实线
context.strokeStyle = context.createPattern(gravel, 'repeat');
context.lineWidth = 20;
context.stroke();
// 恢复先前的画布状态
context.restore();
// 在画布上绘制标题文字
context.save();
// 设置字体
context.font = "60px impact";
// 用棕色填充文字
context.fillStyle = '#996600';
// 显示时可以对齐文本
context.textAlign = 'center';
// 在文本上设置黑色阴影,透明度20%
context.shadowColor = 'rgba(0, 0, 0, 0.2)';
// 将阴影向右移动15个像素,向上移动10个像素
context.shadowOffsetX = 15;
context.shadowOffsetY = -10;
// 轻微模糊阴影
context.shadowBlur = 2;
// 在画布中间绘制文本
context.fillText('快乐足迹!', 200, 60, 400);
context.restore();
}
</script>
</head>
<body>
<canvas id="trails" style="border: 1px solid;" width="400" height="600"> </canvas>
</canvas>
</body>
</html>
三、什么是 Webstorage?
是否厌倦了将您的客户端数据塞入那么小的cookie当中?cookie也称为 Web cookie或浏览器cookie,是服务器在用户浏览器中存储的一小段文本信息。服务器在返回浏览器发出的请求的响应时设置cookie。浏览器存储cookie并将其与下一个请求一起发送回同一服务器。Cookie通常用于会话管理,用户跟踪和存储用户首选项。它是一个在服务器和客户端浏览器之间来回传递文本值的内置机制。cookie的主要缺陷有:
- cookie的大小受限:一个cookie只能设置约4kb的数据。
- cookie有安全风险并消耗带宽:只要有请求涉及cookie,它就要在后端服务器和前端浏览器之间来回传送,而且,cookie数据在网络上是可见的。
现如今,Web应用程序的需求更大。 如果说每个用户的浏览器上可以获得5 MB的数据,该怎么办? 嗯,不需要持怀疑态度,HTML5 Web Storage API可以做到这一点! 在本文的该标题中,将带您了解所需要的信息,将任何对象在本地存储在用户设备上,并在其中使用您的Web体验。
什么是Webstorage?HTML5在浏览器中提供了一个漂亮的简单的JavaScript API,用于持久存储键/值对
。 您也不再局限于小巧的4k字节的存储空间;今天所有的浏览器都会很乐于为您提供5至10 MB的存储空间。 HTML5的本地存储同样也是通过Web App( 包含移动App)创建的。需要 注意!本地存储意味着您的应用可以将数据存储在浏览器中,减少与服务器之间的通信。 来看看它是如何工作的:
开发者可以将数据存储在JavaScript对象中,对象在页面加载时保存,并且容易获取。通过使用sessionStorage
或localStorage
,在打开新窗口或新标签页,或者重启浏览器时,开发者可以选择是否**这些数据。存储的数据不会在网络传输,重新浏览页面时也容易获取到。
- 在浏览器的本地存储中,一个页面可以存储一个或多个键/值对。
- 使用键检索它的相应的值。
sessionStorage
或localStorage
在编程上的唯一的区别是访问它们的名称不同,二者在行为上的差异主要体现在数据的保存时长,以及它们的共享方式:
- sessionStorage:数据会保存到存储它的窗口或标签页关闭时(浏览器刷新时可以存储数据,浏览器关闭时不可以),数据只在构建它们的窗口或标签页内可见。
- localStorage:数据的生命期比窗口或浏览器(打开与关闭)的生命期要长。数据可被同源的每个窗口或者标签页共享。
1.设置和获取数据
设置数据很简单,只需执行以下语句:
sessionStorage.setItem('myKey','myValue');
或
localStorage.setItem('key','value');
为了便于记忆,存储对象应该是window对象的属性对象,即window.sessionStorage
或 window.localStorage
,在此省略了window对象的引用,storage对象可以从默认的页面上下文中获得;setItem()方法需要一个字符串类型的“键”,和一个字符串类型的“值”作为其参数;执行结果将字符串值设置到sessionStorage
或 localStorage
中,随后可通过键名获取。
获取数据同样简单,只需执行以下语句:
var myvalue = sessionStorage.getItem('myKey');
或
var value = localStorage.getItem('key');
不过,访问storage对象还有更简单的方法,可以使用“属性”设置和获取存储对象中的值,根据键值
的配对关系,直接在sessionStorage
或localStorage
对象上设置和获取数据。使用这种方法,设置数据的代码可以改写为:
sessionStorage.myKey = 'myValue';
sessionStorage['myKey'] = 'myValue';
或
localStorage.key = 'value';
localStorage['key'] = 'value';
同样,获取数据的代码可以改写为:
var myvalue = sessionStorage.myKey;
var myvalue1 = sessionStorage['myKey'];
或
var value = localStorage.key;
var value1 = localStorage['key'];
2.封堵数据泄露
数据能够保存多久?对于设置到sessionStorage
中的对象,只要浏览器窗口(或标签页)不关闭,它们就会一直存在。当用户关闭浏览器窗口(或标签页),sessionStorage数据就被清除。使用sessionStorage能够跨页面暂存,不会将其泄漏到用户仍在浏览其他信息的窗口中。这样,不同的偏好信息就会被隔离在各自的窗口中。
3.构建Web storage应用
将数据存储在本地客户端,进而从本地而不是远程获取数据,既可以降低网络流量,又可以提升浏览器的响应能力。当用户浏览某个页面时,如果能够快速获取数据并加以显示,对于增强用户体验来说无疑是非常好的方式。
接下来将完成一个便利贴系统(通常称为即时贴)。它是如何工作的:在便利贴上记下“要做”的事情,然后将它贴在某个地方,一旦完成任务后,便会将便利贴放入垃圾桶(或回收)。
首先,使用HBuilder开发工具创建一个名为stickies
的项目,接下来,在项目中创建一个名为mynotes.html
的html5的文件,该文件包含了页面的基本结构(一个head和一个body):
清单 9. html5初始页面结构
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
</body>
</html>
① 写一个便利贴的内容:“提醒我去拿干洗的衣服”,让我们从存储这个便利贴开始:
Web Storage API通过localStorage对象是可行的方案,您会发现它已经通过浏览器成为本地的底层存储系统。它只能存储字符串类型,不能直接存储数字或对象。setItem方法将两个字符串作为参数,用作键/值对:
localStorage.setItem("sticky_0", "提醒我去拿干洗的衣服");
为了存储,使用setItem方法。第一个字符串参数是存储项的键,只要它是字符串,就可以为它命名sticky_0
;第二个字符串是要存储在本地存储系统中的值。
②那很容易,让我们向本地存储中添加第二项目内容:
localStorage.setItem("sticky_1", "取消有线电视,现在谁需要它?");
sticky_1
是另一个键名。 就像我们已经说过的那样,您可以使用任何喜欢的键,只要它是字符串即可,但是每个键只能存储一个值。第二项参数是对应新建的值。
③ 现在我们已经将两个值安全地存储在浏览器的本地存储中,现在您可以使用其中之一键从localStorage检索其相应的值。 像这样:
var sticky = localStorage.getItem("sticky_0");
alert(sticky);
从本地存储中获取与键“sticky_0”关联的值,并将其分配给名为sticky的变量。为了使这一点更有趣,让我们使用告警功能在屏幕上弹出便笺的值。
④ 认真研究便利贴系统,进行需求分析:
我们将创建一个便笺应用程序,以便您可以查看便笺并添加新便笺。即时贴App将向我们显示便笺笔记,并在localStorage中添加新便笺笔记。我们需要一种添加新便笺的方法,因此,我们将创建一个带有输入框和按钮的表单。
如果存储中有现有的便利贴,则希望在加载页面时看到它们,就像我们已经拥有的两个便笺一样。要显示即时贴,我们将遍历localStorage中的所有即时贴,并将其添加到页面的DOM对象中展示。
我们将使用CSS设置即时贴的样式,使其看起来像真正的即时贴!
请记住,已有的两个即时贴的键是“ sticky_0”和“ sticky_1”。我们将继续遵守这个惯例,并使用递增的整数创建用于即时贴的键名,例如sticky_2,sticky_3等。
我们还将看到显示中有任何新的即时贴的更新,并且我们将为每个即时贴向DOM对象中添加新元素来实现这一点。当您单击“添加便笺”的按钮时,新的便笺将添加到localStorage。
⑤ 创建页面:
在这里,我们需要一种输入便笺文本的方法。如果我们可以在页面中看到它们,那就太好了,所以我们需要一个界面元素来保持页面中的所有笔录。清单 10 中的代码,从HTML标记-使用现有的HTML文件并添加一个<form>元素、<ul>元素和指向它的CSS链接<link>、以及JavaScript脚本<script>。
清单 10. 输入显示便笺页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>我的便笺</title>
<link rel="stylesheet" href="mynotes.css">
<script src="mynotes.js"></script>
</head>
<body>
<form>
<input type="text" id="note_text">
<input type="button" id="add_button" value="添加便笺">
</form>
<ul id="stickies">
</ul>
</body>
</html>
我们通过<link>标记添加了“mynotes.css”的CSS样式文件,使外观看起来更像真实的便利贴;并将所有JavaScript代码由<script>标记移至“mynotes.js”文件;添加了一个<form>表单作为用户交互接口,用于输入新的即时贴。而且我们必须在某个地方将便笺展示在页面上,因此我们将其放置在<ul></ul>无序列表中,CSS处理使每个列表项看起来更像一个便利贴。
⑥ 现在添加JavaScript代码:
现在,已经设计好了页面,存储在localStorage
中便笺
等待显示。 先从localStorage中读取它们,然后将其放入刚刚在页面上创建的无序列表元素。 操作方法如下:
window.onload = init; // 加载页面后,将调用init函数;
// 初始化函数从localStorage读取所有现有的便笺,并通过DOM对象将它们添加到<ul>中。
function init() {
for(var i = 0; i < localStorage.length; i++) { // 遍历存储中的所有项;
var key = localStorage.key(i); // 抓住每一个键;
if(key.substring(0, 6) == "sticky") { // 判断便利贴的键名是否以“sticky”开头;
var value = localStorage.getItem(key);
addStickyToDOM(value); // 若是便利贴,则抓取其值并将它添加到页面中(通过DOM)。
}
}
}
现在需要编写addStickyToDOM函数,该函数将把便笺
插入<ul>元素中:
// 通过传递便笺文本作为参数。 需要得到无序列表对象,创建列表项,然后将便笺插入。
function addStickyToDOM(value) {
var stickies = document.getElementById("stickies"); //获取id为“stickies”的列表元素。
var sticky = document.createElement("li"); // 创建一个列表li元素。
var span = document.createElement("span"); // 创建一个span元素。
span.setAttribute("class", "sticky"); // 并给span一个class名为“sticky”,可以设置样式。
span.innerHTML = value; // 设置span元素的内容,其为便笺文本。
sticky.appendChild(span); // 并将span添加到li.
stickies.appendChild(sticky); // 并将li添加到ul列表。
}
⑦ 是时候测试一下:
将以上的脚本代码放入您的mynotes.js文件,并将其设置在页面<script>标记的src属性的值,在浏览器中加载页面后得到的结果如图12所示:
图12 便笺测试
⑧ 完成用户界面:
现在,需要做的就是启用表单,以便可以添加新的便笺。为此,需要为单击“添加便笺”按钮时添加处理程序,并编写一些代码以创建新的便笺。 以下为添加处理程序的代码:
// 将新代码添加到init函数中
function init() {
var button = document.getElementById("add_button"); // 获取“添加便笺”按钮的对象引用
button.onclick = createSticky; // 并添加一个单击时的处理程序。 触发调用createSticky函数。
// for循环在这里。init的其余代码保持不变,在此不再重复。
}
以及创建新便签的createSticky函数代码:
// 单击该按钮时,将调用此处理程序。
function createSticky() {
var value = document.getElementById("note_text").value; // 它首先在表单文本框中检索文本。
// 需要为‘便笺’创建唯一的键。使用“ sticky_”与整个存储对象的长度相结合,它会继续增加。
var key = "sticky_" + localStorage.length;
localStorage.setItem(key, value); //然后使用给定的键名,向‘localStorage’添加新的便利贴。
addStickyToDOM(value); // 最后,将新文本添加到DOM中以表示便利贴。
}
⑨ 再次测试一下:
现在是真正的交互操作! 在浏览器中加载此新代码,输入新的“给自己的便笺”,然后单击或点击“添加便笺”按钮。 您应该看到新的即时贴出现在您的即时贴列表中。 如图13所示:
图13 新增便笺
这是我们的测试运行! 看起来不错!新增便笺的键名应该是“ sticky_2”,即存储对象 localStorage的长度(在添加之前)与“ sticky_”串联。
确认一下,尝试关闭浏览器窗口,然后再次打开页面文件, 是否仍然看到已有的“便笺”吗?
⑩ 自我维护:
创建一个名为“maintenance.html”的新页面文件:
清单 11. 便笺维护
<!doctype html>
<html>
<head>
<title>便笺维护</title>
<meta charset="utf-8">
<script>
// 我们在页面上添加了一个按钮,此代码为该按钮添加了一个点击处理程序。
window.onload = function() {
var clearButton = document.getElementById("clear_button");
// 当您单击按钮时,将调用clearStorage函数。
clearButton.onclick = clearStorage;
}
function clearStorage() {
// 该函数所做的全部就是调用localStorage.clear方法。 请谨慎使用,因为它将删除与此维护页面来源相关的所有项目!
localStorage.clear();
}
</script>
</head>
<body>
<form>
<!-- 这是我们的按钮。 每当您需要擦除localStorage中的所有内容时使用此文件(适用于测试)。 -->
<input type="button" id="clear_button" value="清除存储">
</form>
</body>
</html>
输入页面标记及代码后,继续并将其加载到浏览器中。(就我们的便利贴应用而言)进行localStorage清理是安全的,请尝试一下! 请使用您的浏览器的菜单项-->开发者工具,以便观察更改变化。
4.Web storage应用优化清单
清单 12. 页面优化
<!doctype html>
<html>
<head>
<title>我的便笺</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="css/mynotes.css">
<script src="js/mynotes2.js"></script>
</head>
<body>
<form>
<label for="note_color">颜色: </label>
<select id="note_color">
<option value="LightGoldenRodYellow">浅金黄色</option>
<!-- #FAFAD2 -->
<option value="PaleGreen">浅绿色</option>
<!-- #98FB98 -->
<option value="LightPink">粉红色</option>
<!-- #FFB6C1 -->
<option value="LightBlue">浅蓝色</option>
<!-- #ADD8E6 -->
</select>
<label for="note_text">文本:</label> <input type="text" id="note_text">
<input type="button" id="add_button" value="添加便笺">
</form>
<ul id="stickies">
</ul>
</body>
</html>
清单 13. 程序优化
window.onload = init;
function init() {
var button = document.getElementById("add_button");
button.onclick = createSticky;
var stickiesArray = getStickiesArray();
for(var i = 0; i < stickiesArray.length; i++) {
var key = stickiesArray[i];
var value = JSON.parse(localStorage[key]);
addStickyToDOM(key, value);
}
}
function getStickiesArray() {
var stickiesArray = localStorage.getItem("stickiesArray");
if(!stickiesArray) {
stickiesArray = [];
localStorage.setItem("stickiesArray", JSON.stringify(stickiesArray));
} else {
stickiesArray = JSON.parse(stickiesArray);
}
return stickiesArray;
}
function createSticky() {
var stickiesArray = getStickiesArray();
var value = document.getElementById("note_text").value;
var colorSelectObj = document.getElementById("note_color");
var index = colorSelectObj.selectedIndex;
var color = colorSelectObj[index].value;
// 使用JSON创建便签以保留值和颜色
var currentDate = new Date();
var key = "sticky_" + currentDate.getTime();
var stickyObj = {
"value": value,
"color": color
};
localStorage.setItem(key, JSON.stringify(stickyObj));
// 向数组添加新的便利贴键名并更新localStorage中的stickiesArray数组
stickiesArray.push(key);
localStorage.setItem("stickiesArray", JSON.stringify(stickiesArray));
addStickyToDOM(key, stickyObj);
}
function deleteSticky(e) {
var key = e.target.id;
if(e.target.tagName.toLowerCase() == "span") {
key = e.target.parentNode.id;
}
var stickiesArray = getStickiesArray();
if(stickiesArray) {
for(var i = 0; i < stickiesArray.length; i++) {
if(key == stickiesArray[i]) {
stickiesArray.splice(i, 1);
}
}
localStorage.removeItem(key);
localStorage.setItem("stickiesArray", JSON.stringify(stickiesArray));
removeStickyFromDOM(key);
}
}
function addStickyToDOM(key, stickyObj) {
var stickies = document.getElementById("stickies");
var sticky = document.createElement("li");
// 将键设置为id属性,以便我们更易查找
// ids存储在stickies数组中
sticky.setAttribute("id", key);
// 使用stickyObj颜色,并设置背景颜色CSS样式
sticky.style.backgroundColor = stickyObj.color;
var span = document.createElement("span");
span.setAttribute("class", "sticky");
// 使用stickyObj值作为便笺的文本
span.innerHTML = stickyObj.value;
// 将所有内容添加到DOM
sticky.appendChild(span);
stickies.appendChild(sticky);
// 添加事件侦听器,以便在单击便笺时可以将其删除
sticky.onclick = deleteSticky;
}
function removeStickyFromDOM(key) {
var sticky = document.getElementById(key);
sticky.parentNode.removeChild(sticky);
}
function clearStickyNotes() {
localStorage.clear();
var stickyList = document.getElementById("stickies");
var stickies = stickyList.childNodes;
for(var i = stickies.length - 1; i >= 0; i--) {
stickyList.removeChild(stickies[i]);
}
// 重置便笺数组
var stickiesArray = getStickiesArray();
}
清单 14. CSS样式
body {
background-color: #dbdbdb;
font-size: 100%;
}
form input#note_text {
width: 350px;
}
/* 便条 */
ul#stickies li {
display: block;
list-style: none;
z-index: 1;
float: left;
margin: 30px;
padding: 15px 15px 50px 15px;
width: 200px;
height: 200px;
border: 1px solid #bfbfbf;
background-color: LightGoldenRodYellow;
/* use #fafad2 if name doesn't work */
color: black;
text-decoration: none;
-webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
-o-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
-webkit-transition: all 0.5s ease-in;
-moz-transition: all 0.5s ease-in;
-o-transition: all 0.5s ease-in;
-ms-transition: all 0.5s ease-in;
transition: all 0.5s ease-in;
overflow: hidden;
}
ul#stickies li span.sticky {
font-family: Verdana, Helvetica, sans-serif;
font-size: 200%;
}
/*
* 旋转
*/
ul#stickies li:nth-child(even) {
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-o-transform: rotate(2deg);
-ms-transform: rotate(2deg);
transform: rotate(2deg);
}
ul#stickies li:nth-child(odd) {
-webkit-transform: rotate(-1deg);
-moz-transform: rotate(-1deg);
-o-transform: rotate(-1deg);
-ms-transform: rotate(-1deg);
transform: rotate(-1deg);
}
ul#stickies li:nth-child(3n) {
-webkit-transform: rotate(1deg);
-moz-transform: rotate(1deg);
-o-transform: rotate(1deg);
-ms-transform: rotate(1deg);
transform: rotate(1deg);
}
/*
转换演示
使用过渡(上面定义)来缓解。
*/
ul#stickies li:hover {
-webkit-box-shadow: 5px 5px 6px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 5px 5px 6px rgba(0, 0, 0, 0.4);
-o-box-shadow: 5px 5px 6px rgba(0, 0, 0, 0.4);
-webkit-transform: rotate(0deg) scale(1.25);
-moz-transform: rotate(0deg) scale(1.25);
-o-transform: rotate(0deg) scale(1.25);
-ms-transform: rotate(0deg) scale(1.25);
transform: rotate(0deg) scale(1.25);
z-index: 10;
}
上一篇: js监听全屏下的esc事件 JavaScriptesc
下一篇: 用PHP 4.2书写安全的脚本