基於業務場景下的圖片/檔案上傳方案總結

千鋒Python唐小強發表於2020-10-26

圖片/檔案上傳 組是企業專案開發中必不可少的環節之一, 但凡涉及到使用者模組的都會有 圖片/檔案 需求, 在很多第三方元件庫( ant desigin element ui )中它也是基礎元件之一. 接下來筆者就來帶大家 從零實現一款圖片/檔案上傳元件以及擴充套件出更強大的上傳元件 .

你將收穫

  • 常用的圖片上傳功能實現方案
  • 手寫一個圖片/檔案上傳元件
  • 如何將 裁剪功能 整合到上傳元件中
  • 內容平臺/視覺化平臺下的圖片 自治 方案
  • 如何擴充套件出更強大的圖片上傳方案

正文

作為一名 前端工程師 , 解決專案問題是我們的基本職責之一, 我們可以利用已掌握的知識去解決專案開發中的問題和需求, 這也是我們職業生涯必將經歷的第一個階段,即—— 適應期 . 如果我們想繼續晉升, 我們就需要 不斷的打怪升級,掌握各種技能 , 這樣我們才能在未來遇到問題時採用最佳的方案高效的解決問題, 也就是第二個階段—— 發展期 .

為了更快的進入發展期, 我們需要不斷的提升自己的技術深度和廣度, 能縱向考慮到問題的本質也能橫向的對問題提出多種解決方案, 最終選擇一種最優方案來實現. 要實現這一點,我們需要對問題做深度思考和覆盤, 接下來筆者將介紹幾種常用的圖片上傳方案,來擴充套件大家的廣度.

1. 常用的圖片上傳方案

web1.0 時代開始, 我們用的最多的上傳方案就是 form表單 , 我們只需要在 form 內寫好各種 input (輸入型元素), 並定義好上傳的伺服器地址( action )即可.形式類似如下:

    <div class="form-item"></div>
    <div class="form-item"></div>
    <div class="form-item"></div>
    <div class="form-item"></div>

XHR 技術還沒普及時, 我們大多會選擇上述方案, 唯一的缺點就是 提交之後會重新整理頁面 , 使用者體驗不太好, 還可能造成區域性資料丟失, 但仍然有解決方案, 就是 form + iframe 技術.

1.1 form + iframe方案

form + iframe 方案的基本思路就是我們提交動作是在父頁面觸發, 但是 form 表單指向為 iframe , 這樣可以實現區域性重新整理, 現在有些場景仍然在使用該方案, 具體原理如下:

基於業務場景下的圖片/檔案上傳方案總結


以上兩種方案都可以實現傳統
form 提交下的區域性重新整理功能, 不過方案一需要單獨維護 iframe表單 , 所以我呢一般採用方案二, 而且相容性都可以達到 IE9 (雖然現在來說相容IE瀏覽器意義不大, 但是還是要了解一下)

1.2 ajax + formData方案

XHR 盛行之後,我們可以輕鬆使用 ajax 來實現非同步請求了, 對於檔案上傳, 我們也可以更靈活的使用 ajax formData 來實現, 逐漸脫離了對 原生form表單 的依賴.
FormData  物件用以將資料編譯成鍵值對,以便用XMLHttpRequest來傳送資料。其主要用於傳送表單資料,但亦可用於傳送帶鍵資料(keyed data),而獨立於表單使用。如果表單enctype屬性設為multipart/form-data ,則會使用表單的submit()方法來傳送資料,從而,傳送資料具有同樣形式。

我們先來看一個簡單的使用formData上傳檔案的例子:

