<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="css/photo.css">
</head>
<body>
<!-- 展示相关 -->
<div class="container">
<div class="photoHeader">
<div class="imgContainer">
<img class="photoName" src="img/1.jpg" />
</div>
<div class="btnContainer">
<span class="photoTitle">相册名称</span>
<button class="mybtn">上传照片</button>
</div>
</div>
<div class="photoContainer">
<div class="photoItem">
<img src="img/1.jpg" />
<span>
home
</span>
</div>
</div>
</div>
<!-- 上传相关 -->
<div class="masking">
<div class="addPhotoContainer"></div>
<div class="addController">
<h3 class="addTitle">上传照片-普通上传(H5)<span class="close">╳</span></h3>
<div class="photoTitles">
<span class="uploadTo">上传到</span>
<div class="photoSelect">
<img class="showPhoto" src="img/1.jpg" />
相册名称
</div>
</div>
<!-- 上传按钮 -->
<div class="showContainer">
<div class="uploadContainer">
<span class="fileinput-button">
<span>上传图片</span>
<input class="imgFile" type="file" name="" multiple="multiple" />
</span>
<span class="hint">
按住Ctrl可多选
</span>
</div>
</div>
<!-- 显示待上传图片 -->
<div class="loadContainer">
<div class="wantUpload">
<div class="uploadPhotoItem">
<!-- <span class="myProgress">
<span class="plan"></span>
30%
</span>
<img src="img/1.jpg" />
<span class="pictureName">
home
</span> -->
</div>
</div>
<div class="addStyle">
<span class="fileinput-add">
<span></span>
<input class="imgFile-add" type="file" multiple="multiple" />
</span>
</div>
<!-- 开始上传按钮 -->
<div class="bottomStyle">
<span class="uploadBtn">开始上传</span>
</div>
</div>
</div>
</div>
</body>
<script>
document.querySelector(".close").onclick = function () {
document.querySelector(".masking").style.display = "none";
}
document.querySelector(".mybtn").onclick = function () {
document.querySelector(".masking").style.display = "block";
}
let uploadArr = [];
/*
用户添加图片会有添加两张后,想继续添加图片,不管添加几次,都是一个陆续到达的状态,
所以需要一个容器里去承载 这个数组就是添加图片的容器,完全接受到之后,再去对这个容器 也就是数组,做相关的处理
通过这个数组可以处理到所有上传的图片,也就是说这个数组是在中间先去过滤处理一下
*/
document.querySelector(".imgFile").onchange = function () {
document.querySelector(".loadContainer").style.display = "block";
document.querySelector(".showContainer").style.display = "none";
// console.log(this.files); // 获取到input框里的文件
/*
this.files是一个类数组 ...剩余参数 就可以用foreach了
根据用户上传了几张图片,来决定你要在显示区创建几个DIV
注意:在使用剩余参数时,上一行的代码结束位置必须要加分号!!!不然会报错
*/
[...this.files].forEach(file => {
// 每次for循环,从input里拿到的 数据 都给 这个类 让这个类去帮我处理并返还给我一个新的数据
let uploadObj = new UploadImg(file);
// 没返还一个新的数据,就给他添加到这个数组里
uploadArr.push(uploadObj);
/*
uploadObj 是 UploadImg() 实例化出来的;
createHtml() 是 UploadImg() 里的方法
也就是说:foreach每次去input标签里去拿一个文件,拿一个给这个类处理一下,处理完,添加到数组里,
然后调用createHtml() 渲染到页面;
拿一个渲染一个,拿是个渲染十个————根据数组的数量来
*/
uploadObj.createHtml();
});
};
document.querySelector(".imgFile-add").onchange = function () {
document.querySelector(".loadContainer").style.display = "block";
document.querySelector(".showContainer").style.display = "none";
/*
因为files是类数组,直接调用foreach会报错,所以加上... 剩余参数
根据用户上传了几张图片,来决定你要在显示区创建几个div
注意:在使用剩余参数时,上一行的代码结束位置必须加分号!!!不然会报错
*/
[...this.files].forEach(file => {
//每遍历一次,从input里拿到数据 都给这个类,让这个类去处理并返回一个新的数据
let uploadObj = new UploadImg(file);
// 每返还一个新的数据,就给他添加到数据里
uploadArr.push(uploadObj);
// 每次去input里拿一次数据,就给类去处理一下,然后添加到数组里,然后调用这个方法,渲染到页面
uploadObj.createHtml();
});
};
class UploadImg {
/*
constructor在类里的作用:在原型中,有一个constructor
它是一个指针,他会指回构造函数
在类里整个都是原型的空间,在里边写的所有东西都是原型用的
要想写点属性写在构造函数里,需要写在constructor里
为什么要使用 类 : 因为这里的功能很多,我们需要给他封装一下
为什么不使用函数封装 :因为他有很多个功能,我们需要把它单独写开。这样就没办法写在函数里,而类会更合适
*/
constructor(file) {
this.file = file;
this.ele = null;
}
createHtml() {
// 把文件转换为base64的格式 只是转了格式,内容不变
let fileReader = new FileReader();
fileReader.readAsDataURL(this.file);
/*
转换完成后执行的事件
this指向问题:函数内直接写this指向的是 fileReader 不是我们外界传进来的this了
两种解决方式:
1. 写成箭头函数
2. 存一下this
*/
let _this = this;
fileReader.onload = function () {
// console.log(fileReader.result); // 会把图片转换完成的信息返回,相当于图片的地址
// 创建一个div
let uploadDiv = document.createElement("div");
// 添加样式
uploadDiv.classList.add("uploadPhotoItem");
// 给这个div拼接内容
uploadDiv.innerHTML = `<span class="myProgress">
<span class="plan"></span>
<span class="percentText">0%</span>
</span>
<img src="${fileReader.result}" />
<span class="pictureName">
${_this.file.name}
</span>`;
// 渲染到页面
document.querySelector(".wantUpload").appendChild(uploadDiv);
_this.ele = uploadDiv;
}
}
/*
依次上传:
一个一个的上传,需要用到异步上传
一步有三个处理方式 : 1. 回调函数(回调地狱)
2. Promise对象
3. es7处理方式 async await
*/
uploadFile() {
return new Promise((resolve, reject) => {
// 使用ajax上传
let xhr = new XMLHttpRequest();
xhr.open("post", "/upload", true); //这里不能是get
let form = new FormData(); // 放在form中
form.append("img", this.file);// 设置一下key键 和 上传的内容 这里不需要转base64 不然在服务器页面还需转回来,比较麻烦无意义
xhr.onload = function () {
console.log(xhr.responseText); // 打印返回值
};
// 写进度条
xhr.upload.onprogress = (evt) => {
/*
当前文件上传的大小 : evt.loaded
需要传输的总大小 : evt.total
为什么*100 : 因为他要100%,不然是零点零零几% 大的时候1%
当 evt.loaded 和 evt.total 相等的时候 :也就是传完了 相除等于1 不符合我们的日常习惯
*/
let percent = Math.round(evt.loaded / evt.total * 100);
/*
把完成的进度,赋值给标签
添加 <span class="plan"></span> 这个类的时候直接找的话,后续可能还会有很多,未来会有很多
且this找不到!!!
解决方式:1. 149行 要写 this.ele = null;
185行写上_this.ele = uploadDiv; 每添加一个,就把他存在_this.ele 里
2. 这里写成箭头函数
为什么这里是 % 不是px或者rem:
上传50% 就让他的宽度为 50%
上传100% 就让他的宽度为 100%
*/
this.ele.querySelector(".plan").style.width = percent + "%"; //进度条
this.ele.querySelector(".percentText").innerHTML = percent + "%"; //文字
this.ele.querySelector(".myProgress").style.display = "block"; //确保整个span可以出现,做一个保险措施
// 当前文件上传的大小 >= 需要传输的总大小
if (evt.loaded >= evt.total) {
console.log("上传完成");
resolve();
}
};
// 发送给后端接口
xhr.send(form);
});
}
}
document.querySelector(".uploadBtn").onclick = function () {
/*
imgfile --> 数组里边遍历出来的每一个对象
uploadObj 是 UploadImg() 实例化出来的;然后被添加到了uploadArr
也就是说,imgfile是UploadImg()的实例化对象
然后用imgfile调用类里的uploadFile()这个方法
*/
// uploadArr.forEach(imgfile => {
// imgfile.uploadFile();
// });
// 依次上传
async function que() {
for (let i = 0; i < uploadArr.length; i++) {
await uploadArr[i].uploadFile(); // 数组的每一个元素,调用uploadFile()这个方法
};
// 上传完成后
document.querySelector(".wantUpload").innerHTML = ""; // 清空存放div的容器
document.querySelector(".masking").style.display = "none"; // 上传完成后,回到准备页面
document.querySelector(".loadContainer").style.display = "none"; //关闭
document.querySelector(".showContainer").style.display = "block"; // 开启
}
que();
}
</script>
</html>
//============================================
//服务器文件
const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
let app = new Koa();
let router = new Router();
app.use(static(__dirname+"/static"));
router.get("/",ctx=>{
ctx.body = "你好"
});
router.post("/upload",ctx=>{
ctx.body = "some value..."
})
app.use(router.routes());
app.listen(8080);
前后端交互——模拟QQ相册
最新推荐文章于 2022-07-17 14:27:48 发布