原生js實現圖片預覽並上傳


最近主導的PC客戶端網站重構工程告一段落,下一階段開始給公司APP開發H5頁面,技術棧是react。最近碰到一個需求:需要在H5頁面上添加身份證照片,預覽並上傳。因為要兼容安卓4.4以下版本的手機,所以連html5的新屬性formData都用不了,純原生js實現。

首先獲取input輸入框,並給其注冊onchange事件。 

uploadImage(){
        let idCardFrontParams={
            showID: "img-box1",
            flag: "idCardFrontFileId"
        };
        let $this=this;
        //獲取頁面的input標簽
        var idCardFrontFile = document.getElementById("idCardFrontFile");
        idCardFrontFile.onchange = function () {
            let that = this;
            $this.preview(that, idCardFrontParams);
        };
    }

 接下來是實現上傳並預覽功能,預覽的關鍵是使用getObjectURL方法來獲得所上傳圖片的url地址。URL.createObjectURL()方法會根據傳入的參數創建一個指向該參數對象的URL,這個URL的生命僅存在於它被創建的這個文檔里,新的對象URL指向執行的File對象或者是Blob對象。其語法為:objectURL = window.URL.createObjectURL(blob || file);不同瀏覽器有差異

獲得圖片url后調用表單的方法submit將其上傳, 並將其地址賦給指定的div。

preview(that, options) {
        //接受files數組列表
        let _file = that.files,$this=this;
        if(_file[0]){
            let addr = getObjectURL(_file[0]);
            let curFile=options.flag;
            this.setState({isLoading:true});
            document.querySelector("#"+curFile).submit();
            if(curFile==="deviceFileId"){
                $this.setState({deviceFile:true});
            }else if(curFile==="idCardFrontFileId"){
                $this.setState({idCardFrontFile:true});
            }else if(curFile==="idCardbackFileId"){
                $this.setState({idCardBackFile:true});
            }

            var fileUpIframe = document.getElementById("file_upload_iframe");
            fileUpIframe.onload = fileUpIframe.onreadystatechange =  function () {
                try {
                    var data = JSON.parse(fileUpIframe.contentWindow.document.body.innerHTML);
                    if (data.code) {
                        $this.submitParams[curFile]="";
                        alert("上傳圖片失敗,請刷新頁面重試!");
                    } else {
                        $this.submitParams[curFile]=data.fileId;
                    }
                    $this.setState({isLoading:false});
                }catch (err){
                    console.warn(err);
                }
            }
            let dom =document.getElementById(options.showID);
            dom.style.backgroundImage = "url("+addr+")";
        }
        function getObjectURL(file) {
            let url = null;
            if (window.createObjectURL != undefined) { // basic
                url = window.createObjectURL(file);
            } else if (window.URL != undefined) { // mozilla(firefox)
                url = window.URL.createObjectURL(file);
            } else if (window.webkitURL != undefined) { // webkit or chrome
                url = window.webkitURL.createObjectURL(file);
            }
            return url;
        }
    }

 在這里由於采用的是最原始的表單提交,而submit方法提交后會跳轉,又不像ajax可以采用回調函數獲取返回值,故需要一個iframe來承載表單提交后的返回值,用target來指向承載返回值的iframe。

<form action="/eyeplus/api/upload" method="post" encType="multipart/form-data" id="idCardbackFileId" target="file_upload_iframe">
                            <input id="idCardBackFile" type="file" accept="image/*" multiple="multiple" name="file" className="uploadImg"/>
                            <input type="text" className="ub-hidden-ele ub-token" readOnly="readOnly" name="token" value={this.submitParams.token}/>
                            <input type="text" className="ub-hidden-ele ub-clientId" readOnly="readOnly" name="client_id" value={this.submitParams.client_id}/>
                            <input type="text" className="ub-hidden-ele ub-deviceId" readOnly="readOnly" name="device_id" value={this.submitParams.device_id}/>
                            <input type="text" className="ub-hidden-ele ub-type" readOnly="readOnly" name="type" value="201" />
                        </form>
<iframe style={{display: "none"}} id="file_upload_iframe" name="file_upload_iframe"></iframe>

在確認服務器得到正確上傳后的,使用方法JSON.parse(fileUpIframe.contentWindow.document.body.innerHTML)來解析服務器返回值,並與其它所需要的參數組合在一起,就可以愉快的進行下一步操作了。

-----------------------------------------------------補充於2018/06/29--------------------------------------------------------------

以上方法雖然能完成需求開發,但后續測試的時候發現了一個問題:IOS手機是沒問題的,只是在安卓手機上,在返回的時候因iframe的存在,導致多級頁面從而使得頁面標題欄變化但是頁面內容沒變化,故點擊返回的時候並不能准確的返回。不得不說這是個大坑,經反復實踐,采用了下面這種方法順利通過測試。

preview(that, options) {
        //接受files數組列表
        let _file = that.files, $this = this;
        if (_file[0]) {
            let addr = getObjectURL(_file[0]);
            let curFile = options.flag;
            this.setState({isLoading: true});
            if (curFile === "deviceFileId") {
                $this.setState({deviceFile: true});
            } else if (curFile === "idCardFrontFileId") {
                $this.setState({idCardFrontFile: true});
            } else if (curFile === "idCardbackFileId") {
                $this.setState({idCardBackFile: true});
            }
            let dom = document.getElementById(options.showID);
            dom.style.backgroundImage = "url(" + addr + ")";

            let frameId = 'uploadFrame'+ new Date().getTime();
            let fileUpIframe = document.createElement("iframe");
            fileUpIframe.id = fileUpIframe.name = frameId;
            fileUpIframe.style.display = 'none';
            document.body.appendChild(fileUpIframe);
            //let fileUpIframe = document.getElementById("file_upload_iframe");
            fileUpIframe.onload = fileUpIframe.onreadystatechange = function () {
                try {
                    var data = JSON.parse(fileUpIframe.contentWindow.document.body.innerHTML);
                    if (data.code) {
                        $this.submitParams[curFile] = "";
                        alert($this.props.locale.ub_fail_upload);
                    } else {
                        $this.submitParams[curFile] = data.fileId;
                    }
                    $this.setState({isLoading: false});
                    document.body.removeChild(fileUpIframe);
                } catch (err) {
                    console.warn(err);
                }
            };
            let form = document.querySelector("#" + curFile);
            form.target = frameId;
            form.submit();
        }

即先去掉HTML文檔中存在的iframe,然后在預覽上傳時create一個iframe,在上傳時修改表單提交的target為此新建iframe的ID,上傳完成后獲取到數據移除掉這個iframe,從而避免了單頁面存在多級頁面的問題。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM