ElementUI先展示图片再手动上传的示例

1,135 阅读4分钟

一、背景和意义

element-ui中有一个用户图片或其他文件上传的组件el-upload,相关文档的链接为element.eleme.cn/#/zh-CN/com… 就图片上传而言element-ui官方提供的el-upload的demo的实际应用中会存在两方面问题:

1.1 问题一:自动上传

例如对于大部分demo,如:

image.png

当用户点击“点击上传”按钮之后,页面弹出文件选择框:

image.png

当选择图片之后,el-upload组件会立即调用后端接口执行上传操作。 但是在实际应用中,文件上传往往是跟其他表单配置放一起的,例如像这样:

image.png

用户选了图片之后,不一定马上创建/修改配置,可能会想一想、修改一下其他字段、换一个图片、基础取消创建/修改操作。这时候就把图片上传到服务器上一方面可能会浪费服务器资源;另一方面如果图片比较大,那么上传可能需要一些时间,用户还没有提交就执行一个比较耗时的操作会影响用户体验(如果是用户确定提交了,此时页面转一会圈圈执行一些稍微耗时的操作一般而言是可接受的)。

1.2 问题二:图片预览

element-ui官方demo提供了一个手动上传的例子,如下图所示:

image.png

但是这个例子中上传图片之后,仅显示了一个文件名列表,没有展示上传的图片的预览效果。

综上所述,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代码对应的页面展示效果为:

image.png

点击“+”符号后将弹出图片选择框,选择好之后点击“上传到服务器”,Chrome开发者工具上打印上传图片的内容:

image.png

在实际中可能会将图片内容作为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的

image.png

所以前面那段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,那么在上传图片之后将会看到图片的文件名,如下图所示:

image.png

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/…