vue 封装 上传图片(有截图功能)并将图片上传到阿里云

vue

第一:需要安装依赖包

封装上传图片

<template>

<div id="demo">

<!-- 遮罩层 -->

<div class="father" v-show="panel">

<div class="container">

<div id="cropper" style="margin-top:1%;margin-left: 1%;margin-right: 1%;height: 82%;margin-bottom: 1%">

<img :id="params.cropperId" class="images" :src="url" alt="Picture">

</div>

<div>

<div style="float: right;margin-right: 1%">

<el-button icon="el-icon-zoom-out" @click="zoom(-1)" size="mini" circle></el-button>

<el-button icon="el-icon-zoom-in" @click="zoom(1)" size="mini" circle></el-button>

<el-button icon="el-icon-refresh" @click="rotate" size="mini" circle></el-button>

<el-button type="success" icon="el-icon-check" @click="crop" size="mini" circle></el-button>

<el-button type="danger" icon="el-icon-close" @click="panel=false" size="mini" circle></el-button>

</div>

</div>

</div>

</div>

<div >

<div >

<input type="file" :id="params.id" accept="image" @change="change" style="display:none;">

<div v-if="!params.slotFlag" class="show" v-on:mouseover="addClassload" v-on:mouseout="removeClassload" @click="upload" :style="'backgroundImage:url(../assets/mao.jpg);border: 1px dashed '+color">

<i class="el-icon-plus i" :style="'color: '+color"></i>

</div>

<div v-else @click="upload">

<slot name="uploadBtn"></slot>

</div>

</div>

</div>

</div>

</template>

<script>

// import {test} from '@/api/psych'

// import { uploadImg } from '@/api/common'

import Cropper from 'cropperjs'

