前言
今天我们聊一聊图片上传, 单张 Or 多张 , 如今, 各大图片上传插件数不胜数, 例如: jQuery 的 verupload.JS,jQuery File Upload,Uploadify,jQuery.filter 等等. But. 上面说到的这些插件, 今天我们不谈, 我们来看一看使用 html5 中的 FileReader 如何实现 图片的单张及多张预览, 删除, 上传等功能.
先看下实现后的效果如下:
实现
前端部分
这块是用户点击按钮 其中我们最重要的一句话是 input type=file 和给了一个 multiple 属性, 可以满足多张图片上传
- <div class="form-group form-row">
- <label class="col-sm-2 control-label uText">俱乐部相册</label><div class="row">
- <div class="col-xs-10 col-sm-8 mTop5">
- <label title="上传俱乐部相册" for="ClubImagesUpload" id="btnClubImg" class="col-sm-2">
- <input type="file" accept="image/*" name="ClubImagesUpload" id="ClubImagesUpload" class="hide" multiple="multiple">
- <img src="/Images/registerNewSite/btn_addimg.png" class="addImg"/>
- </label>
- </div>
- </div></div>
下面这块区域是用于图片预览的
- <div class="form-group form-row" id="preViewMore"><div class="row">
- <div class="col-xs-9">
- <div id="clubInputImagePreview" class="col-sm-9 img-preview img-preview-sm"></div>
- </div>
- </div></div>
样式部分
什么? 连样式你都要看, 还有没有人性(苦笑脸)
JS 部分
首先我们分析下上面的 HTML, 我们用一个 label 把 input 和一个 img 标签包起来了, 我们希望点击效果图那个 + 号图片, 就能弹出选择相片的对话框, 所以, 我们需要先给 label 来一个点击事件:
- $("#btnClubImg").click(function() {
- //TODO Something
- });
接着我们再看, 因为我们是要获取上传的文件, 而我们的文件主要是在 input 上, 所以, 我们先将 input 标签获取到:
- $("#btnClubImg").click(function() {
- var $input = $("#ClubImagesUpload");
- console.log($input);// 打印当前元素
- });
我们将当前 input 元素标签打印出来看看是个什么东东
我们展开第一项会发现 files 里面 length 长度是 0
好, 我们继续分析, 因为我们想要能当 input 框改变的时候, 说简单点 就是有选择到文件的时候, 我们能获取到当前选择的文件, 这个和获取 input 框文字输入是一样的道理, 所以, 经过分析, 我们知道需要给 input 标签加一个 change 事件:
- $("#btnClubImg").click(function() {
- var $input = $("#ClubImagesUpload");
- console.log($input);
- $input.on("change", function () {
- console.log(this);// 打印改变后的当前元素
- });
- });
让我们来瞄一眼, 获取到改变后的 input 元素里面有些啥东东:
这里很清楚得可以看到, 我们获取到了选择的图片, 包括有最后修改事件, 图片名称, 大小以及图片类型(有了文件类型, 我们就可以判断当前用户选择的是否是图片不是吗(斜眼笑))
同样, 这是单个文件的, 如果是多个文件, 就会有多个 file
接着往下看, 通过打印输出我们可以看到, 我们再 input 标签的 files 元素上已经拿到了我们想要的文件信息, 我们只需要获取它们就行了:
- var files = this.files;
- var length = files.length;
这样, 我们就可以获取到所有文件, 以及文件的个数, 那这里问题来了, 我们如果是选择多个文件, 如果将其依次输出并展示到页面上呢?
看到上面标注的四个字, 脑袋中有没有闪现出两个字呢? 循环
- $.each(files, function (key, value) {
- //TOTO Something
- });
通过将上面得到的 files 循环, 我们可以依次得到每个文件的信息. 这样, 你就不仅可以将其依次输出, 如果你愿意, 你还可以将其送上天~
- var fileReader = new FileReader();// 实例化一个 FileReader 对象
- var file_ = files[key];// 获取当前文件
- if (/^image\/\w+$/.test(file_.type)) {// 将当前文件进行正则匹配, 看是否是选择的图片
- fileReader.onload = function() {// 当读取操作完成时调用
- }
- }
有必要延伸下 FileReader 的知识点:
FileReader 主要用于将文件内容读入内存, 通过一系列异步接口, 可以在主线程中访问本地文件.
使用 FileReader 对象, web 应用程序可以异步的读取存储在用户计算机上的文件 (或者原始数据缓冲) 内容, 可以使用 File 对象或者 Blob 对象来指定所要处理的文件或数据.
回到主题, 我们已经能够得到文件并且得到返回, 所以此时, 我们只需要展示返回的结果就行了
$("#clubInputImagePreview").CSS("background-image", "url(" + this.result + ")");
我们将其 this.result 打印出来看看是个什么东东:
不言而喻, 是将图片转换成了 Base64 的数据格式. 最后, 我们调用 readAsDataURL 读取文件内容, 将其用 data:url 字符串表示出来
fileReader.readAsDataURL(value);
这样, 你就可以得到一个简易的图片上传的 Demo 了, 但是并不是最终的, 因为你还需要加很多业务进去. 比如: 得到一张预览图片后, 当前标签会被占用, 如果下次循环进来, 直接使用原标签, 肯定会将之前的图片替换, 那这肯定不是我们想要的效果,
我们希望是能依次展示, 而不是替换展示. 所以, 我们还需要做一些处理:
- $("#clubInputImagePreview").CSS("background-image", "url(" + this.result + ")");
- // 使用 apend 再当前元素下追加一个子节点
- $("#clubInputImagePreview") .append("<img src='/Images/registerNewSite/btn_r_del.png'class='clubsImage'id='ImgRemove'/>");
- // 使用 after 向当前兄弟节点 追加一个同级节点
- $("#clubInputImagePreview").after( "<div id='clubInputImagePreview1'class='col-sm-9 img-preview img-preview-sm delImg'></div>");
然后我们追加的删除图片, 也需要给其点击事件, 让我们的当前预览区域消失:
- $("#ImgRemove").click(function () {
- $(this).parent().remove();
- });
最后, 你会发现结果还不是我们想要的, 那是因为 当前 ID 还在, 所以无法进行下一步操作, 而我们只需要将当前元素的 Id Remove 掉, 然后新增一个同 ID 的元素, 这样浏览器就会认为这是一个新的元素:
- $input.removeAttr("id");
- var newInput ='<input type="file"accept="image/*"name="ClubImagesUpload"id="ClubImagesUpload"class="hide"multiple="multiple">';
- $(this).append($(newInput));
最后完整 JS 代码如下:
- var intP = 0;
- $("#btnClubImg").click(function() {
- var $input = $("#ClubImagesUpload");
- // console.log($input);
- $input.on("change",
- function () {
- // console.log(this);
- var files = this.files;
- var length = files.length;
- if (intP> 8) {
- layer.msg('图片不能再多了~', {});
- return;
- }
- $.each(files,
- function (key, value) {
- var fileReader = new FileReader();
- var file_ = files[key];
- if (/^image\/\w+$/.test(file_.type)) {
- fileReader.onload = function() {
- if (intP> 8) {
- layer.msg('图片不能再多了~', {});
- return;
- }
- if (key == 0 && intP == 0) {
- console.log(this.result);
- $("#clubInputImagePreview").CSS("background-image", "url(" + this.result + ")");
- $("#clubInputImagePreview")
- .append(
- "<img src='/Images/registerNewSite/btn_r_del.png'class='clubsImage'id='ImgRemove'/>");
- $("#clubInputImagePreview").after(
- "<div id='clubInputImagePreview1'class='col-sm-9 img-preview img-preview-sm delImg'></div>");
- } else {
- $("#clubInputImagePreview" + parseInt(intP) + "").CSS("background-image",
- "url(" + this.result + ")");
- $("#clubInputImagePreview" + parseInt(intP) + "").append(
- "<img src='/Images/registerNewSite/btn_r_del.png'class='clubsImage'id='ImgRemove" +
- parseInt(parseInt(1) + parseInt(intP)) +"'/>");
- $("#clubInputImagePreview" + parseInt(intP) + "").after(
- "<div id='clubInputImagePreview" +
- parseInt(parseInt(1) + parseInt(intP)) +
- "'class='col-sm-9 img-preview img-preview-sm delImg'></div>");
- }
- if (key == 0 && intP == 0) {
- $("#ImgRemove").click(function () {
- $(this).parent().remove();
- });
- } else {
- $("#ImgRemove" + parseInt(parseInt(1) + parseInt(intP)) + "").click(function () {
- $(this).parent().remove();
- });
- }
- intP += parseInt(1);
- };
- fileReader.readAsDataURL(value);
- } else {
- layer.msg("格式错误 < br/>请选择一个图片文件");
- }
- });
- });
- $input.removeAttr("id");
- var newInput =
- '<input type="file"accept="image/*"name="ClubImagesUpload"id="ClubImagesUpload"class="hide"multiple="multiple">';
- $(this).append($(newInput));
- });
下一篇, 将讲述 如何将前端得到的多个 File , 存入进数据库, 后端是. NET Core, 敬请期待吧~
来源: https://www.cnblogs.com/zhangxiaoyong/p/10765704.html