mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-30 09:24:46 +08:00
feat: add cropper components
This commit is contained in:
parent
ba6e3447a7
commit
90b2ac8599
5
package-lock.json
generated
5
package-lock.json
generated
@ -562,6 +562,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.10.0.tgz",
|
||||||
"integrity": "sha512-CC582enhrFZStO4F8lGI7QL3SYx7/AIRc+IdSi3btrQGrVsTawo5K/crmKbRrQ+MOMhNX4v+PATn0k2NN6wI7A=="
|
"integrity": "sha512-CC582enhrFZStO4F8lGI7QL3SYx7/AIRc+IdSi3btrQGrVsTawo5K/crmKbRrQ+MOMhNX4v+PATn0k2NN6wI7A=="
|
||||||
},
|
},
|
||||||
|
"cropperjs": {
|
||||||
|
"version": "1.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.11.tgz",
|
||||||
|
"integrity": "sha512-SJUeBBhtNBnnn+UrLKluhFRIXLJn7XFPv8QN1j49X5t+BIMwkgvDev541f96bmu8Xe0TgCx3gON22KmY/VddaA=="
|
||||||
|
},
|
||||||
"cssesc": {
|
"cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "http://192.168.250.101:4873/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "http://192.168.250.101:4873/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"@vueuse/core": "^4.8.1",
|
"@vueuse/core": "^4.8.1",
|
||||||
"await-to-js": "^2.1.1",
|
"await-to-js": "^2.1.1",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
|
"cropperjs": "^1.5.11",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"echarts": "^5.0.2",
|
"echarts": "^5.0.2",
|
||||||
|
128
src/components/cropper/index.vue
Normal file
128
src/components/cropper/index.vue
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="$attrs.class" :style="getWrapperStyle">
|
||||||
|
<img
|
||||||
|
v-show="isReady"
|
||||||
|
ref="imgElRef"
|
||||||
|
:src="src"
|
||||||
|
:alt="alt"
|
||||||
|
:crossorigin="crossorigin"
|
||||||
|
:style="getImageStyle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import type { CSSProperties } from 'vue';
|
||||||
|
|
||||||
|
import { defineComponent, onMounted, ref, unref, computed, PropType } from 'vue';
|
||||||
|
|
||||||
|
import Cropper from 'cropperjs';
|
||||||
|
import 'cropperjs/dist/cropper.css';
|
||||||
|
|
||||||
|
type Options = Cropper.Options;
|
||||||
|
|
||||||
|
const defaultOptions: Cropper.Options = {
|
||||||
|
aspectRatio: 16 / 9,
|
||||||
|
zoomable: true,
|
||||||
|
zoomOnTouch: true,
|
||||||
|
zoomOnWheel: true,
|
||||||
|
cropBoxMovable: true,
|
||||||
|
cropBoxResizable: true,
|
||||||
|
toggleDragModeOnDblclick: true,
|
||||||
|
autoCrop: true,
|
||||||
|
background: true,
|
||||||
|
highlight: true,
|
||||||
|
center: true,
|
||||||
|
responsive: true,
|
||||||
|
restore: true,
|
||||||
|
checkCrossOrigin: true,
|
||||||
|
checkOrientation: true,
|
||||||
|
scalable: true,
|
||||||
|
modal: true,
|
||||||
|
guides: true,
|
||||||
|
movable: true,
|
||||||
|
rotatable: true,
|
||||||
|
};
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
alt: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '360px',
|
||||||
|
},
|
||||||
|
crossorigin: {
|
||||||
|
type: String,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
imageStyle: {
|
||||||
|
type: Object as PropType<CSSProperties>,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object as PropType<Options>,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props, ctx) {
|
||||||
|
const imgElRef = ref<ElRef<HTMLImageElement>>(null);
|
||||||
|
const cropper: any = ref<Nullable<Cropper>>(null);
|
||||||
|
|
||||||
|
const isReady = ref(false);
|
||||||
|
|
||||||
|
const getImageStyle = computed(
|
||||||
|
(): CSSProperties => {
|
||||||
|
return {
|
||||||
|
height: props.height,
|
||||||
|
maxWidth: '100%',
|
||||||
|
...props.imageStyle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getWrapperStyle = computed(
|
||||||
|
(): CSSProperties => {
|
||||||
|
const { height } = props;
|
||||||
|
return { height: `${height}`.replace(/px/, '') + 'px' };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
const imgEl = unref(imgElRef);
|
||||||
|
if (!imgEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cropper.value = new Cropper(imgEl, {
|
||||||
|
...defaultOptions,
|
||||||
|
ready: () => {
|
||||||
|
isReady.value = true;
|
||||||
|
},
|
||||||
|
...props.options,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// event: return base64 and width and height information after cropping
|
||||||
|
const croppered = (): void => {
|
||||||
|
let imgInfo = cropper.value.getData();
|
||||||
|
cropper.value.getCroppedCanvas().toBlob(blob => {
|
||||||
|
let fileReader: FileReader = new FileReader()
|
||||||
|
fileReader.onloadend = (e: any) => {
|
||||||
|
ctx.emit("cropperedInfo", {
|
||||||
|
imgBase64: e.target.result,
|
||||||
|
imgInfo
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fileReader.readAsDataURL(blob)
|
||||||
|
}, 'image/jpeg')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(init);
|
||||||
|
|
||||||
|
return { imgElRef, getWrapperStyle, getImageStyle, isReady, croppered };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -14,5 +14,6 @@
|
|||||||
"map": "地图组件",
|
"map": "地图组件",
|
||||||
"draggable": "拖拽组件",
|
"draggable": "拖拽组件",
|
||||||
"split-pane": "切割面板",
|
"split-pane": "切割面板",
|
||||||
"button": "按钮组件"
|
"button": "按钮组件",
|
||||||
|
"cropping": "图片裁剪"
|
||||||
}
|
}
|
@ -14,5 +14,6 @@
|
|||||||
"map": "Map Components",
|
"map": "Map Components",
|
||||||
"draggable": "Draggable Components",
|
"draggable": "Draggable Components",
|
||||||
"split-pane": "Split Pane",
|
"split-pane": "Split Pane",
|
||||||
"button": "Button Components"
|
"button": "Button Components",
|
||||||
|
"cropping": "Picture Cropping"
|
||||||
}
|
}
|
@ -76,6 +76,15 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
showLink: false,
|
showLink: false,
|
||||||
savedPosition: true
|
savedPosition: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/components/cropping',
|
||||||
|
component: () => import(/* webpackChunkName: "components" */ '../views/components/cropping/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'cropping',
|
||||||
|
showLink: false,
|
||||||
|
savedPosition: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
|
62
src/views/components/cropping/index.vue
Normal file
62
src/views/components/cropping/index.vue
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<div style="margin: 10px">
|
||||||
|
<div class="cropper-container">
|
||||||
|
<cropperImage ref="refCropper" :src="img" @cropperedInfo="cropperedInfo" style="width:45%" />
|
||||||
|
<img :src="cropperImg" class="croppered" v-if="cropperImg" />
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" @click="onCropper">裁剪</el-button>
|
||||||
|
<p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, onBeforeMount, getCurrentInstance } from "vue";
|
||||||
|
import cropperImage from "../../../components/cropper/index.vue";
|
||||||
|
import img from "./picture.jpeg";
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
cropperImage
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
let vm: any;
|
||||||
|
let info = ref("");
|
||||||
|
let cropperImg = ref("");
|
||||||
|
|
||||||
|
const onCropper = (): void => {
|
||||||
|
vm.refs.refCropper.croppered();
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
vm = getCurrentInstance();
|
||||||
|
});
|
||||||
|
|
||||||
|
function cropperedInfo({ imgBase64, imgInfo }) {
|
||||||
|
info.value = imgInfo;
|
||||||
|
cropperImg.value = imgBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
img,
|
||||||
|
info,
|
||||||
|
cropperImg,
|
||||||
|
onCropper,
|
||||||
|
cropperedInfo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cropper-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.el-button {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.croppered {
|
||||||
|
display: block;
|
||||||
|
width: 45%;
|
||||||
|
height: 360px;
|
||||||
|
}
|
||||||
|
</style>
|
BIN
src/views/components/cropping/picture.jpeg
Normal file
BIN
src/views/components/cropping/picture.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
Loading…
x
Reference in New Issue
Block a user