关于vue3 上传图片到七牛云

引子:
前端程序猿,很少写博客,担心有一些技术很牛逼的大佬看不上,还喜欢怼人,玻璃心容易影响心情,这个是我自己在项目上遇到的,也百度参考了很多大佬的文章,感觉多少有点不全,然后就自己整理一下,当一个笔记,也希望有需要的能直接用,不喜勿喷
参考文章:
https://blog.csdn.net/shishuwei111/article/details/100512646
https://blog.csdn.net/qq827245563/article/details/55207819
七牛云上传地址查询

https://developer.qiniu.com/kodo/1671/region-endpoint-fq

本文基于vue3,element-plus,没用ts,七牛云注册,配置存储一大堆,就不截图细说了,主要是以下一些代码,个人整理的,改改参数,安装依赖后应该可以直接用

tokenTools.js
/* utf.js - UTF-8 <=> UTF-16 convertion
 *
 * Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
 * Version: 1.0
 * LastModified: Dec 25 1999
 * This library is free. You can redistribute it and/or modify it.
 */
/*
 * Interfaces:
 * utf8 = utf16to8(utf16);
 * utf16 = utf8to16(utf8);
 */
import CryptoJS from 'crypto-js'
const dataJSON = {
    utf16to8(str) {
        var out,
            i,
            len,
            c;
        out = "";
        len = str.length;
        for (i = 0; i < len; i++) {
            c = str.charCodeAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) {
                out += str.charAt(i);
            } else if (c > 0x07FF) {
                out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
                out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
                out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
            } else {
                out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
                out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
            }
        }
        return out;
    },
    utf8to16(str) {
        var out,
            i,
            len,
            c;
        var char2,
            char3;
        out = "";
        len = str.length;
        i = 0;
        while (i < len) {
            c = str.charCodeAt(i++);
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    // 0xxxxxxx
                    out += str.charAt(i - 1);
                    break;
                case 12:
                case 13:
                    // 110x xxxx 10xx xxxx
                    char2 = str.charCodeAt(i++);
                    out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                    break;
                case 14:
                    // 1110 xxxx 10xx xxxx 10xx xxxx
                    char2 = str.charCodeAt(i++);
                    char3 = str.charCodeAt(i++);
                    out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
                    break;
            }
        }
        return out;
    },
    // ========================================================
    /*
 * Interfaces:
 * b64 = base64encode(data);
 * data = base64decode(b64);
 */
    base64encode(str) {
        var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
        var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
        var out,
            i,
            len;
        var c1,
            c2,
            c3;
        len = str.length;
        i = 0;
        out = "";
        while (i < len) {
            c1 = str.charCodeAt(i++) & 0xff;
            if (i == len) {
                out += base64EncodeChars.charAt(c1 >> 2);
                out += base64EncodeChars.charAt((c1 & 0x3) << 4);
                out += "==";
                break;
            }
            c2 = str.charCodeAt(i++);
            if (i == len) {
                out += base64EncodeChars.charAt(c1 >> 2);
                out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
                out += base64EncodeChars.charAt((c2 & 0xF) << 2);
                out += "=";
                break;
            }
            c3 = str.charCodeAt(i++);
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
            out += base64EncodeChars.charAt(c3 & 0x3F);
        }
        return out;
    },
    base64decode(str) {
        var c1,
            c2,
            c3,
            c4;
        var i,
            len,
            out;
        len = str.length;
        i = 0;
        out = "";
        while (i < len) { /* c1 */
            do {
                c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
            } while (i < len && c1 == -1);
            if (c1 == -1) 
                break;
            


            /* c2 */
            do {
                c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
            } while (i < len && c2 == -1);
            if (c2 == -1) 
                break;
            


            out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
            /* c3 */
            do {
                c3 = str.charCodeAt(i++) & 0xff;
                if (c3 == 61) 
                    return out;
                


                c3 = base64DecodeChars[c3];
            } while (i < len && c3 == -1);
            if (c3 == -1) 
                break;
            


            out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
            /* c4 */
            do {
                c4 = str.charCodeAt(i++) & 0xff;
                if (c4 == 61) 
                    return out;
                


                c4 = base64DecodeChars[c4];
            } while (i < len && c4 == -1);
            if (c4 == -1) 
                break;
            


            out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
        }
        return out;
    },
    safe64(base64) {
        base64 = base64.replace(/\+/g, "-");
        base64 = base64.replace(/\//g, "_");
        return base64;
    },
    // 我把获取生成token的放这里,然后直接用就行了
    // scope 七牛云文件名,就比如你在广东区域创建的images3z文件夹下的文件
    qiniuToken(AccessKey, SecretKey, scope = 'images3z') {
        let timestamp = new Date().getTime() // 当前的时间戳
        timestamp = parseInt(timestamp / 1000) + 36000
        let putPolicy = {
            'scope': scope, // 七牛云文件名,最好跟着改下
            'deadline': timestamp
        }
        // SETP 2
        let put_policy = JSON.stringify(putPolicy)
        // SETP 3
        let encoded = dataJSON.base64encode(dataJSON.utf16to8(put_policy));
        // SETP 4
        let hash = CryptoJS.HmacSHA1(encoded, SecretKey);
        let encoded_signed = hash.toString(CryptoJS.enc.Base64);
        // SETP 5
        return AccessKey + ":" + dataJSON.safe64(encoded_signed) + ":" + encoded;
    }
}
export default dataJSON
// ================================================
// 使用方法  npm install crypto-js
// 引入 import qiniuJSON from '@/utils/tokenTools'
// 使用 console.log(qiniuJSON.qiniuToken(AccessKey,SecretKey,scope))

 

