案例一:
1.效果图:
2.源码:
<!DOCTYPE html>
<html>
<head>
<title>HTML5上传图片预览</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="http://www.codefans.net/ajaxjs/jquery-1.6.2.min.js"></script>
<style>
#imgList{
list-style:none;
overflow:hidden;
clear:both;
}
#imgList li{
float:left;
width:120px;height:120px;margin:10px 10px 0 0;
overflow:hidden;
border-radius:4px;
background-color:pink;
}
#imgList li img{
width:100%;
}
.input-file-box{
display: inline-block;
position: relative;
padding: 3px 5px;
overflow: hidden;
color:#fff;
background-color: #ccc;
}
.file-input{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
outline: none;
background-color: transparent;
filter:alpha(opacity=0);
-moz-opacity:0;
-khtml-opacity: 0;
opacity: 0;
}
</style>
</head>
<body>
<h3>请选择图片文件:JPG/GIF</h3>
<form name="form0" id="form0" >
<!-- 这里特别说一下这个 multiple="multiple" 添加上这个之后可以一次选择多个文件进行上传,是 html5 的新属性-->
<!-- <input type="file" name="file0" id="file0" multiple="multiple" /><br> -->
<div class="input-file-box">
<input type="file" class="file-input" id="file0" multiple="multiple" />
上传文件
</div>
<ul id="imgList">
<li><img src="" alt=""></li>
<li><img src="" alt=""></li>
</ul>
</form>
<script>
$("#file0").change(function(){
// this.files[0]代表的是选择的文件资源的第一个,因为上面写了 multiple="multiple" 就表示上传文件可能不止一个
console.log(this.files)
var arr = [];
for(var val of this.files){
var imgUrl = getObjectURL(val) ;
if (imgUrl) {
// 在这里修改图片的地址属性
arr.push('<li><img src="'+imgUrl+'"/></li>')
}
$('#imgList').html(arr.join(''))
}
}) ;
//建立一個可存取到該file的url
function getObjectURL(file) {
var url = null ;
// 下面函数执行的效果是一样的,只是需要针对不同的浏览器执行不同的 js 函数而已
if (window.createObjectURL!=undefined) { // basic
url = window.createObjectURL(file) ;
} else if (window.URL!=undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file) ;
} else if (window.webkitURL!=undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file) ;
}
return url ;
}
</script>
</body>
</html>
案例二、
模仿 element-ui 的 el-upload 上传组件实现
功能:
1.支持预览
2.返回二进制格式
upload.vue源码:
<!-- 自定义上传图片组件 -->
<template>
<div v-show="preViewUrl" class="upload-wrap flex">
<img class="img-box box-w" :src="preViewUrl" alt="">
<div class="upload-box box-w">
<svg-icon class="icon icon-qr-code" icon-class="icon-qr-code" />
<div class="upload-text">点击上传</div>
<input type="file" class="file-input" :multiple="isMultiple" @change="fileChange">
</div>
</div>
</template>
<script>
export default {
name: 'UploadImg',
props: {
imageUrl: {
type: String,
default: ''
},
isMultiple: {
type: Boolean,
default: false
}
},
data() {
return {
preViewUrl: '',
imgsUrl: '',
mime: ''
}
},
watch: {
imageUrl: {
handler() {
this.preViewUrl = this.imageUrl
},
immediate: true
},
imgsUrl(val) {
this.preViewUrl = val
}
},
methods: {
/**
* database64文件格式转换为2进制
* @param {[String]} data dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
* @param {[String]} mime [description]
* @return {[blob]} [description]
*/
data2blob(data, mime) {
data = data.split(',')[1]
data = window.atob(data)
var ia = new Uint8Array(data.length)
for (var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i)
}
// canvas.toDataURL 返回的默认格式就是 image/png
return new Blob([ia], {
type: mime
})
},
/**
* input chanage 触发事件
*/
fileChange(e) {
const files = e.target.files || e.dataTransfer.files
this.setSourceImg(files[0]).then(() => {
const fileBlob = this.data2blob(this.imgsUrl, this.mime)
const turnData = {
imgUrl: this.imgsUrl,
file: fileBlob
}
this.$emit('updateImgData', turnData)
})
},
/**
* 二进制流的生成
*/
setSourceImg(file) {
const that = this
return new Promise((resolve, reject) => {
const fr = new FileReader()
fr.onload = function(e) {
that.imgsUrl = fr.result
that.mime = file.type
resolve(fr.result)
}
fr.onerror = function() {
reject()
}
fr.readAsDataURL(file)
})
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss"; // css变量
.upload-wrap{
justify-content: flex-start;
.box-w{
width:200px;
height:150px;
}
.upload-box{
position:relative;
margin-left:10px;
overflow:hidden;
text-align:center;
cursor:pointer;
border:1px dashed #e0e0e0;
border-radius: 6px;
transition: border .3s;
&:hover{
border-color:$mainColor;
}
}
.upload-text{
margin-top:-10px;
line-height: 20px;
font-size: 14px;
color: #606266;
}
.icon-qr-code {
$wh: 110px;
width: $wh;
height: $wh;
transition: border .3s;
}
.file-input{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
outline: none;
background-color: transparent;
filter:alpha(opacity=0);
-moz-opacity:0;
-khtml-opacity: 0;
opacity: 0;
}
.img-box{
overflow:hidden;
border-radius:4px;
background-color:pink;
}
}
</style>
调用:
<UploadImg :image-url="imageUrl" @updateImgData="updateImgData" />
案例三、
来源与网络
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>XMLHttpRequest上传文件</title>
<script type="text/javascript">
/*
三个参数
file:一个是文件(类型是图片格式),
w:一个是文件压缩的后宽度,宽度越小,字节越小
objDiv:一个是容器或者回调函数
photoCompress()
*/
function photoCompress(file, w, objDiv) {
debugger
var ready = new FileReader();
/*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(file);
ready.onload = function () {
var re = this.result;
canvasDataURL(re, w, objDiv)
}
}
function canvasDataURL(path, obj, callback) {
debugger
var img = new Image();
img.src = path;
img.onload = function () {
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.7; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
}
}
/**
* 将以base64的图片url数据转换为Blob
* @param urlData
* 用url方式表示的base64图片数据
*/
function convertBase64UrlToBlob(urlData) {
// debugger
const arr = urlData.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const val = new Blob([u8arr], { type: mime })
// debugger
return val
}
var xhr;
//上传文件方法
function UpladFile() {
var fileObj = document.getElementById("file").files[0]; // js 获取文件对象
var url = "后台图片上传接口"; // 接收上传文件的后台地址
var form = new FormData(); // FormData 对象
if (fileObj.size / 1024 > 1025) { //大于1M,进行压缩上传
console.log('大于1M,进行压缩上传')
debugger
photoCompress(fileObj, {
quality: 0.2
}, function (base64Codes) {
//console.log("压缩后:" + base.length / 1024 + " " + base);
var bl = convertBase64UrlToBlob(base64Codes);
form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
xhr.onload = uploadComplete; //请求完成
xhr.onerror = uploadFailed; //请求失败
xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】
xhr.upload.onloadstart = function () {//上传开始执行方法
ot = new Date().getTime(); //设置上传开始时间
oloaded = 0;//设置上传开始时,以上传的文件大小为0
};
xhr.send(form); //开始上传,发送form数据
});
} else { //小于等于1M 原图上传
console.log('小于等于1M 原图上传');
debugger
form.append("file", fileObj); // 文件对象
xhr = new XMLHttpRequest(); // XMLHttpRequest 对象
xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
xhr.onload = uploadComplete; //请求完成
xhr.onerror = uploadFailed; //请求失败
xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】
xhr.upload.onloadstart = function () {//上传开始执行方法
ot = new Date().getTime(); //设置上传开始时间
oloaded = 0;//设置上传开始时,以上传的文件大小为0
};
xhr.send(form); //开始上传,发送form数据
}
}
//上传成功响应
function uploadComplete(evt) {
//服务断接收完文件返回的结果
var data = JSON.parse(evt.target.responseText);
if (data.success) {
alert("上传成功!");
} else {
alert("上传失败!");
}
}
//上传失败
function uploadFailed(evt) {
alert("上传失败!");
}
//取消上传
function cancleUploadFile() {
xhr.abort();
}
//上传进度实现方法,上传过程中会频繁调用该方法
function progressFunction(evt) {
var progressBar = document.getElementById("progressBar");
var percentageDiv = document.getElementById("percentage");
// event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
if (evt.lengthComputable) {//
progressBar.max = evt.total;
progressBar.value = evt.loaded;
percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
}
var time = document.getElementById("time");
var nt = new Date().getTime();//获取当前时间
var pertime = (nt - ot) / 1000; //计算出上次调用该方法时到现在的时间差,单位为s
ot = new Date().getTime(); //重新赋值时间,用于下次计算
var perload = evt.loaded - oloaded; //计算该分段上传的文件大小,单位b
oloaded = evt.loaded;//重新赋值已上传文件大小,用以下次计算
//上传速度计算
var speed = perload / pertime;//单位b/s
var bspeed = speed;
var units = 'b/s';//单位名称
if (speed / 1024 > 1) {
speed = speed / 1024;
units = 'k/s';
}
if (speed / 1024 > 1) {
speed = speed / 1024;
units = 'M/s';
}
speed = speed.toFixed(1);
//剩余时间
var resttime = ((evt.total - evt.loaded) / bspeed).toFixed(1);
time.innerHTML = ',速度:' + speed + units + ',剩余时间:' + resttime + 's';
if (bspeed == 0) time.innerHTML = '上传已取消';
}
</script>
</head>
<body>
<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
<span id="percentage"></span><span id="time"></span>
<br /><br />
<input type="file" id="file" name="myfile" accept="image/x-png, image/jpg, image/jpeg, image/gif" />
<input type="button" onclick="UpladFile()" value="上传" />
<input type="button" onclick="cancleUploadFile()" value="取消" />
</body>
</html>