Vue-cli and Element-ui encapsulate vue Based on cropper. js to implement the image cropping component function. vue-clielement-ui

Source: Internet
Author: User

Vue-cli and Element-ui encapsulate vue Based on cropper. js to implement the image cropping component function. vue-clielement-ui

In front-end work, image cropping is often required,cropper.jsIs an excellent front-end plug-in with a wide range of APIs.

This article encapsulates the image cropping plug-in the vue-cli project, as follows:

Let's take a look at the steps.

Step 1: Prepare the development environment

Cropper. js is based on jquery, so you must install jquery first.

Run the following command:

npm  install --save-dev jquery cropper

Add jquery ing for webpack Configuration

Modifywebpack.base.conf.jsConfiguration, add a red line

Step 2: create an image cropping component

Index. vue content:

Element-ui is used, and the layout references the element-ui component.

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 -- primary"> select an image </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-lg "> </div> <div class =" avatar-preview-round preview-md "> </ div> <! -- <Div class = "avatar-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 -- primary" data-method = "rotate" data -option = "-180" title = "Rotate-180 degrees">-180deg </button> <button type = "primary" class = "el-button -- primary "data-method =" rotate "data-option ="-90 "title =" Rotat E-90 degrees ">-90deg </button> <button type =" primary "class =" el-button -- primary "data-method =" rotate "data- option = "-45" title = "Rotate-45 degrees">-45deg </button> <button type = "primary" class = "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-op Tion = "90" title = "Rotate 90 degrees"> 90deg </button> <button type = "primary" class = "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> <! -- <Button type = "submit" class = "btn-primary btn-block avatar-save"> cut </button> --> </el-row> </div> </div> </form> </div> </template>

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-width: 768px) { .cropper-point.point-se {  height: 15px;  width: 15px; } } @media (min-width: 992px) { .cropper-point.point-se {  height: 10px;  width: 10px; } } @media (min-width: 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-width: 992px) { .avatar-preview {  float: none; } } .avatar-btns { margin-top: 30px; margin-bottom: 15px; } .avatar-btns .btn-group { margin-right: 5px; }</style>

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. $ av AtarForm. 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. startCropp Er () ;}, 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 ('') ;}, initIframe: function () {var target = 'upload-iframe-'+ (new Da Te ()). 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. submitDo Ne (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 () ;}}, // crop and submit: function () {if (! This. $ avatarSrc. val ()&&! This. $ avatarInput. val () {return false;} if (this. support. formData) {this. ajaxUpload (); return false ;}}, // rotation event rotate: function (e) {var data; if (this. active) {data = tables (e.tar get ). 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 = $ (''); 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 (); // Save the cut parameter _ this. $ avatarData. val (json) ;}}); this. active = true ;}, stopCropper: function () {if (this. active) {this. $ img. cropper ('deststroy'); 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) {// send the returned data to the parent component _ 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>

Step 3: parent component references child components

The el-dialog component in element-ui is used. The el-dialog component is the parent component.

Introduce child components into Parent Components

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

Template:

<Template> <div class = "app-main-content"> <el-dialog: visible. sync = "showCropper" title = "cover Cutting Image" width = "70%"> <cropper id = "avatarCrop" ref = "cropper" @ cropper-success = "cropperSuccessHandle"> </cropper> <span slot = "footer" class = "dialog-footer"> <el-button @ click = "cancelCropper"> cancel </el-button> <el- button type = "primary" @ click = "toCropper"> confirm </el-button> </span> </el-dialog> </div>

Script:

Import cropper from '@/components/Cropper/Index' export default {name: 'addnew', components: {cropper}, data () {return {avatarUrl2: null, showCropper: false }}, methods: {// hide the cancelCropper () {this. showCropper = false this. $ refs. cropper. cropDone () ;}, // The parent component calls the toCropper () {this. $ refs. cropper. submit () ;}, // The cropperSuccessHandle (data) {// return data this. showCropper = false this. avatarUrl2 = data. url }}}

This document combines element-ui, vue-cli, jquery, and cropper. js to encapsulate the cut graph component. Write it here first. If it is helpful to you, please give me a thumbs up!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.