上传前预览图片

2118

在上传文件(图片)之前,我想能够预览该文件。 预览操作应完全在浏览器中执行,而不使用Ajax上传图像。

我如何做到这一点?


请注意,除非您使用Gears或其他插件,否则无法在浏览器内部操作图像:http://code.google.com/p/chromium/issues/detail?id=32276 - Steve-o
快来看看这个纯JavaScript实现的方法,其中包括了答案以及Ray Nicholus对最终解决方案的评论:https://dev59.com/SWQn5IYBdhLWcg3w9bGi - Jonathan Root
30个回答

3291

imgInp.onchange = evt => {
  const [file] = imgInp.files
  if (file) {
    blah.src = URL.createObjectURL(file)
  }
}
<form runat="server">
  <input accept="image/*" type='file' id="imgInp" />
  <img id="blah" src="#" alt="your image" />
</form>


17
我已经用ReactJS实现了这个项目的代码,非常流畅。@kxc你应该发起一个ajax请求,并将input.files[0]作为数据发送,可以参考jQuery文档 - Sumi Straessle
1
如果上传后没有选择文件怎么办? - TarangP
Internet Explorer 20H2 版本提示 evt => 是错误的语法 :(。 - Esamo
@Esamo,请将其更改为普通函数声明,而不是箭头函数。 - Sgnl
由于某些原因,这个对我不再起作用了。它之前是可以工作的,但我在另一个文档上尝试了一下,它就停止工作了... - Adan Vivero
显示剩余3条评论

521

有几种方法可以实现这个目标。最有效的方法是使用URL.createObjectURL()处理来自<input>File文件。将此URL传递给img.src以告诉浏览器加载提供的图像。

以下是示例:

<input type="file" accept="image/*" onchange="loadFile(event)">
<img id="output"/>
<script>
  var loadFile = function(event) {
    var output = document.getElementById('output');
    output.src = URL.createObjectURL(event.target.files[0]);
    output.onload = function() {
      URL.revokeObjectURL(output.src) // free memory
    }
  };
</script>

你可以使用 FileReader.readAsDataURL() 方法解析来自<input>的文件。这将在内存中创建一个包含图像的base64表示的字符串。

<input type="file" accept="image/*" onchange="loadFile(event)">
<img id="output"/>
<script>
  var loadFile = function(event) {
    var reader = new FileReader();
    reader.onload = function(){
      var output = document.getElementById('output');
      output.src = reader.result;
    };
    reader.readAsDataURL(event.target.files[0]);
  };
</script>


15
为避免内存问题,当您使用完Blob对象后,应调用URL.revokeObjectURL方法。 - Apolo
7
不在这种情况下,看看这个答案:https://dev59.com/OVUM5IYBdhLWcg3wMN19#49346614 - grreeenn
关于您的第一条评论@tfmontague。你确定吗?我只是复制了使用readAsDataURL后的bese64字符串,并在另一个浏览器中打开它,它可以正常工作。 - Ionel Lupu
@Lonel Lupu - 相信我的答案是不正确的!我还使用了readAsDataURL,并成功将base64字符转换为图像。 - tim-montague
2
请仔细阅读:当使用文件输入上传图像时,它会存储在浏览器的缓存中。URL.createObjectURL()将创建一个链接到浏览器上缓存图像的链接。要创建可存储在数据库中的文件的base64字符串,请使用readAsDataURL - tim-montague

300

一行代码解决方案:

以下代码使用对象URL,相较于数据URL来查看大型图片更加高效(数据URL是一个包含所有文件数据的巨大字符串,而对象URL只是一个引用内存中文件数据的短字符串):

<img id="blah" alt="your image" width="100" height="100" />

<input type="file" 
    onchange="document.getElementById('blah').src = window.URL.createObjectURL(this.files[0])">

生成的URL将类似于:

blob:http%3A//localhost/7514bc74-65d4-4cf0-a0df-3de016824345

2
@Raptor,整个文件API也是如此...(FileReaderinput.files等)URL.createObjectURL是处理用户提交的文件时的最佳选择,它只会在内存中创建一个指向用户磁盘上真实文件的符号链接。 - Kaiido
@cnlevy 我们如何访问已上传的文件?像你提到的那样,仅通过URL获取是唯一的方式吗? 具体来说,我正在使用Flask,其已支持访问上传的文件。在这个一行代码中,是否还有其他方法? - Abhishek Singh
1
这个解决方案对我没用。图片预览没有显示。 - Sundaramoorthy J
我遇到了一个错误:“files未定义”。我正在使用react.js。 - Gilbert
2
很漂亮。但是使用URL.revokeObjectURL()清除内存怎么样? :D - user15023244
1
@pheianox 这取决于您,因为这并不是一个很大的问题。 "浏览器会在文档卸载时自动释放对象URL;但是,为了获得最佳性能和内存使用率,如果有安全的时间可以显式地卸载它们,您应该这样做"。有关更多信息,请参见MDN参考 - Rajan

70

试一下


在不使用 Ajax 或任何复杂的函数的情况下,从浏览器上传图像到服务器之前预览图像。


需要一个"onChange"事件来加载图像。

function preview() {
    frame.src=URL.createObjectURL(event.target.files[0]);
}
<form>
  <input type="file" onchange="preview()">
  <img id="frame" src="" width="100px" height="100px"/>
</form>

要预览多个图像,请点击此处


3
重要提示:如果使用此方法,必须删除对象URL以防止内存泄漏。这可以通过调用URL.revokeObjectURL(myObjectUrl)来完成,其中myObjectUrl是创建的对象URL(这意味着您需要将对象URL分配给临时变量,然后再设置图像src)。请参见https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL#memory_management。 - Isaac Gregson
这对于单个图像来说很有效,如果有三个具有不同id和src的图像文件,它不会改变下一个图像的源。 - Zohaib Yunis

46

LeassTaTT的答案在“标准”浏览器(如FF和Chrome)中效果很好。对于IE,解决方案存在但看起来不同。这里提供跨浏览器解决方案的描述:

在HTML中,我们需要两个预览元素,img用于标准浏览器,div用于IE

HTML:

<img id="preview" 
     src="" 
     alt="" 
     style="display:none; max-width: 160px; max-height: 120px; border: none;"/>

<div id="preview_ie"></div>

在CSS中,我们指定以下IE特定的内容:
CSS:
#preview_ie {
  FILTER: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)
}  

