图片裁剪不行
This commit is contained in:
Generated
+138
@@ -12,9 +12,11 @@
|
|||||||
"@tabler/icons-vue": "^3.35.0",
|
"@tabler/icons-vue": "^3.35.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
|
"cropperjs": "^2.1.0",
|
||||||
"litepicker": "^2.0.12",
|
"litepicker": "^2.0.12",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
|
"vue-cropper": "^0.6.5",
|
||||||
"vue-i18n": "^11.1.12",
|
"vue-i18n": "^11.1.12",
|
||||||
"vue-router": "^4.6.3"
|
"vue-router": "^4.6.3"
|
||||||
},
|
},
|
||||||
@@ -483,6 +485,126 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@cropper/element": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element/-/element-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-2zELddqHQNmlvkPoiYzE5nxEjPE+C8nXoTPuvV3FvLp3YjBinc7qb73Icg9UXP0o9qC4+h9q96JgGo0AyMO/Ng==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-canvas": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-canvas/-/element-canvas-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-el+rfJpZxsD2q5XxDBA4fRczcrOqB65Lb7roqXOq8LKufwf4bPWA9C6DjNJJahh/TP94dsLIEy3tSkgRMDv3Aw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-crosshair": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-crosshair/-/element-crosshair-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-0V589dAx8uZAfvJwdINLn76gfPQEafPH94ukjJ76uX0FCUovLaAVX+VRD/MDSYn0Mza/xejzmL9Dhd1DfemvmA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-grid": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-grid/-/element-grid-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-dEnk0rO+vp553LMvsPYgfrqVFcYXeVFrgFeavBYYEhAXtO40p7kN4rmLYLMMjaN+T/Mx2BATv6kUQpALKy2HLw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-handle": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-handle/-/element-handle-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-8BklWA4C/2GGAULupIWleSnGutECvYt3vx9flodqDfZpDEozws4LgLqmmzVuQmVkRVUdLnXdtx28kjgWLtzkHg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-image": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-image/-/element-image-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-mXOV8ixJvG0XtTxLebYAKDjEkFbFOQnsF02hXPZk1yQSV0J+LLhN7a2NePrtKnoTsEV19fhhX3UorMoyGGxvzg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/element-canvas": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-selection": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-selection/-/element-selection-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-mtFtBl6HIa/s9TWohXw+Z5eJoeYTqylrIcHvS7oVv0uM7IyeRwBW65Q7z+KtLfq/LW+2Sw/XDyvR+VN/DawBPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/element-canvas": "^2.1.0",
|
||||||
|
"@cropper/element-image": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-shade": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-shade/-/element-shade-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-zMdyqbb0lc0Vd1oj2Z1miIZvhyZG41OXMHvrNt0hNwblh0dVdrvtw48lnFDgRv+672vt2CNx7Q04GuvCQfPlgg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/element-canvas": "^2.1.0",
|
||||||
|
"@cropper/element-selection": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/element-viewer": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/element-viewer/-/element-viewer-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-XnxlQuqHitd1FOFZ6E0yXAF5NYd/LyIvONLLHI9p1rJw747WYKUPxQaSYtFKF7IOizJu/8mMj++Zc1dZ5ZP3YQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/element-canvas": "^2.1.0",
|
||||||
|
"@cropper/element-image": "^2.1.0",
|
||||||
|
"@cropper/element-selection": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/elements": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/elements/-/elements-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qvzlYDn3VQgPPpsCu6Gi1XUO0v3vpXQFSjjxcVijbXeNsl/eiKrN7H9/CEiRgi5vr8kXfd7ZvgYxBjUBbH+y+w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/element": "^2.1.0",
|
||||||
|
"@cropper/element-canvas": "^2.1.0",
|
||||||
|
"@cropper/element-crosshair": "^2.1.0",
|
||||||
|
"@cropper/element-grid": "^2.1.0",
|
||||||
|
"@cropper/element-handle": "^2.1.0",
|
||||||
|
"@cropper/element-image": "^2.1.0",
|
||||||
|
"@cropper/element-selection": "^2.1.0",
|
||||||
|
"@cropper/element-shade": "^2.1.0",
|
||||||
|
"@cropper/element-viewer": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@cropper/utils": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cropper/utils/-/utils-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-wLtpZ4/UWgo+fGmG8NBWge8x5ehjfDe9ovleDfLy8kpwFaw43XXOEXQtRL1UNr0u4JZxaeO8FcXcolRWUUrlRQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.25.12",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||||
@@ -1843,6 +1965,16 @@
|
|||||||
"url": "https://github.com/sponsors/mesqueeb"
|
"url": "https://github.com/sponsors/mesqueeb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cropperjs": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-SsSDqdVRl+mjbIBkGWlk1gCGcc+HzBqCbH5EQ+1tkAFUdxq2KUGukXF1RqhmvXrrdrX7PDwSUkWgXS7E36KvGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cropper/elements": "^2.1.0",
|
||||||
|
"@cropper/utils": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
@@ -2999,6 +3131,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-cropper": {
|
||||||
|
"version": "0.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-cropper/-/vue-cropper-0.6.5.tgz",
|
||||||
|
"integrity": "sha512-lSvY6IpeA/Tv/iPZ/FOkMHVRBPSlm7t57nuHEZFBMRNOH8ElvfqVlnHGDOAMlvPhh9gHiddiQoASS+fY0MFX0g==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/vue-i18n": {
|
"node_modules/vue-i18n": {
|
||||||
"version": "11.1.12",
|
"version": "11.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.1.12.tgz",
|
||||||
|
|||||||
@@ -16,9 +16,11 @@
|
|||||||
"@tabler/icons-vue": "^3.35.0",
|
"@tabler/icons-vue": "^3.35.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
|
"cropperjs": "^2.1.0",
|
||||||
"litepicker": "^2.0.12",
|
"litepicker": "^2.0.12",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
|
"vue-cropper": "^0.6.5",
|
||||||
"vue-i18n": "^11.1.12",
|
"vue-i18n": "^11.1.12",
|
||||||
"vue-router": "^4.6.3"
|
"vue-router": "^4.6.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ defineExpose({
|
|||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
placeholder="Select a date"
|
:placeholder="t('message.select_date')"
|
||||||
ref="datepicker"
|
ref="datepicker"
|
||||||
value=""
|
value=""
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
<template>
|
||||||
|
<div class="image-cropper">
|
||||||
|
<div class="cropper-actions">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
ref="fileInput"
|
||||||
|
@change="handleFileSelect"
|
||||||
|
accept="image/*"
|
||||||
|
style="display: none"
|
||||||
|
/>
|
||||||
|
<button @click="$refs.fileInput.click()">选择图片</button>
|
||||||
|
|
||||||
|
<div v-if="haveImageSrc" class="action-buttons">
|
||||||
|
<button @click="setAspectRatio(1)">1:1</button>
|
||||||
|
<button @click="setAspectRatio(16 / 9)">16:9</button>
|
||||||
|
<button @click="setAspectRatio(4 / 3)">4:3</button>
|
||||||
|
<button @click="rotate(-90)">↺</button>
|
||||||
|
<button @click="rotate(90)">↻</button>
|
||||||
|
<button @click="crop">裁剪</button>
|
||||||
|
<button @click="reset">重置</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="haveImageSrc" class="cropper-container">
|
||||||
|
<img ref="imageEl" alt="裁剪图片" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, nextTick } from "vue";
|
||||||
|
import Cropper from "cropperjs";
|
||||||
|
|
||||||
|
const emit = defineEmits(["cropped", "error"]);
|
||||||
|
|
||||||
|
const imageEl = ref(null);
|
||||||
|
const fileInput = ref(null);
|
||||||
|
const haveImageSrc = ref(false);
|
||||||
|
const resultImage = ref("");
|
||||||
|
let cropperInstance = null;
|
||||||
|
|
||||||
|
// 读取文件为DataURL
|
||||||
|
const readFileAsDataURL = (file) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => resolve(e.target.result);
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择文件
|
||||||
|
const handleFileSelect = async (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
if (!file.type.startsWith("image/")) {
|
||||||
|
emit("error", "请选择图片文件");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("选择了文件:", file.name);
|
||||||
|
try {
|
||||||
|
const dataUrl = await readFileAsDataURL(file);
|
||||||
|
haveImageSrc.value = true;
|
||||||
|
console.log("图片加载完成,初始化裁剪器");
|
||||||
|
await nextTick();
|
||||||
|
if (cropperInstance) {
|
||||||
|
cropperInstance.destroy();
|
||||||
|
console.log("销毁旧的Cropper实例");
|
||||||
|
}
|
||||||
|
console.log("加载图片进行裁剪");
|
||||||
|
imageEl.value.src = dataUrl;
|
||||||
|
|
||||||
|
cropperInstance = new Cropper(imageEl.value, {
|
||||||
|
aspectRatio: 1,
|
||||||
|
viewMode: 2,
|
||||||
|
autoCropArea: 0.8,
|
||||||
|
zoomable: true,
|
||||||
|
zoomOnWheel: true,
|
||||||
|
zoomOnTouch: true,
|
||||||
|
wheelZoomRatio: 0.1,
|
||||||
|
ready: function () {
|
||||||
|
console.log("Cropper 初始化成功");
|
||||||
|
},
|
||||||
|
crop: function (event) {
|
||||||
|
// 可以在这里获取裁剪区域的信息
|
||||||
|
console.log(event.detail);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
emit("error", "图片加载失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.image-cropper {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-actions {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons button {
|
||||||
|
margin: 0 5px 5px 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-container {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-container img {
|
||||||
|
max-width: 300px;
|
||||||
|
max-height: 300px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -45,7 +45,8 @@
|
|||||||
"user_home": "Profile",
|
"user_home": "Profile",
|
||||||
"user_settings": "Settings",
|
"user_settings": "Settings",
|
||||||
"preferences": "Preferences",
|
"preferences": "Preferences",
|
||||||
"administrator": "Administrator"
|
"administrator": "Administrator",
|
||||||
|
"select_date":"Select a date"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"account_settings": "Account Settings",
|
"account_settings": "Account Settings",
|
||||||
|
|||||||
@@ -45,7 +45,8 @@
|
|||||||
"user_home": "个人主页",
|
"user_home": "个人主页",
|
||||||
"user_settings": "个人资料",
|
"user_settings": "个人资料",
|
||||||
"preferences": "偏好设置",
|
"preferences": "偏好设置",
|
||||||
"administrator": "管理员"
|
"administrator": "管理员",
|
||||||
|
"select_date":"选择日期"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"account_settings": "个人设置",
|
"account_settings": "个人设置",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ref } from "vue";
|
|||||||
import { my_network_func } from "@/my_network_func";
|
import { my_network_func } from "@/my_network_func";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import MyOffcanvas from "@/components/MyOffcanvas.vue";
|
import MyOffcanvas from "@/components/MyOffcanvas.vue";
|
||||||
|
import imageCropper from "@/components/imageCropper.vue";
|
||||||
const user = useUserStore();
|
const user = useUserStore();
|
||||||
const mos = ref();
|
const mos = ref();
|
||||||
|
|
||||||
@@ -32,5 +33,6 @@ function tt(){
|
|||||||
<button @click="tt">333</button>
|
<button @click="tt">333</button>
|
||||||
{{ user.userInfo }}
|
{{ user.userInfo }}
|
||||||
</main>
|
</main>
|
||||||
|
<imageCropper />
|
||||||
<MyOffcanvas ref="mos" />
|
<MyOffcanvas ref="mos" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { onMounted, watch, ref } from "vue";
|
|||||||
import settingNavigation from "@/components/settingNavigation.vue";
|
import settingNavigation from "@/components/settingNavigation.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import datePicker from "@/components/datePicker.vue";
|
import datePicker from "@/components/datePicker.vue";
|
||||||
|
import imageCropper from "@/components/imageCropper.vue";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const birthday = ref();
|
const birthday = ref();
|
||||||
@@ -46,6 +47,13 @@ function updataInfo() {
|
|||||||
console.log("备注:", userremarkValue);
|
console.log("备注:", userremarkValue);
|
||||||
console.log("生日:", birthdayValue);
|
console.log("生日:", birthdayValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
//console.log("account mounted");
|
||||||
|
//username.value.value="Kevin";
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -74,6 +82,7 @@ function updataInfo() {
|
|||||||
style="background-image: url(./static/avatars/000m.jpg)"
|
style="background-image: url(./static/avatars/000m.jpg)"
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
|
<imageCropper />
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<button class="btn">
|
<button class="btn">
|
||||||
{{ t("settings.change_avatar") }}
|
{{ t("settings.change_avatar") }}
|
||||||
|
|||||||
Reference in New Issue
Block a user