export default {

components: {

},

props:{

params:{

id:'change',

cropperId:"croppers",

slotFlag:false,//显示自定义按钮

name:'uploadImg'

}

},

data () {

return {

headerImage: '',

picValue:'',

cropper:'',

croppable:false,

panel:false,

url:'',

color:"#d9d9d9",

current:0,

}

},

mounted () {

//初始化这个裁剪框

var self = this;

let id = this.params.cropperId || 'cropper'+Math.random()

var image = document.getElementById(id);

this.cropper = new Cropper(image, {

aspectRatio: NaN, //Number,croper box的宽高比,可以为裁剪设置固定的宽高比,值为NaN时,可自由裁剪。可以使用Shift键来切换或者固定宽高比。

viewMode: 1, //Number,默认值0,可选值0,1,2,3 mode为0的情况下,crop box部分可以超出canvans的范围,mode为1,2,3时crop box被限制在canvas范围之内,mode为2,3时会将canvas限制在container之内。

zoomOnWheel:false,//是否允许通过鼠标滚轮来缩放图片

background:true,//是否在容器上显示网格背景

rotatable:true,//是否允许旋转图片

ready: function () {

self.croppable = true;

}

});

// console.log(133)

// console.log(this.params.logo)

this.headerImage = this.params.logo

},

methods: {

addClassload(){

this.color="#1b95e0"

},

removeClassload(){

this.color="#d9d9d9"

},

//点击按钮自动执行选择文件事件

upload(){

this.url='',

this.current=0;

let id = this.params.id

document.getElementById(id).value=null;

document.getElementById(id).click();

},

//旋转

rotate(){

//alert(this.cropper.image)

this.current = (this.current+90)%360;

this.cropper.rotate(this.current);

},

//缩放

zoom(num){

num = num || 1;

this.cropper.zoom(num);

},

getObjectURL (file) {

var url = null ;

if (window.createObjectURL!=undefined) { // basic

url = window.createObjectURL(file) ;

} else if (window.URL!=undefined) { // mozilla(firefox)

url = window.URL.createObjectURL(file) ;

} else if (window.webkitURL!=undefined) { // webkit or chrome

url = window.webkitURL.createObjectURL(file) ;

}

// console.log(file)

return url ;

},

change (e) {

let files = e.target.files || e.dataTransfer.files;

if (!files.length) return;

this.panel = true;

this.picValue = files[0];

this.url = this.getObjectURL(this.picValue);

//每次替换图片要重新得到新的url

if(this.cropper){

this.cropper.replace(this.url);

}

// console.log(files)

this.panel = true;

},

crop () {

this.panel = false;

var croppedCanvas;

var roundedCanvas;

if (!this.croppable) {

return;

}

// Crop

croppedCanvas = this.cropper.getCroppedCanvas();

// console.log(this.cropper)

// Round

/*截取圆形

roundedCanvas = this.getRoundedCanvas(croppedCanvas);

this.headerImage = roundedCanvas.toDataURL();

*/

//方形

this.headerImage = croppedCanvas.toDataURL();

var gettype=Object.prototype.toString

this.postImg()

},

dataURLtoFile (dataurl, filename = 'file') {

let arr = dataurl.split(',')

let mime = arr[0].match(/:(.*?);/)[1]

let suffix = mime.split('/')[1]

let bstr = atob(arr[1])

let n = bstr.length

let u8arr = new Uint8Array(n)

while (n--) {

u8arr[n] = bstr.charCodeAt(n)

}

return new File([u8arr], `${filename}.${suffix}`, {type: mime})

},

/* // 截取圆形

getRoundedCanvas (sourceCanvas) {

var canvas = document.createElement('canvas');

var context = canvas.getContext('2d');

var width = sourceCanvas.width;

var height = sourceCanvas.height;

canvas.width = width;

canvas.height = height;

context.imageSmoothingEnabled = true;

context.drawImage(sourceCanvas, 0, 0, width, height);

context.globalCompositeOperation = 'destination-in';

context.beginPath();

context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);

context.fill();

return canvas;

},*/

// base64转blob

dataURLtoBlob(dataurl) {

var arr = dataurl.split(','),

mime = arr[0].match(/:(.*?);/)[1],

bstr = atob(arr[1]),

n = bstr.length,

u8arr = new Uint8Array(n);

while (n--) {

u8arr[n] = bstr.charCodeAt(n);

}

return new Blob([u8arr], { type: mime });

},

//ArrayBuffer ---> Buffer

toBuffer(ab) {

var buf = new Buffer(ab.byteLength);

var view = new Uint8Array(ab);

for (var i = 0; i < buf.length; ++i) {

buf[i] = view[i];

}

return buf;

},

async postImg () {

//这边写图片的上传

var formData = new FormData();

formData.append("avatar",this.dataURLtoFile(this.headerImage));

// console.log(this.headerImage)

const path = await this.imgUpload(this.headerImage); // imgUpload 方法写在 mixin 里,下文会提到

// console.log('path')

// console.log(path)

this.params.name = this.params.name || 'uploadImg'

this.$emit('changeImg',path,this.params.name)

return false;

const blob = this.dataURLtoBlob(this.headerImage);

// blob转arrayBuffer

const reader = new FileReader();

reader.readAsArrayBuffer(blob);

reader.onload = event => {

// arrayBuffer转Buffer

const buffer = this.toBuffer(event.target.result);

console.log(buffer)

}

// uploadImg(formData).then(response => {

// if(response.data.code == 0){

// // alert("成功");

// this.params.logo = response.data.data

// this.$emit('changeImg',response.data.data)

// }else{

// // this.$toast(res.data.msg)

// }

// }).catch((res) => {

// // this.$toast('网路异常')

// })

}

}

}

</script>

<style>

*{

margin: 0;

padding: 0;

}

.father{

background-color: rgba(0,0,0,0.5);

position: fixed;

left:0px;

top:0px;

width:100%;

height:100%;

z-index: 33;

}

.i{

font-size: 28px;

color: #8c939d;

width: 60px;

height: 60px;

line-height: 60px;

text-align: center;

}

#demo .show {

border: 1px dashed #d9d9d9;

border-radius: 10%;

width: 60px;

height: 60px;

cursor: pointer;

position: relative;

overflow: hidden;

display: inline-block;

