Vue的移動端多圖上傳外掛程式vue-easy-uploader

來源:互聯網
上載者:User

標籤:tip   理解   直接   raw   files   java   main   ble   mod   

原文地址

前言

這段時間趕項目,需要用到多檔案上傳,用Vue進行前端項目開發。在網上找了不少外掛程式,都不是十分滿意,有的使用起來繁瑣,有的不能適應本項目。就打算自己折騰一下,寫一個Vue的上傳外掛程式,一勞永逸,以後可以直接使用。

目前vue-easy-uploader已上傳到GitHubNPM,使用起來方便簡單,不需要繁瑣的配置即可投入生產,不過需要後端配合,實現上傳介面。

本項目GitHub地址: https://github.com/quanzaiyu/vue-easy-uploader

本項目NPM地址: https://www.npmjs.com/package/vue-easy-uploader

詳細的使用方法都在倉庫Readme中,就不贅述,這裡談下本外掛程式的設計開發思路。

外掛程式介紹

vue-easy-uploader是一個多圖上傳外掛程式。主要特性包括:

  • 多檔案上傳
  • 上傳圖片預覽
  • 上傳狀態監測
  • 刪除指定圖片
  • 清空圖片
  • 重新上傳

後期版本迭代將不限於圖片,往通用檔案上傳進行改進。

先看看上傳外掛程式使用時候的:

目錄結構

index.js # 主入口檔案store.js # 狀態管理uploader.vue # 上傳組件
檔案解析index.js
import uploader from ‘./uploader‘import store from ‘./store‘let plugin = {}plugin.install = function (_Vue, _store) {  _Vue.component(‘uploader‘, uploader)  _store.registerModule(‘imgstore‘, store)}export default plugin

這是外掛程式的主入口檔案,註冊了全域的上傳組件和狀態管理,使用時只需要在項目入口檔案(一般是main.js)中加入以下代碼即可引入此外掛程式:

import Vue from ‘vue‘import Vuex from ‘vuex‘import uploader from ‘vue-easy-uploader‘ let store = new Vuex.Store({})Vue.use(uploader, store)
store.js

此檔案為狀態管理設定檔,主要包含三個state:

img_upload_cache # 上傳檔案快取img_paths # 上傳狀態,包括 ready selected uploading finishedimg_status # 上傳後的路徑反饋數組(資料結構為Set集合)

針對每個state都有自己的mutation,用於改變state,規範上mutation都需要使用大寫字母加底線的形式,本人習慣使用小寫字母,不過都不是原則上的問題。

最重要的一個stateimg_status,用於監視圖片上傳的狀態。包括以下幾個狀態:

ready # 上傳開始前的準備狀態 selected # 已選擇上傳檔案 uploading # 開始上傳 finished # 上傳完畢 

在組件中可以通過改變上傳狀態實現檔案的上傳,同時也可以監聽上傳狀態的變化而執行回調。如:

