zoukankan      html  css  js  c++  java
  • vue-cli项目结合Element-ui基于cropper.js封装vue图片裁剪组件

    前端工作中,经常需要图片裁剪的场景,cropper.js是一款优秀的前端插件,api十分丰富。

    本文是在vue-cli项目下封装图片裁剪插件,效果图如下:

    话不多说,看步骤吧。

    第一步:准备开发环境

    cropper.js是基于jquery的,所以要先安装jquery

    执行命令:

      npm  install --save-dev jquery cropper

     为webpack配置添加jquery的映射

    修改webpack.base.conf.js配置,添加标红的一行

     

    第二步:新建图片裁剪组件 

    index.vue内容:

    由于用了element-ui,其中布局就引用了element-ui的组件

     template:

       

    <template>
      <div class="modal-dialog modal-lg" :id="id">
        <div class="modal-content">
          <form class="avatar-form"  enctype="multipart/form-data" method="post">
            <div class="modal-header">
            </div>
            <div class="modal-body">
              <div class="avatar-body">
                <!-- Upload image and data -->
                <div class="avatar-upload">
                  <input type="hidden" class="avatar-src" name="avatar_src">
                  <input type="hidden" class="avatar-data" name="ci">
                  <label for="avatarInput" class="el-button el-button--primary">选择图片</label>
                  <input type="file" class="avatar-input " style="visibility: hidden" id="avatarInput" name="file">
                </div>
    
                <!-- Crop and preview -->
                <el-row>
                  <el-col :span="18">
                    <div class="avatar-wrapper"></div>
                  </el-col>
                  <el-col :span="6" style="overflow: hidden;">
                    <div style="padding-left: 10px">
                      <div class="avatar-preview preview-lg" ></div>
                      <div class="avatar-preview avatar-preview-round preview-md"></div>
                    <!--<div class="avatar-preview preview-sm"></div>-->
                    </div>
                  </el-col>
    
                </el-row>
                <el-row class="avatar-btns">
                  <el-col :span="18">
                    <el-button-group>
                      <button type="primary" class="el-button el-button--primary"  data-method="rotate" data-option="-180" title="Rotate -180 degrees">-180deg</button>
                      <button type="primary" class="el-button el-button--primary"  data-method="rotate" data-option="-90" title="Rotate -90 degrees">-90deg</button>
                      <button type="primary" class="el-button el-button--primary"   data-method="rotate" data-option="-45" title="Rotate -45 degrees">-45deg</button>
                      <button type="primary" class="el-button el-button--primary"  data-method="rotate" data-option="45" title="Rotate 45 degrees">45deg</button>
                      <button type="primary" class="el-button el-button--primary"  data-method="rotate" data-option="90" title="Rotate 90 degrees">90deg</button>
                      <button type="primary" class="el-button el-button--primary"  data-method="rotate" data-option="180" title="Rotate 180 degrees">180deg</button>
                    </el-button-group>
                  </el-col>
                  <el-col :span="6"></el-col>
                </el-row>
                <el-row>
                  <!--<button type="submit" class="btn btn-primary btn-block avatar-save">裁取</button>-->
                </el-row>
              </div>
            </div>
    
          </form>
        </div>
      </div>
    </template>
    View Code

    style:

    <style rel="stylesheet/scss" lang='scss' scoped>
      /*@import "cropper/dist/cropper.css";*/
      /*!
     * Cropper v3.1.3
     * https://github.com/fengyuanchen/cropper
     *
     * Copyright (c) 2014-2017 Chen Fengyuan
     * Released under the MIT license
     *
     * Date: 2017-10-21T10:03:37.133Z
     */
      .avatar-wrapper{
        width: 100%;
        height: 100%;
        overflow: hidden;
      }
      .cropper-container {
        direction: ltr;
        font-size: 0;
        line-height: 0;
        position: relative;
        -ms-touch-action: none;
        touch-action: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
      }
    
      .cropper-container img {/*Avoid margin top issue (Occur only when margin-top <= -height)
     */
        display: block;
        height: 100%;
        image-orientation: 0deg;
        max-height: none !important;
        max-width: none !important;
        min-height: 0 !important;
        min-width: 0 !important;
        width: 100%;
      }
    
      .cropper-wrap-box,
      .cropper-canvas,
      .cropper-drag-box,
      .cropper-crop-box,
      .cropper-modal {
        bottom: 0;
        left: 0;
        position: absolute;
        right: 0;
        top: 0;
      }
    
      .cropper-wrap-box,
      .cropper-canvas {
        overflow: hidden;
      }
    
      .cropper-drag-box {
        background-color: #fff;
        opacity: 0;
      }
    
      .cropper-modal {
        background-color: #000;
        opacity: .5;
      }
    
      .cropper-view-box {
        display: block;
        height: 100%;
        outline-color: rgba(51, 153, 255, 0.75);
        outline: 1px solid #39f;
        overflow: hidden;
        width: 100%;
      }
    
      .cropper-dashed {
        border: 0 dashed #eee;
        display: block;
        opacity: .5;
        position: absolute;
      }
    
      .cropper-dashed.dashed-h {
        border-bottom-width: 1px;
        border-top-width: 1px;
        height: 33.33333%;
        left: 0;
        top: 33.33333%;
        width: 100%;
      }
    
      .cropper-dashed.dashed-v {
        border-left-width: 1px;
        border-right-width: 1px;
        height: 100%;
        left: 33.33333%;
        top: 0;
        width: 33.33333%;
      }
    
      .cropper-center {
        display: block;
        height: 0;
        left: 50%;
        opacity: .75;
        position: absolute;
        top: 50%;
        width: 0;
      }
    
      .cropper-center:before,
      .cropper-center:after {
        background-color: #eee;
        content: ' ';
        display: block;
        position: absolute;
      }
    
      .cropper-center:before {
        height: 1px;
        left: -3px;
        top: 0;
        width: 7px;
      }
    
      .cropper-center:after {
        height: 7px;
        left: 0;
        top: -3px;
        width: 1px;
      }
    
      .cropper-face,
      .cropper-line,
      .cropper-point {
        display: block;
        height: 100%;
        opacity: .1;
        position: absolute;
        width: 100%;
      }
    
      .cropper-face {
        background-color: #fff;
        left: 0;
        top: 0;
      }
    
      .cropper-line {
        background-color: #39f;
      }
    
      .cropper-line.line-e {
        cursor: e-resize;
        right: -3px;
        top: 0;
        width: 5px;
      }
    
      .cropper-line.line-n {
        cursor: n-resize;
        height: 5px;
        left: 0;
        top: -3px;
      }
    
      .cropper-line.line-w {
        cursor: w-resize;
        left: -3px;
        top: 0;
        width: 5px;
      }
    
      .cropper-line.line-s {
        bottom: -3px;
        cursor: s-resize;
        height: 5px;
        left: 0;
      }
    
      .cropper-point {
        background-color: #39f;
        height: 5px;
        opacity: .75;
        width: 5px;
      }
    
      .cropper-point.point-e {
        cursor: e-resize;
        margin-top: -3px;
        right: -3px;
        top: 50%;
      }
    
      .cropper-point.point-n {
        cursor: n-resize;
        left: 50%;
        margin-left: -3px;
        top: -3px;
      }
    
      .cropper-point.point-w {
        cursor: w-resize;
        left: -3px;
        margin-top: -3px;
        top: 50%;
      }
    
      .cropper-point.point-s {
        bottom: -3px;
        cursor: s-resize;
        left: 50%;
        margin-left: -3px;
      }
    
      .cropper-point.point-ne {
        cursor: ne-resize;
        right: -3px;
        top: -3px;
      }
    
      .cropper-point.point-nw {
        cursor: nw-resize;
        left: -3px;
        top: -3px;
      }
    
      .cropper-point.point-sw {
        bottom: -3px;
        cursor: sw-resize;
        left: -3px;
      }
    
      .cropper-point.point-se {
        bottom: -3px;
        cursor: se-resize;
        height: 20px;
        opacity: 1;
        right: -3px;
        width: 20px;
      }
    
      @media (min- 768px) {
        .cropper-point.point-se {
          height: 15px;
          width: 15px;
        }
      }
    
      @media (min- 992px) {
        .cropper-point.point-se {
          height: 10px;
          width: 10px;
        }
      }
    
      @media (min- 1200px) {
        .cropper-point.point-se {
          height: 5px;
          opacity: .75;
          width: 5px;
        }
      }
    
      .cropper-point.point-se:before {
        background-color: #39f;
        bottom: -50%;
        content: ' ';
        display: block;
        height: 200%;
        opacity: 0;
        position: absolute;
        right: -50%;
        width: 200%;
      }
    
      .cropper-invisible {
        opacity: 0;
      }
    
      .cropper-bg {
        background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
      }
    
      .cropper-hide {
        display: block;
        height: 0;
        position: absolute;
        width: 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;
      }
    
      .avatar-view {
        display: block;
        margin: 15% auto 5%;
        height: 220px;
        width: 220px;
        border: 3px solid #fff;
        border-radius: 5px;
        box-shadow: 0 0 5px rgba(0,0,0,.15);
        cursor: pointer;
        overflow: hidden;
      }
    
      .avatar-view img {
        width: 100%;
      }
    
      .avatar-body {
        padding-right: 15px;
        padding-left: 15px;
      }
    
      .avatar-upload {
        overflow: hidden;
      }
    
      .avatar-upload label {
        display: block;
        float: left;
        clear: left;
        width: 100px;
      }
    
      .avatar-upload input {
        display: block;
        margin-left: 110px;
      }
    
      .avatar-alert {
        margin-top: 10px;
        margin-bottom: 10px;
      }
    
      .avatar-wrapper {
        height: 364px;
        width: 100%;
        margin-top: 15px;
        box-shadow: inset 0 0 5px rgba(0,0,0,.25);
        background-color: #fcfcfc;
        overflow: hidden;
      }
    
      .avatar-wrapper img {
        display: block;
        height: auto;
        max-width: 100%;
      }
    
      .avatar-preview {
        float: left;
        margin-top: 15px;
        margin-right: 15px;
        border: 1px solid #eee;
        border-radius: 4px;
        background-color: #fff;
        overflow: hidden;
      }
    
      .avatar-preview:hover {
        border-color: #ccf;
        box-shadow: 0 0 5px rgba(0,0,0,.15);
      }
    
      .avatar-preview img {
        width: 100%;
      }
    
      .avatar-preview-round{
        border-radius: 50%;
      }
      .preview-lg {
        height: 184px;
        width: 184px;
        margin-top: 15px;
      }
    
      .preview-md {
        height: 100px;
        width: 100px;
      }
    
      .preview-sm {
        height: 50px;
        width: 50px;
      }
    
      @media (min- 992px) {
        .avatar-preview {
          float: none;
        }
      }
    
      .avatar-btns {
        margin-top: 30px;
        margin-bottom: 15px;
      }
    
      .avatar-btns .btn-group {
        margin-right: 5px;
      }
    
    
    
    </style>
    View Code

    script:

    <script>
      import $ from 'jquery'
      import 'cropper/dist/cropper.js'
      export default {
    props:{ id:String }, data(){
    return { $container:null, $avatarView:null, $avatarModal : null, $loading : null, $avatarForm : null, $avatarUpload : null, $avatarSrc : null, $avatarData : null, $avatarInput : null, $avatarSave: null, $avatarBtns : null, $avatarWrapper : null, $avatarPreview: null, support: { fileList: !!$('<input type="file">').prop('files'), blobURLs: !!window.URL && URL.createObjectURL, formData: !!window.FormData } } }, created(){}, mounted(){ this.$container = $('#'+this.id); this.$avatarForm = this.$container.find('.avatar-form'); this.$avatarUpload = this.$avatarForm.find('.avatar-upload'); this.$avatarSrc = this.$avatarForm.find('.avatar-src'); this.$avatarData = this.$avatarForm.find('.avatar-data'); this.$avatarInput = this.$avatarForm.find('.avatar-input'); this.$avatarSave = this.$avatarForm.find('.avatar-save'); this.$avatarWrapper = this.$container.find('.avatar-wrapper'); this.$avatarPreview = this.$container.find('.avatar-preview'); this.$avatarBtns = this.$container.find('.avatar-btns');
    this.$nextTick(function () { this.init(); }) }, methods:{ init: function () { this.support.datauri = this.support.fileList && this.support.blobURLs; this.addListener(); // this.startCropper(); }, addListener: function () { this.$avatarInput.on('change', $.proxy(this.change, this)); this.$avatarForm.on('submit', $.proxy(this.submit, this)); this.$avatarBtns.on('click', $.proxy(this.rotate, this)); }, initPreview: function () { var url = this.$avatar.attr('src'); this.$avatarPreview.html('<img src="' + url + '">'); }, initIframe: function () { var target = 'upload-iframe-' + (new Date()).getTime(); var $iframe = $('<iframe>').attr({ name: target, src: '' }); var _this = this; // Ready ifrmae $iframe.one('load', function () { // respond response $iframe.on('load', function () { var data; try { data = $(this).contents().find('body').text(); } catch (e) { console.log(e.message); } if (data) { try { data = $.parseJSON(data); } catch (e) { console.log(e.message); } _this.submitDone(data); } else { } _this.submitEnd(); }); }); this.$iframe = $iframe; this.$avatarForm.attr('target', target).after($iframe.hide()); }, click:function () { this.initPreview(); }, change: function () { var files; var file; if (this.support.datauri) { files = this.$avatarInput.prop('files'); if (files.length > 0) { file = files[0]; if (this.isImageFile(file)) { if (this.url) { URL.revokeObjectURL(this.url); // Revoke the old one } this.url = URL.createObjectURL(file); this.startCropper(); } } } else { file = this.$avatarInput.val(); if (this.isImageFile(file)) { this.syncUpload(); } } }, //裁剪提交 submit: function () { if (!this.$avatarSrc.val() && !this.$avatarInput.val()) { return false; } if (this.support.formData) { this.ajaxUpload(); return false; } },
    //旋转事件 rotate:
    function (e) { var data; if (this.active) { data = $(e.target).data(); if (data.method) { this.$img.cropper(data.method, data.option); } } }, isImageFile: function (file) { if (file.type) { return /^image/w+$/.test(file.type); } else { return /.(jpg|jpeg|png|gif)$/.test(file); } }, startCropper: function () { var _this = this; if (this.active) { this.$img.cropper('replace', this.url); } else { this.$img = $('<img src="' + this.url + '">'); this.$avatarWrapper.empty().html(this.$img); this.$img.cropper({ viewMode:1, aspectRatio: 1, preview: this.$avatarPreview, restore:false, crop: function (e) { var json = [ '{"x":' + e.x, '"y":' + e.y, '"height":' + e.height, '"width":' + e.width, '"rotate":' + e.rotate + '}' ].join(); //裁图参数存起来 _this.$avatarData.val(json); } }); this.active = true; } }, stopCropper: function () { if (this.active) { this.$img.cropper('destroy'); this.$img.remove(); this.active = false; } }, ajaxUpload: function () { var url = '/oss/file/cropping'; var data = new FormData(this.$avatarForm[0]); var _this = this; $.ajax(url, { type: 'post', data: data, dataType: 'json', processData: false, contentType: false, success: function (data,textStatus) { _this.submitDone(data); if(data.success){ //将返回的数据传给父组件 _this.$emit('cropper-success',data.data); _this.cropDone(); } }, }); }, syncUpload: function () { this.$avatarSave.click(); }, submitDone: function (data) { if ($.isPlainObject(data) && data.state === 200) { if (data.result) { this.url = data.result; if (this.support.datauri || this.uploaded) { this.uploaded = false; this.cropDone(); } else { this.uploaded = true; this.$avatarSrc.val(this.url); this.startCropper(); } this.$avatarInput.val(''); } else if (data.message) { } } else { } }, cropDone: function () { // this.$avatarForm.get(0).reset(); // this.$avatarSrc.prop('src', this.url); this.stopCropper(); // this.$container.hide(); } } } </script>

     第三步:父组件引用子组件

    用了element-ui中的 el-dialog组件,此时el-dialog组件为父组件

    在父组件中引入子组件

    import cropper from '@/components/Cropper/index'

    template:

    <template>
    
      <div class="app-main-content" >
    
        <el-dialog :visible.sync="showCropper" title="封面裁图" width="70%">
          <cropper id="avatarCrop" ref="cropper" @cropper-success="cropperSuccessHandle"></cropper>
          <span slot="footer" class="dialog-footer">
            <el-button @click="cancelCropper">取 消</el-button>
            <el-button type="primary" @click="toCropper">确 定</el-button>
          </span>
        </el-dialog>
      </div>

    script:

    import cropper from '@/components/Cropper/index'
    export default {
        name: 'addNews',
        components:{
          cropper
        },
        data(){
          return {
            avatarUrl2: null,
            showCropper:false
          }
        },
        methods:{
         //隐藏裁剪框
          cancelCropper(){
            this.showCropper = false
            this.$refs.cropper.cropDone();
          },
         //父组件调用子组件裁剪方法
          toCropper(){
             this.$refs.cropper.submit();
          },
         //子组件裁剪方法成功执行后与父组件通信
          cropperSuccessHandle(data){
             //返回data
            this.showCropper = false
            this.avatarUrl2 = data.url
          }
        }
      }
    本文结合element-ui,vue-cli,jquery,cropper.js,实现裁图组件的封装,先写到这啦,如果对你有帮助,还请点个赞噢!

  • 相关阅读:
    RAID磁盘阵列
    Activiti任务认领
    Activiti 5.18启动流程到完成所有任务之间的数据库变化(转)
    tomcat优化(转)
    DB2 OLAP函数的使用
    PreparedStatement批量处理和事务
    获取JavaScript异步函数的返回值
    DB2 sql报错后查证原因与解决问题的方法
    DB2有五种约束
    连接db2数据库出现No buffer space available (maximum connections reached?)
  • 原文地址:https://www.cnblogs.com/lizimeme/p/8303709.html
Copyright © 2011-2022 走看看