• 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- 768px) {
        .cropper-point.point-se {
          width: 15px;
          height: 15px
        }
      }
      @media (min- 992px) {
        .cropper-point.point-se {
          width: 10px;
          height: 10px
        }
      }
      @media (min- 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 实例 根据返回值获取对应图片信息;

  • 相关阅读:
    pytest之fixture的详细使用
    pytest之自定义标记mark
    解决pytest.mark自定义标签导致的warning
    pytest之参数化parametrize的使用
    Jenkins上allure报告清空上一次运行记录
    Jenkins配置从节点并生成allure测试报告
    《编程珠玑》笔记:数组循环左移
    精确覆盖 DLX
    海量数据的插入和查找 bloom filter
    ORACLE数据库的一些限制
  • 原文地址:https://www.cnblogs.com/lst619247/p/14821500.html
Copyright © 2020-2023  润新知