up
This commit is contained in:
@@ -0,0 +1,217 @@
|
|||||||
|
<template>
|
||||||
|
<div class="basic_container">
|
||||||
|
<div class="tool_wrap">
|
||||||
|
<button :class="{ active: isCropperMove }" @click="handleMove">
|
||||||
|
移动
|
||||||
|
</button>
|
||||||
|
<button @click="handleRotate">旋转</button>
|
||||||
|
<button :class="{ active: isCropperSelection }" @click="handleCropper">
|
||||||
|
{{ isCropperSelection ? '重置选区' : '裁剪' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dialog_wrap">
|
||||||
|
<div class="image_wrap" ref="imageWrap">
|
||||||
|
<cropper-canvas ref="croppercanvas" background>
|
||||||
|
<cropper-image
|
||||||
|
:src="fileObj.fileShow"
|
||||||
|
alt="Picture"
|
||||||
|
ref="cropperimage"
|
||||||
|
rotatable
|
||||||
|
scalable
|
||||||
|
skewable
|
||||||
|
translatable
|
||||||
|
></cropper-image>
|
||||||
|
<cropper-shade hidden ref="cropperShade"></cropper-shade>
|
||||||
|
<cropper-handle :action="currentType" plain></cropper-handle>
|
||||||
|
<cropper-selection
|
||||||
|
id="cropperSelection"
|
||||||
|
ref="cropperselection"
|
||||||
|
movable
|
||||||
|
resizable
|
||||||
|
hidden
|
||||||
|
outlined
|
||||||
|
@change="onCropperSelectionChange"
|
||||||
|
>
|
||||||
|
<cropper-crosshair centered />
|
||||||
|
<cropper-handle
|
||||||
|
action="move"
|
||||||
|
theme-color="rgba(255, 255, 255, 0.35)"
|
||||||
|
/>
|
||||||
|
<cropper-handle action="n-resize" />
|
||||||
|
<cropper-handle action="e-resize" />
|
||||||
|
<cropper-handle action="s-resize" />
|
||||||
|
<cropper-handle action="w-resize" />
|
||||||
|
<cropper-handle action="ne-resize" />
|
||||||
|
<cropper-handle action="nw-resize" />
|
||||||
|
<cropper-handle action="se-resize" />
|
||||||
|
<cropper-handle action="sw-resize" />
|
||||||
|
</cropper-selection>
|
||||||
|
</cropper-canvas>
|
||||||
|
</div>
|
||||||
|
<div class="info_wrap">
|
||||||
|
<div class="cropper_preview">
|
||||||
|
<cropper-viewer
|
||||||
|
selection="#cropperSelection"
|
||||||
|
style="width: 200px"
|
||||||
|
></cropper-viewer>
|
||||||
|
</div>
|
||||||
|
<div class="btn_wrap">
|
||||||
|
<input type="file" ref="input_form" @change="handleUploadSuccess" />
|
||||||
|
<button type="primary" @click="handleConfirm">确 认</button>
|
||||||
|
</div>
|
||||||
|
点击确认后,看控制台,有信息
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import 'cropperjs';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
const fileObj = ref({});
|
||||||
|
|
||||||
|
const croppercanvas = ref();
|
||||||
|
const cropperimage = ref();
|
||||||
|
const cropperselection = ref();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选区逻辑
|
||||||
|
*/
|
||||||
|
// 是否正在开始选区
|
||||||
|
const isCropperSelection = ref(false);
|
||||||
|
const isCropperMove = ref(true);
|
||||||
|
|
||||||
|
// 判断当前是移动还是选区
|
||||||
|
const currentType = computed(() => (isCropperMove.value ? 'move' : 'select'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮方法
|
||||||
|
*/
|
||||||
|
// 旋转
|
||||||
|
function handleRotate() {
|
||||||
|
cropperimage.value.$rotate('90deg');
|
||||||
|
cropperimage.value.$center('contain');
|
||||||
|
}
|
||||||
|
// 裁剪
|
||||||
|
function handleCropper() {
|
||||||
|
isCropperMove.value = false;
|
||||||
|
if (isCropperMove.value) {
|
||||||
|
cropperselection.value.$clear();
|
||||||
|
} else {
|
||||||
|
const cropperCanvas = croppercanvas.value;
|
||||||
|
const cropperCanvasRect = cropperCanvas.getBoundingClientRect();
|
||||||
|
|
||||||
|
const cropperImage = cropperimage.value;
|
||||||
|
const cropperImageRect = cropperImage.getBoundingClientRect();
|
||||||
|
const maxSelection = {
|
||||||
|
x: cropperImageRect.left - cropperCanvasRect.left,
|
||||||
|
y: cropperImageRect.top - cropperCanvasRect.top,
|
||||||
|
width: cropperImageRect.width,
|
||||||
|
height: cropperImageRect.height,
|
||||||
|
};
|
||||||
|
cropperselection.value.$change(
|
||||||
|
maxSelection.x,
|
||||||
|
maxSelection.y,
|
||||||
|
maxSelection.width,
|
||||||
|
maxSelection.height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 移动
|
||||||
|
function handleMove() {
|
||||||
|
if (!isCropperMove.value) {
|
||||||
|
isCropperMove.value = true;
|
||||||
|
// 如果想要点击移动,清除选区,可以打开下面的代码注释
|
||||||
|
// cropperselection.value.$clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听选择区变化
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
function onCropperSelectionChange(event) {
|
||||||
|
if (event.detail.width && event.detail.height) {
|
||||||
|
isCropperSelection.value = true;
|
||||||
|
} else {
|
||||||
|
isCropperSelection.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认裁剪
|
||||||
|
*/
|
||||||
|
const emit = defineEmits(['success']);
|
||||||
|
async function handleConfirm() {
|
||||||
|
if (isCropperSelection.value) {
|
||||||
|
const res = await cropperselection.value.$toCanvas();
|
||||||
|
|
||||||
|
const dataImage = res.toDataURL('image/png');
|
||||||
|
const file = dataURLtoFile(dataImage, fileObj.value.name);
|
||||||
|
emit('success', {
|
||||||
|
...fileObj.value,
|
||||||
|
file: file,
|
||||||
|
fileShow: dataImage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将data:image转成新的file
|
||||||
|
function dataURLtoFile(dataurl, filename) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
const blob = new Blob([u8arr], { type: mime });
|
||||||
|
const file = new File([blob], filename, { type: mime });
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传
|
||||||
|
*/
|
||||||
|
const input_form = ref();
|
||||||
|
function handleUploadSuccess() {
|
||||||
|
const files = input_form.value.files;
|
||||||
|
|
||||||
|
if (files.length) {
|
||||||
|
fileObj.value = {
|
||||||
|
name: files[0].name,
|
||||||
|
file: files[0],
|
||||||
|
fileShow: URL.createObjectURL(files[0]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dialog_wrap {
|
||||||
|
display: flex;
|
||||||
|
.image_wrap {
|
||||||
|
width: 400px;
|
||||||
|
height: 300px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
cropper-canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info_wrap {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
& + button {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button.active {
|
||||||
|
background-color: #c6dff8;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button @click="handleRotate">旋转</button>
|
<button @click="handleRotate">旋转</button>
|
||||||
<button :class="{ active: isCropperSelection }" @click="handleCropper">
|
<button :class="{ active: isCropperSelection }" @click="handleCropper">
|
||||||
{{ isCropperSelection ? '重置选区' : '裁剪' }}
|
{{ isCropperSelection ? "重置选区" : "裁剪" }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dialog_wrap">
|
<div class="dialog_wrap">
|
||||||
@@ -66,8 +66,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import 'cropperjs';
|
import "cropperjs";
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
const fileObj = ref({});
|
const fileObj = ref({});
|
||||||
|
|
||||||
@@ -83,15 +83,15 @@ const isCropperSelection = ref(false);
|
|||||||
const isCropperMove = ref(true);
|
const isCropperMove = ref(true);
|
||||||
|
|
||||||
// 判断当前是移动还是选区
|
// 判断当前是移动还是选区
|
||||||
const currentType = computed(() => (isCropperMove.value ? 'move' : 'select'));
|
const currentType = computed(() => (isCropperMove.value ? "move" : "select"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按钮方法
|
* 按钮方法
|
||||||
*/
|
*/
|
||||||
// 旋转
|
// 旋转
|
||||||
function handleRotate() {
|
function handleRotate() {
|
||||||
cropperimage.value.$rotate('90deg');
|
cropperimage.value.$rotate("90deg");
|
||||||
cropperimage.value.$center('contain');
|
cropperimage.value.$center("contain");
|
||||||
}
|
}
|
||||||
// 裁剪
|
// 裁剪
|
||||||
function handleCropper() {
|
function handleCropper() {
|
||||||
@@ -114,7 +114,7 @@ function handleCropper() {
|
|||||||
maxSelection.x,
|
maxSelection.x,
|
||||||
maxSelection.y,
|
maxSelection.y,
|
||||||
maxSelection.width,
|
maxSelection.width,
|
||||||
maxSelection.height,
|
maxSelection.height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,14 +142,14 @@ function onCropperSelectionChange(event) {
|
|||||||
/**
|
/**
|
||||||
* 确认裁剪
|
* 确认裁剪
|
||||||
*/
|
*/
|
||||||
const emit = defineEmits(['success']);
|
const emit = defineEmits(["success"]);
|
||||||
async function handleConfirm() {
|
async function handleConfirm() {
|
||||||
if (isCropperSelection.value) {
|
if (isCropperSelection.value) {
|
||||||
const res = await cropperselection.value.$toCanvas();
|
const res = await cropperselection.value.$toCanvas();
|
||||||
|
|
||||||
const dataImage = res.toDataURL('image/png');
|
const dataImage = res.toDataURL("image/png");
|
||||||
const file = dataURLtoFile(dataImage, fileObj.value.name);
|
const file = dataURLtoFile(dataImage, fileObj.value.name);
|
||||||
emit('success', {
|
emit("success", {
|
||||||
...fileObj.value,
|
...fileObj.value,
|
||||||
file: file,
|
file: file,
|
||||||
fileShow: dataImage,
|
fileShow: dataImage,
|
||||||
@@ -158,7 +158,7 @@ async function handleConfirm() {
|
|||||||
}
|
}
|
||||||
// 将data:image转成新的file
|
// 将data:image转成新的file
|
||||||
function dataURLtoFile(dataurl, filename) {
|
function dataURLtoFile(dataurl, filename) {
|
||||||
var arr = dataurl.split(','),
|
var arr = dataurl.split(","),
|
||||||
mime = arr[0].match(/:(.*?);/)[1],
|
mime = arr[0].match(/:(.*?);/)[1],
|
||||||
bstr = atob(arr[1]),
|
bstr = atob(arr[1]),
|
||||||
n = bstr.length,
|
n = bstr.length,
|
||||||
@@ -192,7 +192,7 @@ function handleUploadSuccess() {
|
|||||||
.dialog_wrap {
|
.dialog_wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
.image_wrap {
|
.image_wrap {
|
||||||
width: 400px;
|
width: 300px;
|
||||||
height: 300px;
|
height: 300px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user