ElementUi+Vue+七牛云如何上传文件和视频

in 前端 with 0 comment

elementUi+vue+七牛云如何上传文件和视频( 支持断点续传)

前提

七牛云上传当然必须保证token的有效,所有我们需要编写后端服务来实现token获取,这里简单展示一下代码

QINIU_SK=A**********0QWp
QINIU_AK=uLP4c******J0BXi5P
QINIU_BUKET_PATH=my-image
QINIU_HOST=http://cdn.surest.cn/
QINIU_UPLOAD_URL=https://upload-z2.qiniup.com
QINIU_PREFIX=webvideo

以上的配置应该很清楚,可以自定义一些自己用的到的参数进去

AK、SK 必须

BUKET 对应着你的空间,就是云存储进去单空间管理里面,

host 对应着你的cdn域名,这里的域名是我解析过后的

QINIU_UPLOAD_URL 对应上传地址

存储区域    区域代码    客户端上传地址    服务端上传地址
华东    ECN    http(s)://upload.qiniup.com    http(s)://up.qiniup.com
华北    NCN    http(s)://upload-z1.qiniup.com    http(s)://up-z1.qiniup.com
华南    SCN    http(s)://upload-z2.qiniup.com    http(s)://up-z2.qiniup.com
北美    NA    http(s)://upload-na0.qiniup.com    http(s)://up-na0.qiniup.com
东南亚         http(s)://upload-as0.qiniup.com    http(s)://up-as0.qiniup.com

代码编写

因为前端可能多个地方调用我们的api,我们可以对他针对性的封装

Route::group(['prefix' => 'upload'], function () {
    Route::get('/qiniu/sign', 'QiniuController@uploadSign'); # 获取七牛云密钥
});


> 安装composer 包
> composer require qiniu/php-sdk -vvv

use Qiniu\Auth;
class QiniuController extends Controller
{
    /**
     * 获取七牛云密钥
     * User: surest
     * Date: 2020/6/1
     */
    public function uploadSign()
    {
        // 用于签名的公钥和私钥
        $accessKey = env('QINIU_AK');
        $secretKey = env('QINIU_SK');
        $auth = new Auth($accessKey, $secretKey);
        $token = $auth->uploadToken(env('QINIU_BUKET_PATH'));
        $host = env('QINIU_HOST');
        $buket = env('QINIU_BUKET_PATH');
        $uploadUrl = env('QINIU_UPLOAD_URL');

        return $this->success(compact('token', 'host', 'buket', 'uploadUrl'));
    }
}

单文件上传

这里针对前端组件进行封装

> 创建一个vue mixin
> mkdir -p ./src/layout/mixin/UploadHandler.js

// 这里是封装的一个请求后端方法
import { getToken } from "@/api/qiniu";

export default {
    data(){
        return {
            qiniuToken: null,
            host: null,
            buket: null, 
            uploadUrl: null
        }
    },
    methods: {
        getToken(){
            // 这里返回一个 Promise
            return new Promise((resolve, reject) => {
                getToken().then(response => {
                    this.qiniuToken = response.data.token
                    this.host = response.data.host
                    this.buket = response.data.buket
                    this.uploadUrl = response.data.uploadUrl
                    console.log(response.data)
                    resolve()
                })
            })
        }
    }
};

使用


<template>
    <el-upload
        style="float:left"
        :action="importApi"
        :on-success="uploadDocSuccess"
        :on-error="uploadError"
        :data="postData"
        :show-file-list="false"
    >
    <el-button size="mini" type="success">培训文档上传</el-button>
    </el-upload>
</template>


> 导入
import UploadMixin from '@/layout/mixin/UploadHandler'

export default {
    ...
    mixins: [UploadMixin],
    data(){
        return {
            postData: {
                token: null
            },
            importApi: null
            ....
        }
    },
    methods: {
        ....
        /**
         * 合同导入成功
         */
        uploadSuccess(response) {
          this.excelLoading = false;
          Message.success("导入成功");
          Message.success(this.host + response.key) // 输出的就是文件地址
        },
    
        uploadError(err) {
          let msg = JSON.parse(err.message);
          console.log(msg)
          msg = msg.message;
          Message.error("导入失败: " + msg);
          this.excelLoading = false;
        },
        
        /**
         * 初始化导入七牛云参数
         */
        initImport() {
          this.getToken().then(() => {
              this.importApi = this.uploadUrl
              this.postData.token = this.qiniuToken
            })
        },
        ...
    }
}

视频上传

直接贴代码

<template>
  <div class="upload">
    <div id="video_container">
      <div id="pickfiles"><el-button style="margin-top: 5px" type="primary">上传视频</el-button></div>
      <div>
        <div class="upload_info">
          <b>共{{ fileSize }}MB | 已上传{{ fileLoaded }} | 上传速度{{ fileSpeed }}/s</b>
        </div>
        <div>
          <b>上传进度:{{ filePercent }}%</b>
        </div>
      </div>
    </div>
    <div class="cover-pic" v-if='coverPic'>
      <img :src="coverPic" alt="">
    </div>
  </div>
</template>