在HTML中,我们包含标准和IE专用的Javascripts:
<script type="text/javascript">
  {% include "pic_preview.js" %}
</script>  
<!--[if gte IE 7]> 
<script type="text/javascript">
  {% include "pic_preview_ie.js" %}
</script>

pic_preview.js 是来自 LeassTaTT 回答的 JavaScript。将 $('#blah') 替换为 $('#preview'),并添加 $('#preview').show()

现在是针对 IE 的特定 JavaScript(pic_preview_ie.js):

function readURL (imgFile) {    
  var newPreview = document.getElementById('preview_ie');
  newPreview.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgFile.value;
  newPreview.style.width = '160px';
  newPreview.style.height = '120px';
}    

这就是全部内容。适用于IE7、IE8、FF和Chrome。请在IE9中测试并报告。IE预览的想法可以在此找到:http://forums.asp.net/t/1320559.aspxhttp://msdn.microsoft.com/en-us/library/ms532969(v=vs.85).aspx

42

简短的两行文字

这是对 cmlevy 答案 的尺寸改进 - 请尝试

<input type=file oninput="pic.src=window.URL.createObjectURL(this.files[0])">
<img id="pic" />


如何获取整个文件路径? - Bbb
2
@Bbb,它看起来不像是典型的路径 - 它看起来像是一些临时的“链接”:blob:null/35c35011-111c-4d9e-ac3f-a779e049eb3d - Kamil Kiełczewski

29

我已经编辑了@Ivan的答案,以显示“无法预览”的图像,如果它不是一张图片:

function readURL(input) {
    var url = input.value;
    var ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
    if (input.files && input.files[0]&& (ext == "gif" || ext == "png" || ext == "jpeg" || ext == "jpg")) {
        var reader = new FileReader();

        reader.onload = function (e) {
            $('.imagepreview').attr('src', e.target.result);
        }

        reader.readAsDataURL(input.files[0]);
    }else{
         $('.imagepreview').attr('src', '/assets/no_preview.png');
    }
}

21

这是一个基于 Ivan Baev 的回答的多文件版本。

HTML 代码

<input type="file" multiple id="gallery-photo-add">
<div class="gallery"></div>

JavaScript / jQuery

:JavaScript 是一种常用的编程语言,可在网页上实现互动和动态效果。而 jQuery 则是一个 JavaScript 库,简化了 JavaScript 的编写和操作,使开发者可以更快速、方便地创建交互式网页。
$(function() {
    // Multiple images preview in browser
    var imagesPreview = function(input, placeToInsertImagePreview) {

        if (input.files) {
            var filesAmount = input.files.length;

            for (i = 0; i < filesAmount; i++) {
                var reader = new FileReader();

                reader.onload = function(event) {
                    $($.parseHTML('<img>')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
                }

                reader.readAsDataURL(input.files[i]);
            }
        }

    };

    $('#gallery-photo-add').on('change', function() {
        imagesPreview(this, 'div.gallery');
    });
});

由于使用了$.parseHTML,需要jQuery 1.8及以上版本,这可以帮助防止跨站脚本攻击。

此插件可直接使用,唯一的依赖是jQuery。


1
JS Fiddle 版本 https://jsfiddle.net/iffikhan30/f7xozt8q/1/ - Irfan
有没有一种方法可以使用上述代码将图像包装到 div 中? - Zaheer Abbas
一切皆有可能。 - The Onin

19

是的,这是可能的。

Html

<input type="file" accept="image/*"  onchange="showMyImage(this)" />
 <br/>
<img id="thumbnil" style="width:20%; margin-top:10px;"  src="" alt="image"/>

JavaScript

 function showMyImage(fileInput) {
        var files = fileInput.files;
        for (var i = 0; i < files.length; i++) {           
            var file = files[i];
            var imageType = /image.*/;     
            if (!file.type.match(imageType)) {
                continue;
            }           
            var img=document.getElementById("thumbnil");            
            img.file = file;    
            var reader = new FileReader();
            reader.onload = (function(aImg) { 
                return function(e) { 
                    aImg.src = e.target.result; 
                }; 
            })(img);
            reader.readAsDataURL(file);
        }    
    }
你可以从这里获取Live Demo

12

使用jQuery预览多个文件

$(document).ready(function(){
    $('#image').change(function(){
        $("#frames").html('');
        for (var i = 0; i < $(this)[0].files.length; i++) {
            $("#frames").append('<img src="'+window.URL.createObjectURL(this.files[i])+'" width="100px" height="100px"/>');
        }
    });
});
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
    <input type="file" id="image" name="image[]" multiple /><br/>
    <div id="frames"></div>
</body>


为什么 $(this)[0].files 要优于 this.files - Endless
$(this)[0].files --> 返回所选图像的数量或 [object FileList] - Merrin K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接