圖片上傳知識點梳理

在日常項目開發中,圖片上傳是一個十分常見的場景。而現在的各種UI框架都提供了自己的上傳組件,網上第三方的上傳組件也多如牛毛。可能你早已習慣了直接使用這些現成的組件,然而對于其具體的實現,卻并未深入解析。本文將通過簡單的代碼,為你解析圖片上傳的各個知識點。

樣式自定義

既然是上傳,肯定需要使用到<input type="file">標簽了。然而,默認的input到標簽樣式不僅單一,且在各個瀏覽器下的表現也不相同,所以通常需要對input進行樣式自定義。但<input>標簽對于樣式的修改并不十分友好。解決方法很多,最常用的是將<input type="file">標簽隱藏,然后通過一個<label>標簽進行關聯,然后直接修改<label>標簽的樣式來實現。代碼如下:

    &lt;input type="file" id="uploadImg"&gt;&lt;label for="uploadImg"&gt;點擊上傳&lt;/label&gt;

圖片校驗

在上傳之前,一般會對文件進行各種校驗,例如文件類型,大小,格式,尺寸等。

其中文件類型,可通過設置<input>標簽的accept來指定文件類型。但accept屬性并不能完全禁止用戶上傳指定類型之外的文件。故可以通過上傳文件的各個屬性進行校驗攔截。校驗前,我們需要通過change事件的事件對象來獲取到上傳的文件:

    event.target.files

可以獲取到上傳文件列表。列表中對象包含如下信息:

    {lastModified: 1524153515000lastModifiedDate: Thu Apr 19 2018 23:58:35 GMT+0800 (中國標準時間) {}name: "589adfbfe821c.jpg"size: 1357444type: "image/jpeg"webkitRelativePath: ""}

從該對象中,我們可以獲取到文件大小,文件類型,文件名等信息,從而可以在上傳之前對這些信息進行校驗,從而攔截掉不合法的文件。

然而,從file對象中,我們并不能獲取圖片的尺寸信息。而在我們的業務中,很多場景都需要限制上傳圖片的尺寸為某一個固定值,或者是某一個比例。以減少后期顯示時的適配問題。要實現對上傳圖片尺寸對校驗,我們需要使用到FileReader和Image。

FileReader對象允許Web應用程序異步讀取存儲在用戶計算機上的文件。

Image()函數將會創建一個新的HTMLImageElement實例。它的功能等價于document.createElement('img')

這里,我們需要用到fileReaderreadAsDataURL()方法來讀取上傳文件信息,通過onload處理事件來獲取讀取到的文件信息。如下:

    const reader = new FileReader();reader.readAsDataURL(file);reader.onload = e =&gt; {console.log(e.target.result)}

代碼中,file為我們之前獲取到的文件列表files中的文件對象。e.target.result為讀取到到文件內容。

之后通過new Image()函數創建一個新的HTMLImageElement實例,并將該實例的src賦值為fileReader讀取到到文件內容。即可得到一個該文件的HTMLImageElement實例,通過該實例,我們便可以讀取到該圖片的尺寸信息。具體代碼如下:

    const image = new Image();image.src = e.target.result;image.onload = () =&gt; {console.log(image.width, image.height);}

圖片上傳預覽

在之前的開發中,圖片上傳顯示通常會采用先將文件上傳,預覽圖片直接展示上傳到服務器中到圖片來實現,但這樣無法達到上傳前預覽該圖片的目的,且會造成許多垃圾圖片的上傳。

通過前面對于獲取圖片尺寸研究。相信你能很快想到一種更加優雅的圖片預覽方案,既然我們已經獲取到了該文件的HTMLImageElement實例,那么我們直接將該實例append到頁面的容器Dom中不久行了。或者直接將獲取到的文件設置到已存在的image標簽的src屬性中。圖片上傳預覽就是這么簡單。

圖片上傳與上傳進度展示