let formData = new FormData();// HTML 檔案型別input,由使用者選擇formData.append("userfile", fileInputElement.files[0]);let request = new XMLHttpRequest();
request.open("POST", ");
request.send(formData);

以上短短5行程式碼就實現了將檔案透過 formData 的方式上傳給了伺服器, 是不是很簡單呢? 筆者之前的文章  基於react/vue開發一個專屬於程式設計師的朋友圈應用 就採用了該方案, 感興趣的可以學習研究一下.

如果要實現多檔案上傳也非常簡單, 這裡我們以 axios 為例, 具體實現如下:

const formData = new FormData()for(let i=0; i< files.length; i++) {
  formData.append(`file_${i+1}`, files[i].file)
}
axios({  method: 'post',  url: '/files/upload/tx',  data: formData,  headers: {      'Content-Type': 'multipart/form-data'
  }
});

這裡要注意多檔案上傳要在請求的 http header 中設定  Content-Type  為  multipart/form-data  . 當然大家還可以基於以上原理實現更符合自身業務需求的檔案上傳元件, 比如預覽, 限流等.

1.3 第三方元件實現

為了更高效快速的開發業務, 我們有時候也可以選擇第三方比較成熟的方案, 比如antd的upload元件, 比如element ui的上傳元件, 這裡筆者總結了幾個比較好用且強大的方案, 大家可以感受一下:

  • antd/element  的  upload  元件
  • FilePond  可以上傳任何內容,並能夠最佳化影像以加快上傳速度,同時提供順暢的使用者體驗
  • Web Uploader  百度WebFE(FEX)團隊開發的一個簡單的以 HTML5 為主, FLASH 為輔的現代檔案上傳元件
  • vue-simple-uploader  基於 vue 的強大美觀的檔案上傳元件

我們可以透過上述提供的第三方元件庫, 結合自己服務端的配置,就可以輕鬆實現強大的上傳元件了.

2. 將裁剪功能整合到圖片上傳元件

對於圖片上傳元件來說, 我們往往不能確定使用者上傳的到底是什麼, 所以我們要提前約束, 比如說對圖片大小, 圖片格式, 圖片比例等進行限制以符合我們的業務標準. 圖片大小和圖片格式的限制非常好實現, 但是對於圖片比例, 這個我們不能期望使用者自己來處理, 因為這樣會極大的增加使用者使用網站的負擔, 所以我們可以提供一種功能, 讓使用者 線上切圖 . 如下圖所示:

基於業務場景下的圖片/檔案上傳方案總結


以上截圖來自於
H5-Dooring 線上編輯器的圖片上傳元件, 在使用者上傳之後我們會出現圖片裁切介面, 我們會指定圖片的比例, 讓使用者自由裁切.
筆者將基於
antd upload 元件配合 antd-img-crop 來帶大家實現線上切圖功能. 具體程式碼實現如下:

import React, { useState } from 'react';import { Upload } from 'antd';import ImgCrop from 'antd-img-crop';const Demo = () => {  const [fileList, setFileList] = useState([
    {      uid: '-1',      name: 'image.png',      status: 'done',      url: '
    },
  ]);  const onChange = ({ fileList: newFileList }) => {
    setFileList(newFileList);
  };  const onPreview = async file => {    let src = file.url;    if (!src) {
      src = await new Promise(resolve => {        const reader = new FileReader();
        reader.readAsDataURL(file.originFileObj);
        reader.onload = () => resolve(reader.result);
      });
    }    const image = new Image();
    image.src = src;    const imgWindow = window.open(src);
    imgWindow.document.write(image.outerHTML);
  };  return (
    
        {fileList.length < 5 && '+ Upload'}
      
  );
};
ReactDOM.render(, mountNode);

以上只是一個基本的裁切並上傳圖片的例子, 當然 antd-img-crop 還提供了更多靈活的配置來方便我們設計更靈活強大的裁切效果. 當然我們還可以使用 react-cropper 來實現, 它提供了更靈活的裁切控制以及裁切實時預覽功能, 如下圖所示:

基於業務場景下的圖片/檔案上傳方案總結

3. 內容平臺/視覺化平臺下的圖片自治

對於內容平臺或者視覺化平臺 而且 , 單純的上傳圖片還不能滿足使用者的需求, 因為內容/視覺化平臺更加註重圖片的選擇和使用, 對圖片要求也很高, 使用者自己上傳畢竟資源有限, 往往不能達到使用者對內容釋出的需求或者視覺化設計的需求, 所以往往在這類平臺中會提供 圖片素材庫 這一功能, 使用者可以在素材庫中搜尋海量圖片以滿足自己的需求, 而往往這樣, 才更能留住使用者, 增加使用者粘性.

基於以上場景產品經理往往會提出這樣的需求:  能不能提供可選方案, 使用者既能自己上傳圖片, 也能使用我們提供的圖片庫資源呢?  這個時候 有經驗 的前端往往會說一句:  安排!

在設計該功能之前我們往往要先參考其他已有實現, 這裡我們舉幾個例子, 如下圖所示:

基於業務場景下的圖片/檔案上傳方案總結


基於業務場景下的圖片/檔案上傳方案總結


基於業務場景下的圖片/檔案上傳方案總結

以上案例中我們可以發現在使用者上傳圖片的時候都會提供兩個可選選項, 一個是本地上傳, 一個是直接在圖片庫中選擇, 所以我們的方案也類似, 可以統一將圖片庫封裝到檔案上傳元件中作為通用功能, 也可以組合式封裝, 各自可以獨立使用也可以組合使用.

對於 H5-Dooring 對圖片庫的封裝, 使用了將其作為通用服務來實現, 也就是但凡使用了上傳元件,一定會出現可選的 從圖片庫選擇 按鈕. 實現方案也很簡單, 就是在 upload 元件中擴充套件一層, 使用 Modal+Tab 來做圖片選擇的介面, 當選擇完成後將圖片的地址手動設定到 upload 元件中即可. 程式碼如下:

handleImgSelected= () => {  const fileList = [
    {
      uid: uuid(8, 16),
      name: 'h5-dooring圖片庫',
      status: 'done',
      url: this.state.curSelectedImg,
    },
  ];  this.props.onChange && this.props.onChange(fileList);  this.setState({ fileList, wallModalVisible: false });
};

這裡用了 antd form元件 的受控模式.

4. 圖片上傳元件擴充套件

上面介紹的方案對於基本使用場景完全夠用了, 但是如果是內容網站或者視覺化搭建平臺, 由於我們的配置可能會隨時分發到公網, 這就會涉及到內容安全的問題, 如果一旦使用者配置了違法的圖片資訊, 那麼對於平臺提供上可能會受到牽連, 所以我們還需要提供一套完善的稽核機制, 比如使用者配置好或者釋出好內容後, 需要 進過 稽核才能正式釋出到線上, 但是完全依賴人工稽核效率又比較低, 所以這個時候我們就需求找到機器自動化稽核方案了. 比如阿里雲和騰訊雲等都提供了圖片鑑別等服務, 我們可以將這些服務整合到我們的元件中, 來實現真正的業務自治能力, 這樣才能更安全的進行企業化經營和開發.

還有一個需求就是使用者對於上傳的圖片有編輯需求, 我們還可以提供對圖片的線上編輯功能, 類似於如下方案:

基於業務場景下的圖片/檔案上傳方案總結


我們能讓使用者有能力對自己選擇的圖片進行自行設計, 加水印等能力, 這樣是不是更有意思呢?

5. 總結

以上教程筆者已經整合到 H5-Dooring 中,對於一些更復雜的互動功能,透過合理的設計也是可以實現的,大家可以自行探索研究。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69923331/viewspace-2729654/,如需轉載,請註明出處,否則將追究法律責任。

相關文章