高程笔记9
requestAnimationFrame() 1 2 3 4 5 6 7 8 9 10 11 mozRequestAnimationFrame()方法接收一个参数,即在重绘屏幕前调用的一个函数。这个函数 负责改变下一次重绘时的 DOM 样式。为了创建动画循环,可以像以前使用 setTimeout()一样,把多 个对 mozRequestAnimationFrame()的调用连缀起来。比如: function updateProgress(){ var div = document.getElementById("status"); div.style.width = (parseInt(div.style.width, 10) + 5) + "%"; if (div.style.left != "100%"){ mozRequestAnimationFrame(updateProgress); } } mozRequestAnimationFrame(updateProgress);
webkitRequestAnimationFrame与msRequestAnimationFrame
基于 mozRequestAnimationFrame(),Chrome 和 IE10+也都给出了自己的实现,分别叫 webkitRequestAnimationFrame()和 msRequestAnimationFrame()。这两个版本与 Mozilla 的版本有两个 方面的微小差异。首先,不会给回调函数传递时间码,因此你无法知道下一次重绘将发生在什么时间。 其次,Chrome 又增加了第二个可选的参数,即将要发生变化的 DOM 元素。知道了重绘将发生在页面中 哪个特定元素的区域内,就可以将重绘限定在该区域中。 既然没有下一次重绘的时间码,那 Chrome 和 IE 没有提供 mozAnimationStartTime 的实现也就 很容易理解了——没有那个时间码,实现这个属性也没有什么用。不过,Chrome 倒是又提供了另一个 方法 webkitCancelAnimationFrame(),用于取消之前计划执行的重绘操作。 假如你不需要知道精确的时间差,那么可以在 Firefox 4+、IE10+和 Chrome 中可以参考以下模式创 建动画循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (function(){ function draw(timestamp){ //计算两次重绘的时间间隔 var drawStart = (timestamp || Date.now()), diff = drawStart - startTime; //使用 diff 确定下一步的绘制时间 //把 startTime 重写为这一次的绘制时间 startTime = drawStart; //重绘 UI requestAnimationFrame(draw); } var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame, startTime = window.mozAnimationStartTime || Date.now(); requestAnimationFrame(draw); })();
File API File API 在表单中的文件输入字段的基础上,又添加了一些直接访问文件信息的接口。HTML5 在 DOM 中为文件输入元素添加了一个 files 集合。在通过文件输入字段选择了一或多个文件时,files 集合中将包含一组 File 对象,每个 File 对象对应着一个文件。每个 File 对象都有下列只读属性。
name:本地文件系统中的文件名。 size:文件的字节大小。 type:字符串,文件的 MIME 类型。 lastModifiedDate:字符串,文件上一次被修改的时间(只有 Chrome 实现了这个属性)。 举个例子,通过侦听 change 事件并读取 files 集合就可以知道选择的每个文件的信息:
1 2 3 4 5 6 7 8 9 10 11 var filesList = document.getElementById("files-list"); EventUtil.addHandler(filesList, "change", function(event){ var files = EventUtil.getTarget(event).files, i = 0, len = files.length; while (i < len){ console.log(files[i].name + " (" + files[i].type + ", " + files[i].size + " bytes) "); i++; } });
FileReader类型 FileReader类型实现的是一种异步文件读取机制。可以把FileReader想象成XMLHttpRequest, 区别只是它读取的是文件系统,而不是远程服务器。为了读取文件中的数据,FileReader 提供了如下 几个方法。
readAsText(file,encoding):以纯文本形式读取文件,将读取到的文本保存在 result 属 性中。第二个参数用于指定编码类型,是可选的。 readAsDataURL(file):读取文件并将文件以数据 URI 的形式保存在 result 属性中。 readAsBinaryString(file):读取文件并将一个字符串保存在 result 属性中,字符串中的 每个字符表示一字节。 readAsArrayBuffer(file):读取文件并将一个包含文件内容的 ArrayBuffer 保存在 result 属性中。 这些读取文件的方法为灵活地处理文件数据提供了极大便利。例如,可以读取图像文件并将其保存 为数据 URI,以便将其显示给用户,或者为了解析方便,可以将文件读取为文本形式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 var filesList = document.getElementById("files-list"); EventUtil.addHandler(filesList, "change", function(event){ var info = "", output = document.getElementById("output"), progress = document.getElementById("progress"), files = EventUtil.getTarget(event).files, type = "default", reader = new FileReader(); if (/image/.test(files[0].type)){ reader.readAsDataURL(files[0]); type = "image"; } else { reader.readAsText(files[0]); type = "text"; } reader.onerror = function(){ output.innerHTML = "Could not read file, error code is " + reader.error.code; }; reader.onprogress = function(event){ if (event.lengthComputable){ progress.innerHTML = event.loaded + "/" + event.total; } }; reader.onload = function(){ var html = ""; switch(type){ case "image": html = "<img src=\"" + reader.result + "\">"; break; case "text": html = reader.result; break; } output.innerHTML = html; }; }); 这个例子读取了表单字段中选择的文件,并将其内容显示在了页面中。如果文件有 MIMI 类型,表 示文件是图像,因此在 load 事件中就把它保存为数据 URI,并在页面中将这幅图像显示出来。如果文 件不是图像,则以字符串形式读取文件内容,然后如实在页面中显示读取到的内容。这里使用了 progress 事件来跟踪读取了多少字节的数据,而 error 事件则用于监控发生的错误。
读取部分内容 有时候,我们只想读取文件的一部分而不是全部内容。为此,File 对象还支持一个 slice()方法, 这个方法在 Firefox 中的实现叫 mozSlice(),在 Chrome 中的实现叫 webkitSlice(),Safari 的 5.1 及 之前版本不支持这个方法。slice()方法接收两个参数:起始字节及要读取的字节数。这个方法返回一 个 Blob 的实例,Blob 是 File 类型的父类型。下面是一个通用的函数,可以在不同实现中使用 slice() 方法:
1 2 3 4 5 6 7 8 9 10 11 function blobSlice(blob, startByte, length){ if (blob.slice){ return blob.slice(startByte, length); } else if (blob.webkitSlice){ return blob.webkitSlice(startByte, length); } else if (blob.mozSlice){ return blob.mozSlice(startByte, length); } else { return null; } }
对象URL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 对象 URL 也被称为 blob URL,指的是引用保存在 File 或 Blob 中数据的 URL。使用对象 URL 的 好处是可以不必把文件内容读取到 JavaScript 中而直接使用文件内容。为此,只要在需要文件内容的地 方提供对象 URL 即可。要创建对象 URL,可以使用 window.URL.createObjectURL()方法,并传入 File 或 Blob 对象。这个方法在 Chrome 中的实现叫 window.webkitURL.createObjectURL(),因 此可以通过如下函数来消除命名的差异: function createObjectURL(blob){ if (window.URL){ return window.URL.createObjectURL(blob); } else if (window.webkitURL){ return window.webkitURL.createObjectURL(blob); } else { return null; } }
读取拖放的文件 围绕读取文件信息,结合使用 HTML5 拖放 API 和文件 API,能够创造出令人瞩目的用户界面:在页 面上创建了自定义的放置目标之后,你可以从桌面上把文件拖放到该目标。与拖放一张图片或者一个链接 类似,从桌面上把文件拖放到浏览器中也会触发 drop 事件。而且可以在 event.dataTransfer. files 中读取到被放置的文件,当然此时它是一个 File 对象,与通过文件输入字段取得的 File 对象一样。 下面这个例子会将放置到页面中自定义的放置目标中的文件信息显示出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var droptarget = document.getElementById( "droptarget"); function handleEvent(event){ var info = "", output = document.getElementById("output"), files, i, len; EventUtil.preventDefault(event); if (event.type == "drop"){ files = event.dataTransfer.files; i = 0; len = files.length; while (i < len){ info += files[i].name + " (" + files[i].type + ", " + files[i].size + " bytes)<br>"; i++; } output.innerHTML = info; } } EventUtil.addHandler(droptarget, "dragenter", handleEvent); EventUtil.addHandler(droptarget, "dragover", handleEvent); EventUtil.addHandler(droptarget, "drop", handleEvent);
使用XHR上传文件 首先,要创建一个 FormData对象,通过它调用 append()方法并传入相应的 File 对象作为参数。然后,再把 FormData 对象传递给 XHR 的 send()方法,结果与通过表单上传一模一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 var droptarget = document.getElementById("droptarget"); function handleEvent(event){ var info = "", output = document.getElementById("output"), data, xhr, files, i, len; EventUtil.preventDefault(event); if (event.type == "drop"){ data = new FormData(); //读取拖放的文件 files = event.dataTransfer.files; i = 0; len = files.length; while (i < len){ data.append("file" + i, files[i]); i++; } xhr = new XMLHttpRequest(); xhr.open("post", "FileAPIExample06Upload.php", true); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ alert(xhr.responseText); } }; xhr.send(data); } } EventUtil.addHandler(droptarget, "dragenter", handleEvent); EventUtil.addHandler(droptarget, "dragover", handleEvent); EventUtil.addHandler(droptarget, "drop", handleEvent);