<script>
import { getToken, chttp } from '@/api/qiniu'
require('qiniu-js/dist/qiniu.min.js')
import * as qiniu from 'qiniu-js'
export default {
  data () {
    return {
      fileSize: 0,
      fileLoaded: 0,
      fileSpeed: 0,
      filePercent: 0,
      uploader: null,
      token: '',
      filename: '',
      hash: '',
      resFileName: '',
      coverPic: '',
      phoneType: null,
      domain: undefined,
      buket: undefined
    }
  },
  methods: {
    pauseUpload () {
      this.uploader.stop()
    },
    continueUpload () {
      this.uploader.start()
    },
    toDecimal (size) {
      size = size / 1024 / 1024
      var f = parseFloat(size)
      if (isNaN(f)) {
        return
      }
      f = Math.round(size * 10) / 10
      var s = f.toString()
      var rs = s.indexOf('.')
      if (rs < 0) {
        rs = s.length
        s += '.'
      }
      while (s.length <= rs + 1) {
        s += '0'
      }
      return s
    },
    init() {
        this.data = this.$data
    },
    initUploader () {
      let plupload = window.plupload
      let _this = this
      // domain为七牛空间对应的域名,选择某个空间后,可通过 空间设置->基本设置->域名设置 查看获取
      let isIphone5 = this.phoneType === '5'
      // uploader为一个plupload对象,继承了所有plupload的方法
      this.uploader = Qiniu.uploader({
        runtimes: 'html5,flash,html4', // 上传模式,依次退化
        browse_button: 'pickfiles', // 上传选择的点选按钮,必需
        uptoken: _this.token, // uptoken是上传凭证,由其他程序生成
        get_new_uptoken: true, // 设置上传文件的时候是否每次都重新获取新的uptoken
        bucket_name: _this.buket, // 空间名
        unique_names: false, // 默认false,key为文件名。若开启该选项,JS-SDK会为每个文件自动生成key(文件名)
        save_key: false, // 默认false。若在服务端生成uptoken的上传策略中指定了sava_key,则开启,SDK在前端将不对key进行任何处理
        domain: _this.domain, // bucket domain eg:http://qiniu-plupload.qiniudn.com/
        container: 'video_container', // 上传区域DOM ID,默认是browser_button的父元素
        max_file_size: '10mb', // 最大文件体积限制
        dragdrop: false, // 开启可拖曳上传
        drop_element: 'video_container', // 拖曳上传区域元素的ID,拖曳文件或文件夹后可触发上传
        chunk_size: '4mb', // 分块上传时,每块的体积
        max_retries: 3, // 上传失败最大重试次数
        auto_start: true, // 选择文件后自动上传,若关闭需要自己绑定事件触发上传
        multi_selection: !isIphone5,
        init: {
          Key: function (up, files) {
            return _this.filename
          },
          FilesAdded: function (up, files) {
            plupload.each(files, function (file) {
              // 文件添加进队列后,处理相关的事情
              console.log('FilesAdded')
              _this.fileSize = _this.toDecimal(file.size)
            })
          },
          BeforeUpload: function (up, file) {
            console.log('BeforeUpload')
          },
          ChunkUploaded: function (up, file, info) {
            console.log('ChunkUploaded')
          },
          UploadProgress: function (up, file) {
            // 每个文件上传时,处理相关的事情
            _this.filePercent = parseInt(file.percent)
            _this.fileLoaded = plupload.formatSize(file.loaded).toUpperCase()
            _this.fileSpeed = plupload.formatSize(file.speed).toUpperCase()
          },
          FileUploaded: function (up, file, info) {
            console.log('FileUploaded')
            let response = JSON.parse(info.response)
            console.log(response)
            let coverPic = _this.domain + response.key
            _this.$emit('toHtml', coverPic)
            console.log(response, coverPic)
          },
          Error: function (up, err, errTip) {
            // 上传出错时,处理相关的事情
            console.log(arguments)
          },
          UploadComplete: function () {
            // 队列文件处理完毕后,处理相关的事情
            console.log(arguments)
          }
        }
      })
      console.log(this.uploader)
    },
    getToken (callback) {
      getToken().then(res => {
          this.token = res.data.token
          this.domain = res.data.host
          this.buket = res.data.buket
          console.log(res.data)
          callback()
        })
    },
    getPhoneType () {
      // 正则,忽略大小写
      var patternPhone = new RegExp('iphone', 'i')
      var patternAndroid = new RegExp('Android', 'i')
      var userAgent = navigator.userAgent.toLowerCase()
      var isAndroid = patternAndroid.test(userAgent)
      var isIphone = patternPhone.test(userAgent)
      var phoneType = 'phoneType'
      if (isAndroid) {
        var zhCnIndex = userAgent.indexOf('-')
        var spaceIndex = userAgent.indexOf('build', zhCnIndex + 4)
        var fullResult = userAgent.substring(zhCnIndex, spaceIndex)
        phoneType = fullResult.split('')[1]
      } else if (isIphone) {
        // 6   w=375    6plus w=414   5s w=320     5 w=320
        var wigth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
        if (wigth > 400) {
          phoneType = 'iphone6 plus'
        } else if (wigth > 370) {
          phoneType = 'iphone6'
        } else if (wigth > 315) {
          phoneType = '5'
        } else {
          phoneType = 'iphone 4s'
        }
      } else {
        phoneType = '您的设备太先进了'
      }
      return phoneType
    },
    uploadFile() {

    }
  },
  mounted () {
    this.phoneType = this.getPhoneType()
    this.filename = 'webvideo/' + new Date().getTime() + '.mp4'
    // this.initUploader()
    this.getToken(() => {
        console.log(this)
      this.initUploader()
    })
  },
}
</script>


<style lang="scss" scoped>
</style>

使用

import QiniuUpload from "@/components/Upload/Qiniu"

export default {
  ...
  components: { QiniuUpload }
 }
Comments are closed.