圖片的上傳,我們可以直接通過form標簽搭配表單的submit()方法來實現圖片的上傳。然而,這樣我們就無法在上傳前進行上傳文件的校驗與攔截。同時需要用戶主動觸發提交操作。要想讓我們之前做的上傳前的攔截工作不白做,我們需要去在合適的時候,主動觸發文件的上傳操作。

這里,需要使用到FormData對象,來將入參對象數據轉為表單數據。

FormData對象用以將數據編譯成鍵值對,以便用XMLHttpRequest來發送數據。其主要用于發送表單數據,但亦可用于發送帶鍵數據(keyed data),而獨立于表單使用。如果表單enctype屬性設為multipart/form-data ,則會使用表單的submit()方法來發送數據,從而,發送數據具有同樣形式。

首先我們創建一個formData對象,然后通過append() 方法來添加字段。如下:

    const formData = new FormData();formData.append("file", file);

注意,formData雖然為一個對象,但通過console.log卻無法打印出其具體的值,只會得到FormData {}

接下來創建一個XMLHttpRequest對象,用來發送ajax請求。并且通過該XMLHttpRequest對象的upload.onprogress方法,可以實時獲取到上傳信息,并進一步獲取到上傳的進度。具體代碼如下:

    const client = new XMLHttpRequest()client.open("POST", uploadUrl)client.upload.onprogress = function(e) {if (e.lengthComputable) {let total = e.total;let loaded = e.loaded;let percentage = parseFloat(loaded / total).toFixed(2);}}client.send(formData)

上面代碼中,uploadUrl為上傳的URL。通過upload.onprogress的事件對象,可以獲取到當前進度已上傳的文件大小以及完整文件大小,通過這兩個大小參數,可以很容易計算出已上傳文件的比例,之后是顯示上傳進度條、還是展示進度數據,就可以隨意操作了。

拖拽上傳

除了傳統的點擊選擇上傳文件外,拖拽文件上傳也是一個十分常見的場景。要使用拖拽上傳,就需要使用H5的拖放方法dropdrag方法。除了這兩個主要的方法外,還有拖放的不同階段觸發的多個方法,常用的拖拽方法如下:

  • ondragstart 事件:當拖拽元素開始被拖拽的時候觸發的事件(作用對象為被拖曳元素)
  • ondrag:在元素拖動期間不停的觸發該事件,與touchmove事件類似。(作用對象為被拖曳元素)
  • ondragend 事件:當拖拽完成后觸發的事件(作用對象為被拖曳元素)
  • ondragenter 事件:當拖曳元素進入目標元素的時候觸發的事件(作用對象為目標元素)
  • ondragover 事件:拖拽元素在目標元素上移動的時候觸發的事件(作用對象為目標元素)
  • ondragleave 事件:拖拽元素在目標元素上移動的時候觸發的事件(作用對象為目標元素)
  • ondrop 事件:被拖拽的元素在目標元素上同時鼠標放開觸發的事件(作用對象為目標元素)

拖拽的各個事件類似與touch事件的各個階段。然而需要注意的是,拖拽的各個事件,有著自己的作用對象,作用對象分為‘被拖拽元素’和‘目標元素’。被拖拽元素 為拖拽的那個Dom元素,主要使用在頁面內Dom拖拽移動的場景。目標元素為接收被拖拽元素的元素區域。當被拖拽元素進入到該區域,便會觸發目標對象的一系列事件。

