移动端HTML5 文件预览及上传

本文主要介绍使用HTML5 图片上传及上传前的预览。本人是做PHP后端的,由于前端有时也需要自己写,有空就研究了下图片上传预览,写的都是原生代码,废话不多说,直接上代码。

前端代码


<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>Documenttitle>
    <style>
        *{
            margin:0;
            padding:0;
        }

        ul,ol{
            list-style-type:none;
        }

        .clearfix:after,.clearfix:before{

            display:table;
            content:' ';
        }

        .clearfix:after{
            clear:both
        }

        .tc{
            text-align:center;
        }

        .select,.select_video{
            height:2rem;
            line-height:2rem;
            background:#fff;
            border:1px solid #4285F4;
            margin:0.5rem 1rem;
            position:relative;
        }

        .select label,.select_video label{
            width:100%;
            position:absolute;
            top:0;
            left:0;
            font-size:14px;
            color:#333;
        }

        #upload,#upload_video{
            display:none;
        }

        .preview,.video_preview{
            margin:0.5rem 1rem;
            border:1px solid #bbb;
            padding:4px;
            display:none;
        }

        .preview_img_list li{
            float:left;
            width:25%;
            padding:2px 0;

        }   

        .preview_img_list li img{
            vertical-align:top;
            max-width:98%;
        }

        .btn{
            background: #4285F4;
            color:#fff;
            height:2.5rem;
            line-height:2.5rem;
            margin:2rem 1rem;
            border-radius:0.5rem;
        }
    style>
    <script>
        window.onload = function(){

            var uploadBtn = document.querySelector('#upload');
            var previewImgList = document.querySelector('.preview_img_list');

            var uploadVideo = document.querySelector('#upload_video');
            var submitBtn = document.querySelector('.submit');

            imgArr = new Array();

            uploadBtn.addEventListener('change',function(){
                var imgLen = this.files.length;
                var liLen = previewImgList.getElementsByTagName('li').length;
                var ImgLen = imgLen + liLen ;

                if(ImgLen > 9){
                    alert("上传最大数量不能大于9");
                    return false;
                }

                document.querySelector(".preview").style.display = 'block';

                for(var i = 0; i < imgLen;i++){
                    var file = this.files[i];
                    var imgType = /^image\//;

                    if(!imgType.test(file.type)){
                        continue;
                    }

                    var li = document.createElement('li');
                    var img = document.createElement("img");

                    li.appendChild(img);
                    previewImgList.appendChild(li); 

                    var reader = new FileReader();
                    reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; initHW(); imgArr.push(e.target.result);}; })(img);
                    reader.readAsDataURL(file);
                    // var objectUrl = window.URL.createObjectURL(file);
                    // img.src = objectUrl;
                }

            },false);


            uploadVideo.addEventListener('change',function(){
                var file = this.files[0];
                var videoType = /^video\//;

                if(!videoType.test(file.type)){
                    alert("所选文件不是合法的视频文件");
                    return false;
                }

                var pv =  document.querySelector('.video_preview');
                var video =  document.createElement('video');
                video.setAttribute('controls','controls');
                video.style.width = "100%";

                pv.appendChild(video);
                pv.style.display = "block";
                // var objectUrl = window.URL.createObjectURL(file);
                // video.src = objectUrl;
                // 
                var reader = new FileReader();
                reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(video);
                reader.readAsDataURL(file);
                video.play();
            },false);

            submitBtn.addEventListener('click',function(){
                if(!imgArr.length){
                    alert('请选择要上传的图片');
                    return false;
                }
                var form = document.querySelector('form');
                var fd = new FormData(form);
                for(var i = 0;i < imgArr.length;i++){
                    fd.append('file[]',imgArr[i]);
                }

                var request = new XMLHttpRequest();
                var url = "./file_preview.php";
                request.open('post',url);
                request.send(fd);
            },false);

        }



        // 初始化图片宽度
        // 使得图片高度一致
        function initHW(){
            var previewImgList = document.querySelector('.preview_img_list');
            var Lis = previewImgList.getElementsByTagName('li');

            var LisLen = Lis.length;

            if(LisLen > 1){
                var img = Lis[0].getElementsByTagName('img')[0];

                var imgW = img.width;
                var imgH = img.height;

                for(var i = 1; i < LisLen; i++){
                    var img = Lis[i].getElementsByTagName('img')[0];
                    img.style.width = imgW + 'px';
                    img.style.height = imgH + 'px';
                }
            }

        }


    script>
head>
<body>
    <h2 class = "tc">图片上传及预览h2>
    <form action="" >
        <div class="select tc" >
            <label for="upload">图片上传及预览label>
            <input type="file" id = "upload" multiple="multiple" accpet = "image/*" capture = "camera" >
        div>

        <div class="preview">
            <ul class = "preview_img_list clearfix">

            ul>
        div>

        <div class="select_video tc">
            <label for="upload_video">视频上传及预览label>
            <input type="file" id = "upload_video" accpet = "video/*" capture = "camcorder">
        div>

        <div class="video_preview">

        div>

        <div class="submit btn tc">上传div>
    form>
body>
html>

看效果:

在google chrome 浏览器打开效果

移动端HTML5 文件预览及上传_第1张图片

手机uc浏览器打开

移动端HTML5 文件预览及上传_第2张图片

移动端HTML5 文件预览及上传_第3张图片

在手机浏览器打开会调用手机摄像头进行拍摄。

抛开美观不说,暂且讨论下兼容性,除了苹果safari没测试外,在现在主流浏览器上(ie8以上级别),展示效果差不多。

下面开始讲解代码(关键部分代码)
文件预览主要是用到了这个webApi :FileReader

var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; initHW(); imgArr.push(e.target.result);}; })(img);
reader.readAsDataURL(file);
// var objectUrl = window.URL.createObjectURL(file);
// img.src = objectUrl;
// imgArr.push(e.target.result);
}

首先是新建了一个FileReader 对象,然后是readAsDataURL(file),该方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。 在读取操作完成时触发reader.onload事件,在该事件出来处理中,将读取的图片内容赋值给生成的img dom的src 属性。然后初始化预览图片高度(inintHW()),将base64编码内容push 到数组中。

上面注释掉的代码跟没注释的代码功能是一样的,只不过该api 有兼容性问题,我看到也有网友使用该api实现了图片预览功能,但我个人看法跟官方给的提示一样,暂时不建议使用!!!

移动端HTML5 文件预览及上传_第4张图片

至于FileReader 这个web api 的使用说明,详情请移步:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
URL.createObjectURL() 用法:https://developer.mozilla.org/zh-CN/docs/Web/API/URL/createObjectURL

再看一下视频预览:
移动端HTML5 文件预览及上传_第5张图片

移动端HTML5 文件预览及上传_第6张图片

移动端HTML5 文件预览及上传_第7张图片

视频预览是跟图片预览原理是一样的。

不过在移动端即便这样子写 也不会调起手机摄像,至于为什么要这样子写,我也不是很懂,在网上查资料,看到有人这样子做,就尝试了下,果然不行,不过读取文件预览是没问题的,这里暂不考虑这个问题。

下面来看上传功能代码(只讨论图片上传):

submitBtn.addEventListener('click',function(){
       if(!imgArr.length){
          alert('请选择要上传的图片');
          return false;
       }
       var form = document.querySelector('form');
       var fd = new FormData(form);
       for(var i = 0;i < imgArr.length;i++){
           fd.append('file[]',imgArr[i]);
        }

       var request = new XMLHttpRequest();
       var url = "./file_preview.php";
       request.open('post',url);
       request.send(fd);
},false);

关键代码fd.append('file[]',imgArr[i]); 在for循环中,写成file[]是为了后台PHP 处理方便,写成这个样子,PHP后台可以把它当做数组来处理。

这里使用了ajax 和 formData ,如果不熟悉这两个知识点,请移步
ajax: https://developer.mozilla.org/zh-CN/docs/Web/Guide/AJAX
formData:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData

file_preview.php 代码


$imgCount = count($_POST['file']);
for($i = 0;$i < $imgCount;$i++){
    if(preg_match('/^(data:\s*image\/(\w+);base64,)/',$_POST['file'][$i],$result)){

        $ImageType = $result[2];
        $res = str_replace($result[0],'',$_POST['file'][$i]);
        $filePath = './';
        $fileName = mt_rand().'.'.$ImageType;
        file_put_contents($filePath.$fileName,base64_decode($res));
    }else{
        return false;
    }
}

讲解:首先判断上传的文件的数量,$imgCount = count($_POST['file']); 然后循环处理,正则匹配文件名后缀,preg_match('/^(data:\s*image\/(\w+);base64,)/',$_POST['file'][$i],$result),获取文件名后缀:$ImageType = $result[2];,然后将类似data:image/png;base64,头给处理掉:$res = str_replace($result[0],'',$_POST['file'][$i]);,然后保存图片到服务器:file_put_contents($filePath.$fileName,base64_decode($res));

为什么要将base64编码:data:image/png;base64 给处理掉呢?因为如果直接放到php里用base64_decode函数解码会导致最终保存的图片文件格式损坏,而解决方法就是先去掉这一base64识别部分。

整体效果图:
移动端HTML5 文件预览及上传_第8张图片

移动端HTML5 文件预览及上传_第9张图片

你可能感兴趣的:(php,javascript,html5,+,css,正则)