if(window.Worker){ // 使用Worker }
var worker = new Worker("./worker.js");
生成了“两个对象”(你可能会问:为什么是两个不是一个呢?请往下看)
“第一个”对象是我们在当前脚本中通过构造函数显式创建出来的worker对象,它拥有一套API:postMessage和onmessage,通过postMessage方法可以向worker脚本(上文worker.js)发送数据, 通过onmessage方法可以从worker脚本接收数据 “第二个”对象是在Web Worker脚本(上文的worker.js)中隐式创建出来的全局变量对象,它叫DedicatedWorkerGlobalScope(这个时候在work.js全局变量对象是它而不是Window!!),而它也拥有一套API:postMessage和onmessage,通过postMessage方法可以向当前执行任务的脚本发送数据, 通过onmessage方法可以从当前执行任务的脚本接收数据 【注意】关于DedicatedWorkerGlobalScope 1. 它是在Web Worker脚本中生成的特殊的全局变量对象,也就是在全局执行环境中使用this指向的不是Window而是它 2. 它不能像Windows那样通过变量名直接访问,但在Web Worker脚本中你能通过this取到它 所以现在数据传递方向有两条: 1. 调用当前脚本中worker对象的postMessage方法, 然后在Web Worker脚本(上文的worker.js)中通过onmessage这个回调方法接收数据 2. 调用Web Worker脚本中的this.postMessage方法(this指向DedicatedWorkerGlobalScope),然后在当前脚本中worker对象的onmessage回调方法接收数据 看到这里可能有点懵,来让我们通过一个例子看看1中的数据传递: 先看示例吧,这是我们的目录结构├─worker.js
├─main.js
└─index.html
index.html:
<html> <head> <meta charset="utf-8" /> <button id="work-button">传递数据</button> </head> <body> <script type="text/javascript" src="./main.js"></script> </body> </html>
main.js:
var button = document.querySelector("#work-button"); if(window.Worker){ var worker = new Worker("./worker.js"); button.onclick = function () { worker.postMessage("你好,我是当前脚本"); } }
worker.js:
this.onmessage = function (e) { console.log('work接收到的数据为:', e.data); }
点击按钮后,在main.js中调用worker对象的postMessage方法, 这个数据就被发给了work.js中的全局变量对象DedicatedWorkerGlobalScope, 所以我们在work,js中通过this.onmessage接收数据并输出
├─worker.js
├─main.js
└─index.html
index.html:
同上
main.js:
var button = document.querySelector("#work-button"); if(window.Worker){ var worker = new Worker("./worker.js"); button.onclick = function () { worker.postMessage("你好,我是当前脚本"); worker.onmessage = function (e) { console.log('当前脚本接收到的数据:',e.data) } } }
worker.js:
this.onmessage = function (e) { console.log('work接收到的数据为:', e.data); this.postMessage("你好,我是worker发来的数据") }
demo如下 点击传递数据输出:
<canvas id="canvas"></canvas>
这样取得上下文对象:
let canvas = document.getElementById("canvas"); // 首先取得canvas元素对象 let ctx = canvas.getContext("2d"); //通过getContext()取得关键的上下文对象,2d表示画布是“平面”的
fillRect(x, y, width, height) // 绘制一个填充的矩形 strokeRect(x, y, width, height) // 绘制一个矩形的边框
上面的x,y代表相对于canvas画布左上角的横纵坐标:
<canvas id="canvas" width="200px" height="100px"> 你的浏览器不支持canvas </canvas>
JS部分:
let canvas = document.getElementById("canvas"); if(canvas.getContext){ let ctx = canvas.getContext("2d"); ctx.fillRect(20,20,40,40); // 绘制矩形 }
【注意】. canvas标签内的内容(例如上面的文本)是否呈现取决于浏览器是否支持canvas,如果支持,则不出现,如果不支持,则会呈现出来 demo:
let ctx = canvas.getContext("2d"); ctx.fillStyle = "#0081F0"; // 给上下文对象这支画笔添加填充颜色 ctx.fillRect(20,20,40,40);
demo:
let canvas = document.getElementById("canvas"); if(canvas.getContext){ let ctx = canvas.getContext("2d"); ctx.font = "26px serif"; // 设置文字大小和样式 ctx.fillText("外婆的",20,20); // “实心”的文本 ctx.strokeText("彭湖湾",20,60); // “空心”的文本 }
demo:
这里要稍微提一下, 也许上面的那些绘制图形,绘制文本的操作对你来说都没有触动,因为它们离我们的直接需求似乎还有一定的距离,但我想接下来的这几个上下文API你或许有些兴趣。 例如我们可能有一个需求是载入已有的图片,对它截图(裁剪)后保存为一张新的图片,这个时候我们就可以使用到canvas的绘制图片,裁剪图片,保存图片的API了
drawImage(image, x, y) // 其中 image 是 image 或者 canvas 对象
我们可以通过下面的一段代码动态获取img元素对象
let img = new Image(); img.onload = function () { // 运行这个函数的时候可以确保img已经被加载好了 }; img.src = "./beach.jpg" // 指定src后图片开始加载
废话不多说,直接上demo! 在相同目录下有这么一张图片
let canvas = document.getElementById("canvas"); let img = new Image(); img.onload = function () { if(canvas.getContext){ let ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0) } }; img.src = "./beach.jpg"
demo: 我们发现, 图片加载完成后被写入了画布当中!
let canvas = document.getElementById("canvas"); let img = new Image(); img.onload = function () { if(canvas.getContext){ let ctx = canvas.getContext("2d"); ctx.beginPath(); // 开始绘制路径 ctx.arc(100,100,100,0,Math.PI*2,true); // 绘制一个起点(100,100),半径为100的圆 ctx.clip(); // 裁剪 ctx.drawImage(img, 0, 0); // 画图 } }; img.src = "./beach.jpg"
【注意】clip方法的调用要在drawImage方法之前,否则不能成功! 也就是说要“先裁剪,再画图”
canvas.toDataURL() // 默认返回的是png图片 canvas.toDataURL('image/jpeg') // 返回jpeg图片 canvas.toDataURL('image/jpeg', quality) // 创建一个JPG图片。你可以有选择地提供从0到1的品质量,1表示最好品质
看下面的例子
let canvas = document.getElementById("canvas"); let img = new Image(); img.onload = function () { if(canvas.getContext){ let ctx = canvas.getContext("2d"); ctx.beginPath(); // 开始绘制路径 ctx.arc(100,100,100,0,Math.PI*2,true); // 绘制一个起点为(100,100),半径为100的圆 ctx.clip(); // 裁剪 ctx.drawImage(img, 0, 0); // 画图 let src = canvas.toDataURL('image/png') console.log(src); } }; img.src = "./beach.jpg"
控制台输出了base64格式的数据:
indexedDB.open([ 数据库名称 ], [数据库版本])
调用open方法时候,如果对应名称的数据库不存在,则创建一个新的数据库,如果已存在,则打开已存在的那个数据库 需要说明的是, indexedDB里面绝大多数操作都是异步的, 上述的indexedDB.open并不会立即创建一个数据库, 你需要在异步的回调里面判断数据库是否创建成功,并对可能出现的错误做判断和处理 只有在onsuccess回调中,你才能通过request.result取得创建成功的数据库
var request = indexedDB.open("XXX", 1); request.onsuccess = function () { // request.result === 你通过open创建的数据库 }
通过open返回的request对象有三个回调: onsuccess 每次创建/打开数据库时候都会调用 onerror 创建/打开数据库发生错误的时候调用 onupgradeneeded 数据库版本变化的时候调用 (onupgradeneeded 是我们唯一可以修改数据库结构的地方) open一个indexedDB数据库后,一般在onupgradeneeded回调中初始化(或修改)数据库结构(划重点!!) 这包括两个方面的操作: 1. 通过db.createObjectStore创建对象存储空间,并取得ObjectStore对象(类似于SQL数据库中的建表操作) 2. 通过调用ObjectStore.createIndex创建该存储空间内的索引( 以便于提高查询时候的速度) 具体的可看下面的例子:
<script type="text/javascript"> if(!window.indexedDB) { alert("你的浏览器还不能支持indexedDB哦!") } var request = indexedDB.open("phwDataBase", 1); var db request.onsuccess = function () { // 将成功创建的数据库对象赋给db db = request.result; } request.onerror = function () { var errorDescribe = request.errorCode; // 打印错误 console.log(errorDescribe); } request.onupgradeneeded = function (e){ // 取得更新后的数据库对象, 并赋给db db = request.result; // 创建名为people数据存储空间, 第二个参数里的keyPath相当于“主键” var objectStore = db.createObjectStore("people", { keyPath: "id" }); // 创建索引, 加快查询速度 objectStore.createIndex("name", "name", {unique: false}); } </script>
运行一下, 然后让我们看看效果:
<button id="add-button">增加数据</button> <button id="delete-button">删除数据</button> <button id="get-button">获取数据</button> <button id="show-all-button">遍历全部数据</button> <button id="index-button">通过索引获取数据</button>
demo:
var transaction = db.transaction(["people"],"readwrite");
2. transaction.objectStore方法 这个方法接受一个参数: 指定的objectStore的名称, 方法返回的是获取到的objectStore 例如我们下面的一行代码:
var objectStore = transaction.objectStore("people");
function addData () { // 确保这个时候异步的open方法已经完成,并取得数据库对象 if(!db){ return; } // 我们要写入的数据 var data = [ {id: '1',name:'a', age: 10}, {id: '2',name:'b', age: 20}, {id: '3',name:'c', age: 30} ]; // 创建事务,并使其可读可写 var transaction = db.transaction(["people"],"readwrite"); transaction.oncomplete = function () { alert("添加事务已经完成") } transaction.onerror = function () { alert("出现错误") } // 通过事务对象取得people存储空间 var objectStore = transaction.objectStore("people"); for(let d of data) { // 调用add方法添加数据 objectStore.add(d); } } var addButton = document.getElementById("add-button"); addButton.onclick = addData
demo: 点击“增加数据”后弹出
function deleteData () { if(!db){ return; } var transaction = db.transaction(["people"],"readwrite"); var objectStore = transaction.objectStore("people"); objectStore.delete("1"); transaction.oncomplete = function () { alert("删除事务已经完成") } } var deleteButton = document.getElementById("delete-button"); deleteButton.onclick = deleteData;
点击上面的“删除数据”按钮(删除id = 1的数据)
function getData () { if(!db){ return; } var transaction = db.transaction(["people"], "readwrite"); var objectStore = transaction.objectStore("people"); var request = objectStore.get("2"); request.onsuccess = function () { alert(JSON.stringify(request.result)); } } var getButton = document.getElementById("get-button"); getButton.onclick = getData;
demo: 点击“获取数据”按钮,弹出
function showAllData () { if(!db){ return; } var transaction = db.transaction(["people"], "readwrite"); var objectStore = transaction.objectStore("people"); console.log("遍历开始") objectStore.openCursor().onsuccess = function (event) { var cursor = event.target.result; if(cursor) { console.log(cursor.key, cursor.value); cursor.continue(); } } } var showAllButton = document.getElementById("show-all-button"); showAllButton.onclick = showAllData;
点击“遍历全部数据”按钮,看看控制台
function getByIndex () { if(!db){ return; } var transaction = db.transaction(["people"], "readwrite"); var objectStore = transaction.objectStore("people"); var index = objectStore.index("name"); var request = index.get("c"); request.onsuccess = function (event) { alert(JSON.stringify(request.result)); } } var indexButton = document.getElementById("index-button"); indexButton.onclick = getByIndex;
点击“通过索引获取数据”按钮:
好! 现在让我们对indexedDB做一个小小的总结: 1. indexedDB是面向对象的, 与传统的以二维表为基础的数据库不同 2. IndexedDB是一个事务型数据库系统 3. indexedDB大多数API都是异步的,这意味着调用一个方法你不能马上得到关键的那个对象,而在对应的success回调中才能取得
<div> <img id = "myImg" src="./clock.jpg" draggable="true" ondragstart="dragstart(event)" /> </div> <div id="targetDiv" ondragover="dragover(event)" ondrop="drop(event)"> </div> <script type="text/javascript"> function dragstart (event) { event.dataTransfer.setData("text/plain", event.target.id) } function drop (event) { // 阻止默认行为——禁止在浏览器中打开新的链接 event.preventDefault(); var imgId = event.dataTransfer.getData("text/plain"); var targetDiv = document.getElementById("targetDiv"); targetDiv.appendChild(document.getElementById(imgId)); } function dragover (event) { // 组织默认行为——禁止放置 event.preventDefault(); } </script>
拖拽前
拖拽后
参考资料: HTML5-MDN https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/HTML5 【完】