在前不久我给我的程序写了一个在线更新的功能,这样用户就不用每次更新都需要下载安装包自己覆盖了,但是每次用户更新的时候会跳转到一个下载页面然后一直转啊转,如果更新包不大那倒是没有问题,几秒钟就下载好了,如果更新包太大了那么对于用户的体验就是非常的不好了,没有人喜欢对着一个转圈的页面。
所以我准备做一个在线更新并且可以显示更新的进度,使用的是原生的PHP和原生的JavaScript加上Ajax技术实现这个功能。这个是用的前后端分离,不用前后端分离我感觉应该要简单一点。
功能分析:
前端页面(ajax.html)+后端下载文件页面(wenjian.php)+后端获取文件下载进度页面(jindu.php)
后端两个页面直接用的文件和进度的拼音(真的捞)
- 前端页面分析:
显示进度条框架:一个div中包含一个section,这个是用来实现进度的效果,div宽度和高度固定,section设置一个红色的背景颜色,高度和div一样,宽度为0。
- 请求后端部分:
需要两个ajax请求,先请求后端下载文件的页面(wenjian.php),然后请求后端获取进度条的页面(jindu.php),获取进度这个请求我们需要用一个定时器来刷新它的进度。
后端页面分析:
- 下载文件的页面(wenjian.php)分析:
我们需要前端发送一个用来存储进度的文件名,通过GET请求发送。
然后打开远程文件和本地文件,将远程文件读取然后写入本地文件。
while循环实现读取远程文件直到读取完成,读取一次就写入一次到本地文件,通过每次读取的字节和总字节和读取的次数,可以计算出读取的进度,公式如下:
读取的百分比进度 = 读取的次数*每次读取的字节数/总字节数
最后把百分比进度写入记录进度的文件里面。
- 获取进度条的页面(jindu.php)分析:
读取记录进度文件的内容返回给前端即可。
最后附上代码
前端代码 ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100%;
height: 50px;
border: 1px solid grey;
}
section {
width: 0;
height: 100%;
background-color: red;
text-align: center;
line-height: 100%;
color: white;
font-weight: 700;
}
</style>
</head>
<div>
<section></section>
</div>
<body>
</body>
<script>
let jd = Math.random(10);
sec = document.querySelector('section');
// 请求下载
let xhr = new XMLHttpRequest();
xhr.open('get', 'wenjian.php?jd='+jd, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status = 200) {
console.log('下载成功');
sec.style.width = '100%';
sec.innerText = '100%';
clearInterval(jindu);
}
}
}
// 获取下载进度
let axhr = new XMLHttpRequest();
var jindu = setInterval(function () {
axhr.open('get', 'jindu.php?jd='+jd, true);
axhr.send();
axhr.onreadystatechange = function () {
if (axhr.readyState == 4) {
if (axhr.status = 200) {
var obj = JSON.parse(axhr.response);
var size = obj.size;
console.log(size);
if (size != '') {
if (size > 100) {
sec.style.width = '100%';
sec.innerText = '100%';
} else {
sec.style.width = size + '%';
sec.innerText = size + '%';
}
}
}
}
}
}, 10);
</script>
</html>
后端代码
wenjian.php:
<?php
ini_set('max_execution_time', '0');
$jd = $_GET['jd'];
//远程文件地址
$url = 'http://120.48.58.230/wp.zip';
// 打开远程文件
$remote = fopen($url, 'rb') or die('打开失败');
// 打开本地文件
$local = fopen('wp.zip', 'wb');
// 写入的次数i
$i = 0;
// 将远程文件写本地文件
while (!feof($remote)) {
// 一次写入1024个字节 1kb;
fwrite($local, fread($romete, 1024));
$i++;
// 计算下载的进度 (单位为字节 21064643是远程文件的字节)
$n = $i * 1024 / 21064643;
// 计算下载的百分比
$n *= 100;
echo $i;
// 将下载进度写入进度文件
file_put_contents($jd.'.txt',$n);
}
//删除进度文件
unlink($jd . '.txt');
fclose($local);
fclose($remote);
?>
jindu.php:
<?php
$jd = $_GET['jd'];
$jindu = file_get_contents($jd.'.txt');
$jindu = number_format($jindu,2);
echo json_encode(['size'=>$jindu]);
?>