在圖片拖拽上傳這個業務場景中,被拖拽元素為頁面外部的圖片文件,故此處僅用到目標元素的各個事件。我們可以通過這些事件來修改目標區域樣式等。核心的兩個事件為ondragoverondrop事件。可能你覺得我只需要在松開鼠標時獲取拖拽的文件就行,因此只需要使用ondrop事件就行了?但是,由于瀏覽器的默認行為,ondrop事件并不會被觸發。因此,需要使用e.preventDefault(); 來阻止掉 ondropover的瀏覽器默認事件,從而保證ondrop事件的觸發。通過ondrop事件的事件對象,我們可以獲取到跟event.target.files相同的文件列表,獲取方法為event.dataTransfer.files;然而,當你這么寫完之后,進行拖拽之后,你會發現瀏覽器自動跳轉到了該圖片的預覽頁。這也是由于瀏覽器的默認行為導致,因此也需要使用e.preventDefault();來阻止掉瀏覽器的默認行為。這樣,便可以進行后續的文件校驗操作來。
具體實現代碼如下:

    &lt;label for="uploadImg"onDragOver={e =&gt; {e.preventDefault();}}onDrop={e =&gt; {if (e.dataTransfer) {e.preventDefault();const file = e.dataTransfer.files[0];...} }}&lt;/label&gt;

至此,圖片上傳的常用知識點以梳理完畢,歡迎補充。

原文地址:https://segmentfault.com/a/1190000016920382

轉載于:https://www.cnblogs.com/lalalagq/p/9921316.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450789.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450789.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450789.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決 java.lang.IllegalArgumentException: Repository interface must not be null on initialization!

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 報錯&#xff1a;Caused by: java.lang.IllegalArgumentException: Repository interface must not be null on initialization! Cause…

【狂神說】JVM

文章目錄1.JVM的位置2.JVM的體系結構3.類加載器4.雙親委派機制&#xff08;重要&#xff09;5.沙箱安全機制(了解)6.native&#xff08;核心&#xff09;7.PC寄存器&#xff08;了解&#xff09;8.方法區9.棧10.三種JVM11.堆&#xff08;Heap&#xff09;12.新生區、老年區13.永…

我們真的需要統一的編程規范?

摘要&#xff1a;仁者見仁智者見智&#xff0c;編碼風格的不同&#xff0c;對項目也會有不同的影響&#xff0c;統一的編碼規范有益于項目的維護。俗話說&#xff0c;沒有規矩不成方圓&#xff0c;在2004年&#xff0c;UNIX創始人之一的Ken Arnold就發表了一篇很幽默文章&#…

百度云重磅發布ABC 3.0 尹世明如何詮釋百度云的“新”打法

雷鋒網9月4日消息&#xff0c;2018百度云智峰會正式召開&#xff0c;百度總裁張亞勤發表題為《新技術驅動&#xff0c;全面進入Cloud2.0》的演講并表示&#xff0c;經歷了PCClient/Server到MobileCloud 1.0&#xff0c;再到如今的AICloud 2.0過程&#xff0c;新技術推動云計算產…

EcmaScript對象克隆之謎

先談談深拷貝 如何在js中獲得一個克隆對象&#xff0c;可以說是喜聞樂見的話題了。相信大家都了解引用類型與基本類型&#xff0c;也都知道有種叫做深拷貝的東西&#xff0c;傳說深拷貝可以獲得一個克隆對象&#xff01;那么像我這樣的萌新自然就去學習了一波&#xff0c;我們能…

開發人員眼中最好的代碼編輯器是誰?

摘要&#xff1a;對開發人員來講&#xff0c;開發工具就好比戰場上的“兵器”&#xff0c;不同領域的開發人員他們所使用的“兵器”也不完全相同&#xff0c;本文從友好性、功能性、擴展等多方面總結了最受開發人員歡迎的“兵器”。你最愛的那個在這里嗎&#xff1f; 如果我們把…

關于RESTful一些注意事項,接口開發規范

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 最近在研究restful&#xff0c;公司開發要使用&#xff0c;所以自己就去網上找了好些資料&#xff0c;并整理了一套公司開發的接口規范。…

【老杜】MySQL—day01

文章目錄day01課堂筆記1、數據庫概述及數據準備1.1、什么是數據庫1.2、什么是數據庫管理系統1.3、SQL概述1.4、安裝MySQL數據庫管理系統。1.4、MySQL數據庫的完美卸載&#xff01;1.5、MySQL的服務1.6、用命令來啟動和關閉mysql服務1.7、登錄mysql數據庫2、MySQL常用命令&#…

