vue-cli 결합 Element-ui 는 cropper.js 패키지 vue 를 기반 으로 이미지 재단 구성 요소 기능 을 실현 합 니 다.
cropper.js
우수한 전단 플러그 인 으로 api 가 매우 풍부 합 니 다.본 고 는 vue-cli 프로젝트 에서 그림 재단 플러그 인 을 밀봉 하고 효과 도 는 다음 과 같 습 니 다.
말 이 많 지 않 으 니 절 차 를 보 세 요.
STEP 1:개발 환경 준비
cropper.js 는 jquery 기반 이기 때문에 jquery 를 먼저 설치 해 야 합 니 다.
명령 실행:
npm install --save-dev jquery cropper
웹 팩 설정 에 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>
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.$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 와 결합 하여 컷 구성 요소 의 패 키 징 을 실현 합 니 다.먼저 여기까지 썼 습 니 다.도움 이 된다 면 좋아요 도 눌 러 주세요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Fastapi websocket 및 vue 3(Composition API)1부: FastAPI virtualenv 만들기(선택 사항) FastAPI 및 필요한 모든 것을 다음과 같이 설치하십시오. 생성main.py 파일 및 실행 - 브라우저에서 이 링크 열기http://127.0.0.1:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.