methods: {  upload () {    this.$store.commit(‘set_img_status‘, ‘uploading‘)  },  submit () {    // some code  }}computed: {  ...mapState({    imgStatus: state => state.imgstore.img_status  })},watch: {  imgStatus () {    if (this.imgStatus === ‘finished‘) {      this.submit()    }  }}

上述代碼中,使用upload方法更新了上傳狀態,讓圖片開始執行上傳操作,使用watch進行上傳狀態的監視,當上傳完成(img_status狀態變為finished),執行回呼函數submit

源檔案如下:

// Created by quanzaiyu on 2017/10/25 0025.var state = {  img_upload_cache: [],  img_paths: [],  img_status: ‘ready‘ // 上傳狀態 ready selected uploading finished}const actions = {}const getters = {}const mutations = {  set_img_upload_cache (state, arg) {    state.img_upload_cache = arg  },  set_img_paths (state, arg) {    state.img_paths = arg  },  set_img_status (state, arg) {    state.img_status = arg  }}export default {  state,  mutations,  actions,  getters}
uploader.vue

先看原始碼(為了節省空間的,未貼出style部分的代碼):

<template>  <div class="imgUploader">    <div class="file-list">      <section        v-for="(file, index) in imgStore" :key="index"        class="file-item draggable-item"      >        <img :src="file.src"  ondragstart="return false;">        <span class="file-remove" @click="remove(index)">+</span>      </section>      <section class="file-item" v-if="imgStatus !== ‘finished‘">        <div class="add">          <span>+</span>          <input type="file" pictype=‘30010003‘ multiple            data-role="none" accept="image/*"            @change="selectImgs"            ref="file"          >        </div>      </section>    </div>    <div class="uploadBtn">      <section>        <span v-if="imgStore.length > 0" class="empty"          @click="empty">            {{imgStatus === ‘finished‘ ? ‘重新上傳‘ : ‘清空‘}}        </span>      </section>    </div>  </div></template><script>import { mapState } from ‘vuex‘export default {  props: [‘url‘],  data () {    return {      files: [], // 檔案快取      index: 0 // 序號    }  },  computed: {    ...mapState({      imgStore: state => state.imgstore.img_upload_cache,      imgPaths: state => state.imgstore.img_paths,      imgStatus: state => state.imgstore.img_status    })  },  methods: {    // 選擇圖片    selectImgs () { # ①      let fileList = this.$refs.file.files      for (let i = 0; i < fileList.length; i++) {        // 檔案過濾        if (fileList[i].name.match(/.jpg|.gif|.png|.bmp/i)) {           let item = {            key: this.index++,            name: fileList[i].name,            size: fileList[i].size,            file: fileList[i]          }          // 將圖片檔案轉成BASE64格式          let reader = new FileReader()  # ②          reader.onload = (e) => {            this.$set(item, ‘src‘, e.target.result)          }          reader.readAsDataURL(fileList[i])          this.files.push(item)          this.$store.commit(‘set_img_upload_cache‘, this.files) // 隱藏檔緩衝          this.$store.commit(‘set_img_status‘, ‘selected‘) // 更新檔案上傳狀態        }      }    },    // 上傳圖片    submit () {      let formData = new FormData() # ③      this.imgStore.forEach((item, index) => {        item.name = ‘imgFiles[‘ + index + ‘]‘ # ④        formData.append(item.name, item.file)      })      formData.forEach((v, k) => console.log(k, ‘ => ‘, v))      // 建立請求      const xhr = new XMLHttpRequest()  # ⑤      xhr.open(‘POST‘, this.url, true)      xhr.send(formData)      xhr.onload = () => {        if (xhr.status === 200 || xhr.status === 304) {          let datas = JSON.parse(xhr.responseText)          console.log(‘response: ‘, datas)          // 儲存返回的地址          let imgUrlPaths = new Set()   # ⑥          datas.forEach(e => { // error === 0為成功狀態            e.error === 0 && imgUrlPaths.add(e.url)          })          this.$store.commit(‘set_img_paths‘, imgUrlPaths) // 儲存返回的地址          this.files = [] // 清空檔案快取          this.index = 0 // 初始化序號          this.$store.commit(‘set_img_status‘, ‘finished‘) // 更新檔案上傳狀態        } else {          alert(`${xhr.status} 請求錯誤!`)        }      }    },    // 移除圖片    remove (index) {      this.files.splice(index, 1)      this.$store.commit(‘set_img_upload_cache‘, this.files) // 更新隱藏檔緩衝    },    // 清空圖片    empty () {      this.files.splice(0, this.files.length)      this.$store.commit(‘set_img_upload_cache‘, this.files) // 更新隱藏檔緩衝      this.$store.commit(‘set_img_paths‘, [])    }  },  beforeCreate () {    this.$store.commit(‘set_img_status‘, ‘ready‘) // 更新檔案上傳狀態  },  destroyed () {    this.$store.commit(‘set_img_upload_cache‘, [])    this.$store.commit(‘set_img_paths‘, [])  },  watch: {    imgStatus () {      if (this.imgStatus === ‘uploading‘) {        this.submit()   # ⑦      }    },    imgStore () {      if (this.imgStore.length <= 0) {        this.$store.commit(‘set_img_status‘, ‘ready‘) // 更新檔案上傳狀態      }    }  }}</script><style lang="less" scoped>...</style>

以上代碼中有一些注釋序號,是此外掛程式設計的主要思路,其他代碼都比較容易理解,分別說下

  • ① 選擇檔案後執行,img_status狀態變為selected
  • ② 將帶上傳的圖片檔案轉化為Base64格式,用於縮圖顯示。
  • ③ 建立一個表單對象,用於儲存待上傳的檔案。
  • ④ 注意這裡的name屬性值,暫時寫死,後面設計打算從組件中指定name屬性,如果是多檔案的話,name屬性的數組序號從0開始遞增。
  • ⑤ 未依賴任何Ajax請求外掛程式,使用原生的XMLHttpRequest對象建立請求。
  • ⑥ 儲存上傳成功後伺服器返回的上傳路徑。
  • ⑦ 檢測上傳狀態,當在使用此外掛程式時將img_status的狀態設定為uploading時執行上傳操作。
使用

參考本項目的GItHub和NPM。

注意

使用此外掛程式時,需要與後端約定返回的資料格式,如下:

[{"error":0,"url":"\/uploads\/api\/201711\/25\/fde412bd83d3ec5d6a49769bd0c143cd.jpg"},{"error":0,"url":"\/uploads\/api\/201711\/25\/c6fd51f0388c63a0b6d350331c945fb1.jpg"}]

預覽如下:

返回的是一個上傳後的路徑數組,包括errorurl欄位,每個檔案有自己的上傳狀態,當error為0的時候為上傳成功,並返回上傳後的路徑url

改進

後續版本打算進行如下改進

  1. 把表單的name屬性名稱通過組件傳遞。
  2. 自訂上傳成功後伺服器響應的資料格式,比如自訂error的名稱和其值所表示的狀態。
  3. 支援其他類型檔案的上傳,可以在組件中自行制定上傳的檔案類型,及其預覽方式。

Vue的移動端多圖上傳外掛程式vue-easy-uploader

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.