text-align: center;

outline: none;

background-position: center center;

background-repeat: no-repeat;

background-size: cover;

}

#demo .container {

z-index: 99;

height: 400px;

width: 50%;

position: fixed;

/*padding-top: 60px;*/

left: 25%;

top: 25%;

background-color: white;

}

#demo .images {

max-width: 100%;

}

/* .cropper-view-box,.cropper-face {

border-radius: 100%; 圆形截图设置

}*/

/*!

* Cropper.js v1.0.0-rc

* https://github.com/fengyuanchen/cropperjs

*

* Copyright (c) 2017 Fengyuan Chen

* Released under the MIT license

*

* Date: 2017-03-25T12:02:21.062Z

*/

.cropper-container {

font-size: 0;

line-height: 0;

position: relative;

-webkit-user-select: none;

-moz-user-select: none;

-ms-user-select: none;

user-select: none;

direction: ltr;

-ms-touch-action: none;

touch-action: none

}

.cropper-container img {

/* Avoid margin top issue (Occur only when margin-top <= -height) */

display: block;

min-width: 0 !important;

max-width: none !important;

min-height: 0 !important;

max-height: none !important;

width: 100%;

height: 100%;

image-orientation: 0deg

}

.cropper-wrap-box,

.cropper-canvas,

.cropper-drag-box,

.cropper-crop-box,

.cropper-modal {

position: absolute;

top: 0;

right: 0;

bottom: 0;

left: 0;

}

.cropper-wrap-box {

overflow: hidden;

}

.cropper-drag-box {

opacity: 0;

background-color: #fff;

}

.cropper-modal {

opacity: .5;

background-color: #000;

}

.cropper-view-box {

display: block;

overflow: hidden;

width: 100%;

height: 100%;

outline: 1px solid #39f;

outline-color: rgba(51, 153, 255, 0.75);

}

.cropper-dashed {

position: absolute;

display: block;

opacity: .5;

border: 0 dashed #eee

}

.cropper-dashed.dashed-h {

top: 33.33333%;

left: 0;

width: 100%;

height: 33.33333%;

border-top-width: 1px;

border-bottom-width: 1px

}

.cropper-dashed.dashed-v {

top: 0;

left: 33.33333%;

width: 33.33333%;

height: 100%;

border-right-width: 1px;

border-left-width: 1px

}

.cropper-center {

position: absolute;

top: 50%;

left: 50%;

display: block;

width: 0;

height: 0;

opacity: .75

}

.cropper-center:before,

.cropper-center:after {

position: absolute;

display: block;

content: ' ';

background-color: #eee

}

.cropper-center:before {

top: 0;

left: -3px;

width: 7px;

height: 1px

}

.cropper-center:after {

top: -3px;

left: 0;

width: 1px;

height: 7px

}

.cropper-face,

.cropper-line,

.cropper-point {

position: absolute;

display: block;

width: 100%;

height: 100%;

opacity: .1;

}

.cropper-face {

top: 0;

left: 0;

background-color: #fff;

}

.cropper-line {

background-color: #39f

}

.cropper-line.line-e {

top: 0;

right: -3px;

width: 5px;

cursor: e-resize

}

.cropper-line.line-n {

top: -3px;

left: 0;

height: 5px;

cursor: n-resize

}

.cropper-line.line-w {

top: 0;

left: -3px;

width: 5px;

cursor: w-resize

}

.cropper-line.line-s {

bottom: -3px;

left: 0;

height: 5px;

cursor: s-resize

}

.cropper-point {

width: 5px;

height: 5px;

opacity: .75;

background-color: #39f

}

.cropper-point.point-e {

top: 50%;

right: -3px;

margin-top: -3px;

cursor: e-resize

}

.cropper-point.point-n {

top: -3px;

left: 50%;

margin-left: -3px;

cursor: n-resize

}

.cropper-point.point-w {

top: 50%;

left: -3px;

margin-top: -3px;

cursor: w-resize

}

.cropper-point.point-s {

bottom: -3px;

left: 50%;

margin-left: -3px;

cursor: s-resize

}