上传组件封装
我用了vueuse/core实现父子组件的动态绑定  npm i @vueuse/core

上传组件
<template>
  <!-- 上传后显示 -->
  <div class="uploadImage_qiniu">
    <el-upload
      class="upload-pic"
      :action="props.domain"
      :data="props.QiniuData"
      :on-remove="handleRemove"
      list-type="picture-card"
      :on-error="uploadError"
      :on-success="uploadSuccess"
      :before-upload="beforeAvatarUpload"
      :on-preview="handlePictureCardPreview"
      :limit="1"
      :on-exceed="handleExceed"
      :file-list="props.fileList"
    >
      <el-icon><Plus /></el-icon>
    </el-upload>
    <el-dialog v-model="dialogVisible">
      <img
        w-full
        class="uploadPicUrl"
        :src="props.uploadPicUrl"
        alt="Preview Image"
      />
    </el-dialog>
  </div>
</template>
 
<script setup>
import { ref, defineProps, defineEmits, watch } from "vue";
import { Plus } from '@element-plus/icons-vue'
import qiniuJSON from '@/utils/tokenTools'
import { ElMessage } from 'element-plus'
import { useVModel } from '@vueuse/core'
// 初始值
let props = ref({})
props = {
  qiNiu: {
    AccessKey: '',
    SecretKey: ''
  },
  //   headers: { 'Content-Type': 'application/json' },
  QiniuData: {
    name: '/jiancai',
    key: '', // 图片名字处理
    token: '' // 七牛云token
  },
  domain: 'https://upload-z2.qiniup.com', // 七牛云的上传地址(华南区)
  qiniuaddr: 'http://zximg.666.ren', // 七牛云的图片外链地址
  uploadPicUrl: '', // 提交到后台图片地址
  fileList: [], //[{ name: '我试试', url: '' }]
  loading: false
}

// 初始值
const propsValue = defineProps({
  modelValue: String
})
const emit = defineEmits(['update:modelValue'])
let imageUrl = useVModel(propsValue, 'modelValue', emit)
props.fileList = ![undefined, null, ''].includes(propsValue.modelValue) ? [{ name: '', url: imageUrl }] : []

// 获取七牛云token
props.QiniuData.token = qiniuJSON.qiniuToken(props.qiNiu.AccessKey, props.qiNiu.SecretKey,'images3z')
let handleRemove = (file, fileList) => {
  console.log(0)
  props.uploadPicUrl = ''
  props.fileList = []
}
let handleExceed = (files, fileList) => {
  ElMessage.warning(
    `当前仅能选择 1 张图片,请情况重新选择!`
  )
}

let beforeAvatarUpload = (file) => {
  props.uploadPicUrl = ''
  props.fileList = []
  console.log(2)
  const isPNG = file.type === 'image/png'
  const isJPEG = file.type === 'image/jpeg'
  const isJPG = file.type === 'image/jpg'
  const isLt2M = file.size / 1024 / 1024 < 2

  if (!isPNG && !isJPEG && !isJPG) {
    ElMessage.error('上传头像图片只能是 jpg、png、jpeg 格式!')
    return false
  }
  if (!isLt2M) {
    ElMessage.error('上传头像图片大小不能超过 2MB!')
    return false
  }
  props.QiniuData.key = `jiancai/upload_pic_${file.name}`// 根目录文件夹
}
let uploadSuccess = (response, file, fileList) => {
  console.log(3)
  props.uploadPicUrl = `${props.qiniuaddr}/${response.key}`
  props.fileList = [{ name: response.key, url: props.uploadPicUrl }]
}
let uploadError = (err, file, fileList) => {
  console.log(4)
  ElMessage({
    message: '上传出错,请重试!',
    type: 'error',
    center: true
  })
}
// 点击图片放大
let dialogVisible = ref('')
dialogVisible.value = false
const handlePictureCardPreview = () => {
  dialogVisible.value = true
}
</script>
 
 
<style lang="scss">
.uploadImage_qiniu {
  .el-dialog {
    padding-bottom: 20px;
    img {
      width: 95%;
      margin: 20px auto;
    }
  }
}
</style>

使用方法如下
  <wangEditor v-model="form.content"></wangEditor>

  

posted @ 2023-04-12 09:17  好色的菜狗  阅读(97)  评论(0编辑  收藏  举报