關於React中上傳頭像 / 圖片的那點事, 這樣做就對了

項目需求:
React中實現用戶頭像的上傳,可能有人就說了,網上針對頭像上傳的庫簡直不要太多哦,什麼AntDesign、Material等等. 但是爲了一個小小的上傳需求就將一個很大的庫引入到項目中, 是不是有點欠妥.

先上最終實現圖:在這裏插入圖片描述

最開始考慮的是用html原生的 <input type="file" />方式, 但是在嘗試的過程中,發現涉及到各種上傳七牛憑證、圖片過大涉及的裁剪、圖片尺寸的範圍設置等. 決定還是放棄這種原生操作實現方式.

於是開始在網上找有沒有造好的輪子可以用, 找了好幾個,發達不是庫很大就是不合適,最後 同事推薦了一個plupload這個庫, 網上搜了一下,發現對es6的支持也很好, 決定開始嘗試這種上傳方式,而且plupload對圖片的大小限制,裁切都做了處理,真的很方便.

但沒有找到關於在React中上傳頭像/圖片的文章, 索性就自己摸索寫一個大概的用例出來給需要的小夥伴做個參考.


參考來源:
1_官網(更多的需求請到官網看document): https://www.plupload.com/

2_pulpload部分中文文檔: http://www.bubuko.com/infodetail-909829.html

3_參考項目: https://github.com/ProjectForLearnNodejs/qiniu-nodejsSDK-plupload_real_fileup

關於plupload的參數介紹,可以參考上面參考來源的 1、2 兩條, 裏面有一些基本的語法使用介紹.


好,言歸正傳,我們開始嘗試入手:


首先 需要

install plupload: > npm i plupload

安裝完成之後, 就可以在你的項目文件中,進行使用和操作了.

在項目文件中, 需要在文件頭部引入: import plupload from 'plupload'

// 部分示例代碼如下:
constructor(props) {
  super(props)
  this.state = {
    filePhoto: this.props.baby.photo_url || null,
  }
}
// 這裏我在推薦另一種寫法, 如果你不需要在構造函數中 處理其他的數據,只是想初始化用戶數據而已, 那麼可以使用`屬性初始化`方式來簡化你的代碼:
// 如:
state = {
  filePhoto: this.props.baby.photo_url || null,
}

render() {
  return (
    <div id="user-photo">
      // 這裏的id值是必須要的, 否則取不到
      // uploadDefaultPhoto 是用戶沒上傳頭像時 import進來的默認頭像
      <img src={this.state.filePhoto || uploadDefaultPhoto} />
    </div>
  )
}

然後在文件裏寫一個上傳的方法,此處我們就起名叫: initSinglePlupload

initSinglePlupload = () => {
  var uploader = new plupload.Uploader({//創建實例的構造方法
    runtimes : 'html5, flash',//上傳插件初始化選用那種方式的優先級順序
    browse_button: 'user-photo', // 上傳按鈕 引發上傳事件的按鈕的id
    url: "https://upload.qiniup.com",   //遠程上傳地址 後臺地址
    filters : {
      max_file_size : '10mb', //最大上傳文件大小(格式100b, 10kb, 10mb, 1gb)
      mime_types: [
        {title : "JPG/PNG文件", extensions : "jpg,jpeg,JPG,JPEG,png,PNG,gif,GIF"}
      ]
    },
    multi_selection: false,   //true多文件上傳, false 單文件上傳
    multipart_params : { 
      // 需要的token值,這個token我在componentDidMount中對token值做了處理了,所以這裏不需要在帶值過去了
      token: ''
    },
    multipart: true, //爲true時將以multipart/form-data的形式來上傳文件
    resize: {
      width: 1600,
      height: 1600
    },
    init: {
      // 注: FilesAdded方法我放到componentDidMount中做了,然後在componentDidMount中做了init的調用,這麼做是因爲是想要在頁面刷新完之後,點擊上傳圖標就可以很及時的拿到上傳所需要的token值
  // FilesAdded: function (uploader, files) { //文件上傳前
  //   this.toast = ToastManager.showLoading("圖片上傳中...");
  //   uploader.start();
  // },
  FileUploaded: function (up, file, result) { //文件上傳成功的時候觸發
    // 圖片上傳成功之後, 本地不會異步執行state值, 把頭像替換,所以這裏需要reload一遍頁面
    // 然後後端會重新返回頭像鏈接,這時候img中再去取頭像即可

    location.reload() 
    this.toast.cancel()
  },
  Error: function (up, err) { //上傳出錯的時候觸發
    this.toast.cancel() // 隱藏 圖片上傳loading..
  }
}
  });
  return uploader
}

// 頁面初始化全部加載完
   componentDidMount() {
     // 獲取後端返回的token url
     var generate_token_url = this.props.generate_token_url
     
     var uploader = this.initSinglePlupload('')
     uploader.bind('FilesAdded',function(uploader, file) {
       this.toast = ToastManager.showLoading("圖片上傳中...");
       
       // 說明, 下面的`request`是我在axios的基礎上做的一個請求封裝, 如果你沒有封裝, 直接用axios的方式操作也是沒有問題的.
       
       request({
         url: generate_token_url, // 友情提醒: generate_token_url必須要放到 uploader.bind上面去定義.否則拿不到值
         method: "GET",
         params: {
           type: 'baby'
           // 這裏的參數根據 自己項目來判斷傳什麼樣的參數
           // 因爲我當前針對的是寶寶信息頁面的頭像上傳,所以這裏和後端商量之後,傳'baby'給後端
         },
         headers: csrfHeaders // 跨域處理
       }).then(res => {
         // 下面log裏面打印的是從七牛請求鏈接中拿到的token值,這個值必需要,是爲了上傳憑證,給七牛做校驗
         // console.log(res.data.token)
         
         uploader.setOption('multipart_params', {
           token: res.data.token  // 上傳憑證
         })
   
         uploader.start() // 調用實例對象的start()方法開始上傳文件,當然你也可以在其他地方調用該方法
       }).catch(err => {
         Raven.captureException(err)
         this.toast.cancel()
       })
     })
     uploader.init(); //在實例對象上調用init()方法進行初始化
   }

看到這裏, 差不多就結束了, 自己根據network中的返回值和狀態碼來判斷哪裏處理問題,在處理下;

通過以上的方式操作, 基本上就實現了,在React中上傳頭像的操作了;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章