.cropper-point.point-ne {

top: -3px;

right: -3px;

cursor: ne-resize

}

.cropper-point.point-nw {

top: -3px;

left: -3px;

cursor: nw-resize

}

.cropper-point.point-sw {

bottom: -3px;

left: -3px;

cursor: sw-resize

}

.cropper-point.point-se {

right: -3px;

bottom: -3px;

width: 20px;

height: 20px;

cursor: se-resize;

opacity: 1

}

@media (min-width: 768px) {

.cropper-point.point-se {

width: 15px;

height: 15px

}

}

@media (min-width: 992px) {

.cropper-point.point-se {

width: 10px;

height: 10px

}

}

@media (min-width: 1200px) {

.cropper-point.point-se {

width: 5px;

height: 5px;

opacity: .75

}

}

.cropper-point.point-se:before {

position: absolute;

right: -50%;

bottom: -50%;

display: block;

width: 200%;

height: 200%;

content: ' ';

opacity: 0;

background-color: #39f

}

.cropper-invisible {

opacity: 0;

}

.cropper-bg {

background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');

}

.cropper-hide {

position: absolute;

display: block;

width: 0;

height: 0;

}

.cropper-hidden {

display: none !important;

}

.cropper-move {

cursor: move;

}

.cropper-crop {

cursor: crosshair;

}

.cropper-disabled .cropper-drag-box,

.cropper-disabled .cropper-face,

.cropper-disabled .cropper-line,

.cropper-disabled .cropper-point {

cursor: not-allowed;

}

</style>

View Code

备注:需要动态设置不同id以防止同一个页面多次引入组件;(具体id在props有);

第二:设置阿里云部分

在utils文件夹下 创建upload.js

const OSS = require('ali-oss');

const moment = require('moment');

const env = process.env.NODE_ENV;

let expirationTime = null; // STS token 过期时间

let client = null; // OSS Client 实例

const bucket = {

development: 'brinvest',

dev: 'brinvest',

pre: 'filespre',

beta: 'filespro',

production: 'filespro'

};

// 初始化 oss client

export function initOssClient(accessKeyId, accessKeySecret, stsToken, expiration, bucketName) {

client = new OSS({

accessKeyId,

accessKeySecret,

stsToken,

// region: '/',

region: 'oss-cn-beijing',

bucket: bucketName

// bucket: bucket[`${env}`]

});

expirationTime = expiration;

return client;

}

// 检查 oss 实例以及过期时间

export function checkOssClient() {

const current = moment();

return moment(expirationTime).diff(current) < 0 ? null : client;

}

// 用于 sts token 失效、用户登出时注销 oss client

export function destroyOssClient() {

client = null;

}

View Code

在 mixins文件夹下 创建upload.js

import { checkOssClient, initOssClient } from '../utils/upload';

import { uploadOssImg } from '../api/common'

// import { resolve } from 'core-js/fn/promise';