【轉載】DRuid 大數據分析之查詢

轉載自http://yangyangmyself.iteye.com/blog/23217591、Druid 查詢概述上一節完成數據導入后&#xff0c;接下來講講Druid如何查詢及統計分析導入的數據。Druid的查詢是使用REST風格的HTTP請求查詢服務節點&#xff08;Broker、Historical、Realtime&#xff09;&#xff0c;這…

記錄 Parameter with that position [1] did not exist; nested exception is java.lang.IllegalArgumentExce

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 報錯如題&#xff1a; Parameter with that position [1] did not exist; nested exception is java.lang.IllegalArgumentException: Pa…

[轉]簡單的動態修改RDLC報表頁邊距和列寬的方法

本文轉自&#xff1a;http://star704983.blog.163.com/blog/static/136661264201161604413204/ 1.修改頁邊距 XmlDocument XMLDoc new XmlDocument();XMLDoc.Load(System.Windows.Forms.Application.StartupPath "\Report_try-2.rdlc");XmlNamespaceManager xmn n…

函數式編程語言天生就慢嗎?

摘要&#xff1a;近期&#xff0c;函數式編程得到了越來越多的關注&#xff0c;Lisp不僅重獲青春還涌現出了一批新函數式編程語言。因此開發者們對函數式編程語言的運行快慢各抒己見&#xff0c;展開激烈討論。本文將和大家一起討論&#xff0c;函數式編程語言真的就慢嗎&#…

【老杜】MySQL—day02

文章目錄day02課堂筆記1、把查詢結果去除重復記錄【distinct】10、連接查詢10.1、什么是連接查詢&#xff1f;10.2、連接查詢的分類&#xff1f;10.3、當兩張表進行連接查詢時&#xff0c;沒有任何條件的限制會發生什么現象&#xff1f;10.4、怎么避免笛卡爾積現象&#xff1f;…

vue根據數組對象中某個唯一標識去重

由于在vue中&#xff0c;會自動在數組和對象中加入_obser__觀察者模式的一些屬性&#xff0c;所以直接用數組的filter去重&#xff08;下面這種&#xff09;&#xff0c;indexOf不能準確識別 var arr [1, 2, 2, 3, 4, 5, 5, 6, 7, 7]; var arr2 arr.filter(function(x, index…

Springsecurity之AuthenticationProvider

2019獨角獸企業重金招聘Python工程師標準>>> 注意&#xff1a;AuthenticationProvider與Authentication緊密聯系&#xff0c;關于Authentication&#xff0c;看我的這篇博客。 先上一張圖&#xff0c;如下圖1 圖1 AuthenticationProvider的類圖 AuthenticationProvi…

Postman使用入門

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Postman測試管理的單位是測試集&#xff08;Collections&#xff09;&#xff0c;測試集內可以創建文件夾(Folder)和具體的請求(Requests…

編程需要知道多少數學知識?

摘要&#xff1a;許多人認為在開始學習編程之前必須對數學很在行或者數學分數很高。但一個人為了編程的話&#xff0c;需要學習多少數學呢&#xff1f; 實際上不需要很多 。這篇文章中我會深入探討編程中所需要的數學知識。 下面是我在reddit的子論壇 r/learnprogramming 看到的…

HDU 6071 Lazy Running

鏈接HDU 6071 Lazy Running 給出四個點1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;1和2&#xff0c;2和3&#xff0c;3和4&#xff0c;4和1之間有路相連&#xff0c;現在從2點出發&#xff0c;最后回到2點&#xff0c;要求路徑大于等于\(K\)&#xff0c;問路徑長度最…

vue彈窗插件實戰

vue做移動端經常碰到彈窗的需求, 這里寫一個功能簡單的vue彈窗 popup.vue <template><div class"popup-wrapper" v-show"visible" click"hide"><div class"popup-text">{{text}}</div></div> </temp…