一、背景和意义
element-ui中有一个用户图片或其他文件上传的组件el-upload,相关文档的链接为element.eleme.cn/#/zh-CN/com… 就图片上传而言element-ui官方提供的el-upload的demo的实际应用中会存在两方面问题:
1.1 问题一:自动上传
例如对于大部分demo,如:
当用户点击“点击上传”按钮之后,页面弹出文件选择框:
当选择图片之后,el-upload组件会立即调用后端接口执行上传操作。 但是在实际应用中,文件上传往往是跟其他表单配置放一起的,例如像这样:
用户选了图片之后,不一定马上创建/修改配置,可能会想一想、修改一下其他字段、换一个图片、基础取消创建/修改操作。这时候就把图片上传到服务器上一方面可能会浪费服务器资源;另一方面如果图片比较大,那么上传可能需要一些时间,用户还没有提交就执行一个比较耗时的操作会影响用户体验(如果是用户确定提交了,此时页面转一会圈圈执行一些稍微耗时的操作一般而言是可接受的)。
1.2 问题二:图片预览
element-ui官方demo提供了一个手动上传的例子,如下图所示:
但是这个例子中上传图片之后,仅显示了一个文件名列表,没有展示上传的图片的预览效果。
综上所述,element-ui提供了有图片预览效果的demo,也提供了手动上传图片的demo,但缺少手动上传图片同时支持图片预览的demo。本文将提供一个手动上传图片同时支持图片预览的demo,并对其作一些说明。
二、代码示例
手动上传图片同时支持图片预览的demo如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.15.13/lib/theme-chalk/index.min.css">
<script src="https://cdn.jsdelivr.net/npm/element-ui@2.15.13/lib/index.min.js"></script>
<style>
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
cursor: pointer;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
.image {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
}
</style>
</head>
<body>
<div id="app">
<el-upload
class="image-uploader"
:on-change="uploadImageChanged"
:auto-upload="false"
:show-file-list="false">
<img v-if="imageUrl" :src="imageUrl" class="image">
<i v-else class="el-icon-plus image"></i>
</el-upload>
<el-button style="margin-top: 10px;" type="success" @click="doUpload">上传到服务器</el-button>
</div>
</body>
<script>
function toBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
let fileResult = '';
reader.readAsDataURL(file.raw);
reader.onload = () => fileResult = reader.result;
reader.onerror = error => reject(error);
reader.onloadend = () => resolve(fileResult);
});
};
new Vue({
el: "#app",
data : { imageUrl: '' },
methods: {
uploadImageChanged (file) { toBase64(file).then(result => this.imageUrl = result) },
doUpload() { console.log("upload image: ", this.imageUrl) }
}
});
</script>
</html>
该HTML代码对应的页面展示效果为:
点击“+”符号后将弹出图片选择框,选择好之后点击“上传到服务器”,Chrome开发者工具上打印上传图片的内容:
在实际中可能会将图片内容作为json数据中的一个字段,调用相关服务端接口。
三、代码解读
3.1 样式相关
代码中的CSS样式的前面部分为:
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
cursor: pointer;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
其中HTML代码中的<el-upload>标签会生成一个class属性为el-upload的
所以前面那段CSS代码是画出上传组件的外边框,当鼠标移动到上传组件上时显示为手形,另外通过.el-upload:hover指明当鼠标挪上去时边框变成不同的颜色。
接下来的CSS代码是:
image {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
}
这段CSS对应的HTML元素为:
<img v-if="imageUrl" :src="imageUrl" class="image">
<i v-else class="el-icon-plus image"></i>
其中<img>和<i>都是<el-upload>下的内容,一个是有设置图片时展示图片,另一个是没有图片时展示是个“+”号。<img>和<i>的大小应该是要一样的,这里用width和height属性指明大小都是178px;另外的font-size、color设置是用于<i>,指明“+”号的大小与颜色;line-height: 178px设置行高与height一样高,这将会使得“+”号在垂直方向居于上传组件框中的中间。
3.2 el-upload组件配置相关
在<el-upload>标签中:on-change="uploadImageChanged"表示用户选择文件之后调用的方法,auto-upload="false"表示用户选择文件之后不自动地调用文件上传的接口,:show-file-list="false"表示上传文件之后,不展示文件列表,如果show-file-list未设置或者设置为true,那么在上传图片之后将会看到图片的文件名,如下图所示:
3.3 读取图片内容
:on-change="uploadImageChanged"指明了选择图片之后调用的方法,uploadImageChanged又调用了一个toBase64方法,其内部使用FileReader类读取文件的内容:
function toBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
let fileResult = '';
reader.readAsDataURL(file.raw);
reader.onload = () => fileResult = reader.result;
reader.onerror = error => reject(error);
reader.onloadend = () => resolve(fileResult);
});
};
其中FileReader类的readAsDataURL方法表示开始读取指定的文件中的内容。一旦完成,result属性中将包含一个Base6字符串以表示所读取文件的内容。FileReader类的更多用法可以参考mozilla的官方文档: developer.mozilla.org/zh-CN/docs/…