const uploadMixin = {

methods: {

// 图片上传至 oss

async imgUpload(opt) {

// console.log(opt)

// if (opt.file.size > 1024 * 1024) {

// this.$message.warning(`请上传小于1MB的图片`);

// return;

// }

// 获取文件后缀

// const tmp = opt.file.name.split('.');

// const extname = tmp.pop();

// const extList = ['jpg', 'jpeg', 'png', 'gif'];

// // 校验文件类型

// const isValid = extList.includes(extname);

// if (!isValid) {

// this.$message.warning(`只支持上传 jpg、jpeg、png、gif 格式的图片`);

// return;

// }

// 检查是否已有 Oss Client

// let client = checkOssClient();

let client = null;

let getTokenRes = {}

if (client === null) {

try {

// const res = await this.$http.get('/api/oss/getAccessToken', {});

const res = await uploadOssImg().then((resout) => {

return resout

})

// console.log(res.data )

if (res.code == 0) {

const credentials = res.data; //fileName requestId

getTokenRes = { ...res.data }

client = initOssClient(

credentials.accessKeyId,

credentials.accessKeySecret,

credentials.securityToken,

credentials.expiration,

credentials.bucketName

);

}

} catch (error) {

this.$message.error(`${error}`);

return;

}

}

// 生产随机文件名

const randomName = Array(32)

.fill(null)

.map(() => Math.round(Math.random() * 16).toString(16))

.join('');

let path = getTokenRes.fileName +'.jpg' //brinvest/mZy3zteXmJGTn2q4zI00nZq0ltG2mJGTmJyXy2jHmwe2oda20mJeZmdCWnJqZmW

// path = 'brinvest/mZy3zteXmJGTn2q4zI00nZq0ltG2mJGTmJyXy2jHmwe2oda20mJeZmdCWnJqZmW'

let url;

// return path;

// try {

// 使用 multipartUpload 正式上传到 oss

// console.log(path)

// console.log(client)

// const PromiseMsg = new Promise((resolve , reject) => {

// const blob = this.dataURLtoBlob(opt);

// // blob转arrayBuffer

// const reader = new FileReader();

// reader.readAsArrayBuffer(blob);

// reader.onload = event => {

// // arrayBuffer转Buffer

// const buffer = this.toBuffer(event.target.result);

// // console.log(buffer)

// //命名规则 以后缀为文件目录 md5为文件名 可自定义

// //${this.suffix}/${this.pw}.${this.suffix}

// client

// .put(path, buffer)

// .then(res => {

// // console.log(res);

// url = 'http://brinvest.bridata.com/' + path;

// // resolve(url)

// return url;

// })

// .catch(err => {

// console.log(err);

// });

// console.log('multipartUpload res')

// // console.log(result)

// // 去除 oss 分片上传后返回所带的查询参数,否则访问会 403

// // const ossPath = res.requestUrls[0];

// // // 替换协议,统一使用 'https://',否则 Android 无法显示图片

// // url = ossPath.replace('http://', 'https://');

// console.log('minix url111')

// // console.log(result)

// }

// })

// PromiseMsg.then((res) => {

// console.log(res)

// return res

// })

const blob = this.dataURLtoBlob(opt);

// blob转arrayBuffer

const reader = new FileReader();

reader.readAsArrayBuffer(blob);

let res;

// reader.onload = (event) => {

// arrayBuffer转Buffer

// console.log('p')

// const buffer = this.toBuffer(event.target.result);

res = await client.multipartUpload(path, blob, {

// progress: async function(p) {

// console.log(p)

// // progress is generator

// let e = {};

// e.percent = p * 100;

// // 上传进度条,el-upload 组件自带的方法

// // opt.onProgress(e);

// },

});

// console.log(res);

if(res.res){

url = 'http://bri.com/' + path;

}

return url;

// }

console.log('PromiseMsg');

console.log(res);

// } catch (error) {

// console.log('error')

// console.log(error)

// this.$message.error(`${error}`);

// }

console.log('minix url222')

console.log(url)

// resolve(url)

},

// base64转blob

dataURLtoBlob(dataurl) {

var arr = dataurl.split(','),

mime = arr[0].match(/:(.*?);/)[1],

bstr = atob(arr[1]),

n = bstr.length,

u8arr = new Uint8Array(n);

while (n--) {

u8arr[n] = bstr.charCodeAt(n);

}

return new Blob([u8arr], { type: mime });

},

//ArrayBuffer ---> Buffer

toBuffer(ab) {

var buf = new Buffer(ab.byteLength);

var view = new Uint8Array(ab);

for (var i = 0; i < buf.length; ++i) {

buf[i] = view[i];

}

return buf;

},

}

};

export default uploadMixin;

View Code

在main.js中引用

import uploadjs from '@/mixins/upload'

Vue.mixin(uploadjs)

备注:根据后台提供接口获取token等信息创建client OSS Client 实例 根据返回值获取对应图片信息;

以上是 vue 封装 上传图片(有截图功能)并将图片上传到阿里云 的全部内容, 来源链接: utcz.com/z/378111.html

回到顶部