Web前端文件上传进度的显示
跟后台关系不大,主要是前端js实现,具体使用了XMLHttpRequest的ProgressEvent事件,可以参考MDN中的Using XMLHttpRequest
https://developer.mozilla.org/cn/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Submitting_forms_and_uploading_files
XMLHttpRequest
让发送一个HTTP请求变得非常容易。你只需要简单的创建一个请求对象实例,打开一个URL,然后发送这个请求。当传输完毕后,结果的HTTP状态以及返回的响应内容也可以从请求对象中获取。本页把这个强大的JavaScript对象的一些常用的甚至略有晦涩的使用案例进行了一下概述。
function reqListener () {
console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.open("get", "yourFile.txt", true);
oReq.send();
请求类型Edit
通过XMLHttpRequest生成的请求可以有两种方式来获取数据,异步模式或同步模式。请求的类型是由这个XMLHttpRequest对象的open()方法的第三个参数async
的值决定的。如果该参数的值为false,则该XMLHttpRequest请求以同步模式进行,否则该过程将以异步模式完成。这两种类型请求的详细讨论和指南可以在同步和异步请求页找到。
注意:由于对用户体验的糟糕效果,从Gecko 30.0(Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27)版本开始,在主线程上的同步请求已经被弃用。
处理响应Edit
W3C规范定义了XMLHttpRequest对象的几种类型的响应属性。这些属性告诉客户端关于XMLHttpRequest返回状态的重要信息。一些处理非文本返回类型的用例可能包含一些下面章节描述的操作和分析。
分析并操作 responseXML属性
如果你使用 XMLHttpRequest 来获得一个远程的 XML 文档的内容,responseXML 属性将会是一个由 XML 文档解析而来的 DOM 对象,这很难被操作和分析。这里有五种主要的分析 XML 文档的方式:
- 使用 XPath 定位到文档的制定部分。
- 使用 JXON 将其转换成 JavaScript 对象树。
- 手工的 解析和序列化 XML 为字符串或对象。
- 使用 XMLSerializer 把 DOM 树序列化成字符串或文件。
- 如果你预先知道 XML 文档的内容,你可以使用 RegExp。如果你用 RegExp 扫描时受到换行符的影响,你也许想要删除所有的换行符。然而,这种方法是"最后手段",因为如果 XML 代码发生轻微变化,该方法将可能失败。
解析和操作包含 HTML 文档的 responseText
属性
如果使用 XMLHttpRequest
从远端获取一个 HTML 页面,则所有 HTML 标记会以字符串的形式存放在responseText 属性里,这样就使得操作和解析这些标记变得困难。解析这些HTML标记主要有三种方式:
- 使用 XMLHttpRequest.responseXML 属性。
- 将内容通过 fragment.body.innerHTML 注入到一个 文档片段 中,并遍历 DOM 中的片段。
- 如果你预先知道 HTML 文档的内容,你可以使用 RegExp。如果你用 RegExp 扫描时受到换行符的影响,你也许想要删除所有的换行符。 然而,这种方法是"最后手段",因为如果 HTML 代码发生轻微变化,该方法将可能失败。
处理二进制数据Edit
尽管 XMLHttpRequest
一般用来发送和接收文本数据,但其实也可以发送和接受二进制内容。有许多经过良好测试的方法来强制使用 XMLHttpRequest 发送二进制数据。利用 XMLHttpRequest 的 .overrideMimeType() 方法是一个解决方案,虽然它并不是一个标准方法。
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
// retrieve data unprocessed as a binary string
oReq.overrideMimeType("text/plain; charset=x-user-defined");
/* ... */
在 XMLHttpRequest Level 2 规范中新加入了 responseType 属性 ,使得发送和接收二进制数据变得更加容易。
var oReq = new XMLHttpRequest();
oReq.onload = function(e) {
var arraybuffer = xhr.response; // not responseText
/* ... */
}
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.send();
更多示例请参考 发送和接收二进制数据 。
监测进度Edit
XMLHttpRequest
提供了各种在请求被处理期间发生的事件以供监听。这包括定期进度通知、 错误通知,等等。
支持 DOM 的 progress 事件监测之于 XMLHttpRequest
传输,遵循 Web API 进度事件规范 : 这些事件实现了 ProgressEvent
接口。
var req = new XMLHttpRequest();
req.addEventListener("progress", updateProgress, false);
req.addEventListener("load", transferComplete, false);
req.addEventListener("error", transferFailed, false);
req.addEventListener("abort", transferCanceled, false);
req.open();
...
// progress on transfers from the server to the client (downloads)
function updateProgress(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
...
} else {
// Unable to compute progress information since the total size is unknown
}
}
function transferComplete(evt) {
alert("The transfer is complete.");
}
function transferFailed(evt) {
alert("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
alert("The transfer has been canceled by the user.");
}
第 3-6 行为多种事件添加了事件监听,这些事件在使用 XMLHttpRequest
执行数据传输时被发出。
open()
之前添加事件监听。否则 progress 事件将不会被触发。在上个例子中,progress 事件被指定由 updateProgress()
函数处理,并接收到传输的总字节数和已经传输的字节数,它们分别在事件对象的 total
和 loaded
属性里。但是如果 lengthComputable
属性的值是 false,那么意味着总字节数是未知并且 total 的值为零。
progress 事件同时存在于下载和上传的传输。下载相关事件在 XMLHttpRequest
对象上被触发,就像上面的例子一样。上传相关事件在 XMLHttpRequest.upload
对象上被触发,像下面这样:
var req = new XMLHttpRequest();
req.upload.addEventListener("progress", updateProgress);
req.upload.addEventListener("load", transferComplete);
req.upload.addEventListener("error", transferFailed);
req.upload.addEventListener("abort", transferCanceled);
req.open();
file:
协议的情况下是无效的。responseType
为 "moz-blob" 时,如果你的 progress 事件被触发,则响应的值是一个包含了接收到的数据的 Blob
。使用 loadend
事件可以侦测到所有的三种加载结束条件(abort、load、error):
req.addEventListener("loadend", loadEnd, false);
function loadEnd(evt) {
alert("The transfer finished (although we don't know if it succeeded or not).");
}
需要注意的是,没有方法可以确切的知道 loadend
事件接收到的信息是来自何种条件引起的操作终止;但是你可以在所有传输结束的时候使用这个事件处理。
提交表单和上传文件Edit
XMLHttpRequest
的实例有两种方式提交表单:
- 使用 AJAX
- 使用
FormData
API
第二种方式( 使用 FormData
API )是最简单最快捷的,但是缺点是被收集的数据不是字符串形式的。
第一种方式反而是最复杂的但也是最灵活和最强大。
只使用 XMLHttpRequest
在大多数用例中,提交表单时即便不使用 FormData
API 也不会要求其他的 API。唯一的例外情况是,如果你要上传一个或多个文件,你需要额外的 FileReader
API。
提交方法简介
一个 html <form>
可以用以下四种方式发送:
- 使用
POST
方法,并设置enctype
属性为application/x-www-form-urlencoded
(默认) - 使用
POST
方法,并设置enctype
属性为text/plain
- 使用
POST
方法,并设置enctype
属性为multipart/form-data
- 使用
GET
方法(这种情况下enctype
属性会被忽略)
现在,我们提交一个表单,它里面有两个字段,分别被命名为 foo
和 baz
。如果你用 POST
方法,那么服务器将会接收到一个字符串类似于下面三种情况之一,其中的区别依赖于你采用何种编码类型:
- 方法:
POST
; - 编码类型:
application/x-www-form-urlencoded
(default):
Content-Type: application/x-www-form-urlencoded
foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
- 方法:
POST
; - 编码类型:
text/plain
:
Content-Type: text/plain
foo=bar
baz=The first line.
The second line.
- 方法:
POST
; - 编码类型:
multipart/form-data
:
Content-Type: multipart/form-data; boundary=---------------------------314911788813839
-----------------------------314911788813839
Content-Disposition: form-data; name="foo"
bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz"
The first line.
The second line.
-----------------------------314911788813839--
相反的,如果你用 GET
方法,一个像下面这样的字符串将被简单的附加到 URL:
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
一个小的普通的框架
所有这些事情都是由浏览器在你提交一个 <form>
的时候自动完成的。但是如果你想要用 JavaScript 做同样的事情,你不得不告诉解释器所有的事。那么,如何发送表单这件事在使用纯粹的 AJAX 时会复杂到无法在这里解释清楚。基于这个原因,我们提供一个完整的(但仍然教条的)框架,它可以使用所有的四种提交方式,甚至上传文件:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Sending forms with pure AJAX – MDN</title>
<script type="text/javascript">
"use strict";
/*\
|*|
|*| :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary()
\*/
if (!XMLHttpRequest.prototype.sendAsBinary) {
XMLHttpRequest.prototype.sendAsBinary = function(sData) {
var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
for (var nIdx = 0; nIdx < nBytes; nIdx++) {
ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
}
/* send as ArrayBufferView...: */
this.send(ui8Data);
/* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */
};
}
/*\
|*|
|*| :: AJAX Form Submit Framework ::
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
|*|
|*| This framework is released under the GNU Public License, version 3 or later.
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*| Syntax:
|*|
|*| AJAXSubmit(HTMLFormElement);
\*/
var AJAXSubmit = (function () {
function ajaxSuccess () {
/* console.log("AJAXSubmit - Success!"); */
alert(this.responseText);
/* you can get the serialized data through the "submittedData" custom property: */
/* alert(JSON.stringify(this.submittedData)); */
}
function submitData (oData) {
/* the AJAX request... */
var oAjaxReq = new XMLHttpRequest();
oAjaxReq.submittedData = oData;
oAjaxReq.onload = ajaxSuccess;
if (oData.technique === 0) {
/* method is GET */
oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/, oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
oAjaxReq.send(null);
} else {
/* method is POST */
oAjaxReq.open("post", oData.receiver, true);
if (oData.technique === 3) {
/* enctype is multipart/form-data */
var sBoundary = "---------------------------" + Date.now().toString(16);
oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" + oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
} else {
/* enctype is application/x-www-form-urlencoded or text/plain */
oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
}
}
}
function processStatus (oData) {
if (oData.status > 0) { return; }
/* the form is now totally serialized! do something before sending it to the server... */
/* doSomething(oData); */
/* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
submitData (oData);
}
function pushSegment (oFREvt) {
this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
this.owner.status--;
processStatus(this.owner);
}
function plainEscape (sText) {
/* how should I treat a text/plain form encoding? what characters are not allowed? this is what I suppose...: */
/* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
return sText.replace(/[\s\=\\]/g, "\\$&");
}
function SubmitRequest (oTarget) {
var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
/* console.log("AJAXSubmit - Serializing form..."); */
this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
this.technique = bIsPost ? this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
this.receiver = oTarget.action;
this.status = 0;
this.segments = [];
var fFilter = this.technique === 2 ? plainEscape : escape;
for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
oField = oTarget.elements[nItem];
if (!oField.hasAttribute("name")) { continue; }
sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
if (sFieldType === "FILE" && oField.files.length > 0) {
if (this.technique === 3) {
/* enctype is multipart/form-data */
for (nFile = 0; nFile < oField.files.length; nFile++) {
oFile = oField.files[nFile];
oSegmReq = new FileReader();
/* (custom properties:) */
oSegmReq.segmentIdx = this.segments.length;
oSegmReq.owner = this;
/* (end of custom properties) */
oSegmReq.onload = pushSegment;
this.segments.push("Content-Disposition: form-data; name=\"" + oField.name + "\"; filename=\""+ oFile.name + "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
this.status++;
oSegmReq.readAsBinaryString(oFile);
}
} else {
/* enctype is application/x-www-form-urlencoded or text/plain or method is GET: files will not be sent! */
for (nFile = 0; nFile < oField.files.length; this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name)));
}
} else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
/* field type is not FILE or is FILE but is empty */
this.segments.push(
this.technique === 3 ? /* enctype is multipart/form-data */
"Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
: /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
fFilter(oField.name) + "=" + fFilter(oField.value)
);
}
}
processStatus(this);
}
return function (oFormElement) {
if (!oFormElement.action) { return; }
new SubmitRequest(oFormElement);
};
})();
</script>
</head>
<body>
<h1>Sending forms with pure AJAX</h1>
<h2>Using the GET method</h2>
<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h2>Using the POST method</h2>
<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: text/plain</h3>
<form action="register.php" method="post" enctype="text/plain" onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
Your name: <input type="text" name="user" />
</p>
<p>
Your message:<br />
<textarea name="message" cols="40" rows="8"></textarea>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: multipart/form-data</h3>
<form action="register.php" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Upload example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" /><br />
Sex:
<input id="sex_male" type="radio" name="sex" value="male" /> <label for="sex_male">Male</label>
<input id="sex_female" type="radio" name="sex" value="female" /> <label for="sex_female">Female</label><br />
Password: <input type="password" name="secret" /><br />
What do you prefer:
<select name="image_type">
<option>Books</option>
<option>Cinema</option>
<option>TV</option>
</select>
</p>
<p>
Post your photos:
<input type="file" multiple name="photos[]">
</p>
<p>
<input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" /> <label for="vehicle_bike">I have a bike</label><br />
<input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" /> <label for="vehicle_car">I have a car</label>
</p>
<p>
Describe yourself:<br />
<textarea name="description" cols="50" rows="8"></textarea>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
</body>
</html>
要测试它的话,创建一个页面名为 register.php
(作为示例表单的 action
属性)并且只输入以下内容:
<?php
/* register.php */
header("Content-type: text/plain");
/*
NOTE: You should never use `print_r()` in production scripts, or
otherwise output client-submitted data without sanitizing it first.
Failing to sanitize can lead to cross-site scripting vulnerabilities.
*/
echo ":: data received via GET ::\n\n";
print_r($_GET);
echo "\n\n:: Data received via POST ::\n\n";
print_r($_POST);
echo "\n\n:: Data received as \"raw\" (text/plain encoding) ::\n\n";
if (isset($HTTP_RAW_POST_DATA)) { echo $HTTP_RAW_POST_DATA; }
echo "\n\n:: Files received ::\n\n";
print_r($_FILES);
跨站的 XMLHttpRequestEdit
现代浏览器可以通过执行 WebApps 工作小组通过的 Access Control for Cross-Site Requests 标注来支持跨站请求。只要服务器端的配置允许您从您的 Web 应用发送请求,就可以使用 XMLHttpRequest
。 否则,会抛出一个 INVALID_ACCESS_ERR
异常
绕过缓存Edit
一般地,如果缓存中有相应内容, XMLHttpRequest
会试图从缓存中读取内容。绕过缓存的方法见下述代码:
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
req.send(null);
channel
attribute is Gecko-specific.或者还有一个跨浏览器兼容的方法,就是给 URL 添加时间戳。请确保你酌情地添加了 "?" or "&" 。例如,将:
http://foo.com/bar.html
改为
http://foo.com/bar.html?12345
以及将
http://foo.com/bar.html?foobar=baz
改为
http://foo.com/bar.html?foobar=baz&12345
因为本地缓存都是以 URL 作为索引的,这样就可以使每个请求都是唯一的,也就可以这样来绕开缓存。
你也可以用下面的方法自动更改缓存:
var req = new XMLHttpRequest();
req.open("GET", url += ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime(), false);
req.send(null);
安全性Edit
要启用跨站脚本,推荐的做法是对 XMLHttpRequest 的响应使用 the Access-Control-Allow-Origin
的 HTTP 头。
XMLHttpRequests being stopped
If you end up with an XMLHttpRequest having status=0
and statusText=null
, it means that the request was not allowed to be performed. It was UNSENT
. A likely cause for this is when the XMLHttpRequest
origin (at the creation of the XMLHttpRequest) has changed when the XMLHttpRequest is then open()
. This case can happen for example when one has an XMLHttpRequest that gets fired on an onunload event for a window: the XMLHttpRequest gets in fact created when the window to be closed is still there, and then the request is sent (ie open()
) when this window has lost its focus and potentially different window has gained focus. The way to avoid this problem is to set a listener on the new window "activate" event that gets set when the old window has its "unload" event fired.
Downloading JSON and JavaScript from extensionsEdit
For security reasons, extensions should never use eval()
to parse JSON or JavaScript code downloaded from the web. See Downloading JSON and JavaScript in extensions for details.
Using XMLHttpRequest from JavaScript modules / XPCOM componentsEdit
Instantiating XMLHttpRequest
from a JavaScript module or an XPCOM component works a little differently; it can't be instantiated using the XMLHttpRequest()
constructor. The constructor is not defined inside components and the code results in an error. The easiest way to work around this is to use the XMLHttpRequest constructor associated with the hidden DOM window:
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
.getService(Components.interfaces.nsIAppShellService)
.hiddenDOMWindow;
var req = XMLHttpRequest();
Warning: The following code will create an XMLHttpRequest associated with the nearest available window object. If this window is closed then it will cancel your XMLHttpRequest.
This was fixed by bug 756277, so starting from this version it is always safe to create an XMLHttpRequest this way.
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
var req = XMLHttpRequest();
For C++ code, you would need to QueryInterface
the component to an nsIEventTarget
in order to add event listeners, but chances are that in C++, using a channel directly would be better.
参考:https://segmentfault.com/q/1010000005955853
Web前端文件上传进度的显示的更多相关文章
- 七牛云存储的 Javascript Web 前端文件上传
因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,七牛云存储的 Web 前端文件上传 七牛是不错的云存储产品,特别是有免费的配额可 ...
- Layui多文件上传进度条
Layui原生upload模块不支持文件上传进度条显示,百度,谷歌找了一下不太适用.后面找到一个别人修改好的JS,替换上去,修改一下页面显示即可使用,一下是部分代码 HTML: <div cla ...
- 基于HT for Web矢量实现HTML5文件上传进度条
在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传.上传成功了没有,所以今天给大家介绍的内容是通过HT for Web矢量来实现HTML5文件 ...
- silverlight漂亮的文件上传进度显示原理及示例
silverlight漂亮的文件上传进度显示原理及示例 作者:chenxumi 出处:博客园 2009/11/27 13:37:11 阅读 1219 次 概述:在网站根目录web.config里配 ...
- PHP中使用Session配合Javascript实现文件上传进度条功能
Web应用中常需要提供文件上传的功能.典型的场景包括用户头像上传.相册图片上传等.当需要上传的文件比较大的时候,提供一个显示上传进度的进度条就很有必要了. 在PHP .4以前,实现这样的进度条并不容易 ...
- Web Uploader文件上传插件
http://www.jq22.com/jquery-info2665 插件描述:WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现 ...
- HTML5矢量实现文件上传进度条
在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传.上传成功了没有,所以今天给大家介绍的内容是通过HT for Web矢量来实现HTML5文件 ...
- java web(四)文件上传与下载
一.文件上传原理 1.在TCP/IP中,最早出现的文件上传机制是FTP ,它是将文件由客户端发送到服务器的标准机制:但是在jsp使用过程中不能使用FTP方法上传文件,这是由jsp运行机制所决定. 通 ...
- Web Uploader文件上传&&使用webupload有感(黄色部分)
引入资源 使用Web Uploader文件上传需要引入三种资源:JS, CSS, SWF. <!--引入CSS--> <link rel="stylesheet" ...
随机推荐
- OC语言编写:为视图添加丝滑的水波纹
先看一下最终效果图: 首先我们可以把如此丝滑的水波纹拆分一下下: 一条规律的曲线. 曲线匀速向右移动. 曲线下方的位置用颜色填充. 于是先来一条曲线吧. 对于需要产生波动如此规律的曲线,我们首先想到的 ...
- Android Studio重构之路,我们重新来了解一下Google官方的Android开发工具
Android Studio重构之路,我们重新来了解一下Google官方的Android开发工具 记得我的第一篇博客就是写Android Studio,但是现在看来还是有些粗糙了,所有重构了一下思路, ...
- Java-IO之FileDescriptor
FileDescriptor是文件描述符,可以被用来表示开放文件,开放套接字等,FileDescriptor可以被看成某个文件,但无法对该文件进行操作,需要新创建FileDescriptor对应的Fi ...
- JavaScript 关键字
JavaScript 关键字 和其他任何编程语言一样,JavaScript 保留了一些关键字为自己所用. JavaScript 同样保留了一些关键字,这些关键字在当前的语言版本中并没有使用,但在以后 ...
- 如何通过rsync+sersync 实现同步备份
3.rsync+sersync更快更节约资源实现web数据同步4.unison+inotify实现web数据双向同步 一:为什么要实现同步备份 服务器上有些重要文件或数据时,可以把他们多备份一份到其他 ...
- shell脚本整段注释
摘自:http://zhidao.baidu.com/link?url=XmCCZmfluRe6n8TjPRKJTx4GGOUPSGX1VNBm-euqGdpKGpveTESxC0HL90UBNT5n ...
- Touch Handling in Cocos2D 3.x(六)
使英雄变成可触碰的对象 这是另一个非常有用的特性.很多用户需要捡起已经存在的英雄然后满屏幕移动它们.让我们按以下步骤实现该功能: 如果用户触摸屏幕空白位置,一个新的英雄将被创建 如果用户触摸一个已经存 ...
- 【算法导论】单源最短路径之Dijkstra算法
Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄. 迪杰斯特拉提出的按路径长度递增次序来产生源点到 ...
- 对C语言中递归算法的分析
C通过运行时堆栈支持递归函数的实现.递归函数就是直接或间接调用自身的函数. 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的<C语言程序设计> ...
- android混淆和反编译
混淆 Android Studio: 只需在build.gradle(Module:app)中的buildTypes中增加release的编译选项即可,如下: <code class=&quo ...