feat: 图片裁剪组件
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal
|
||||||
class="image-clip-dialog generalModel"
|
class="image-clip-dialog generalModel"
|
||||||
|
:class="{ 'is-product': data.isProduct }"
|
||||||
v-model:visible="show"
|
v-model:visible="show"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
width="70%"
|
width="70%"
|
||||||
@@ -25,10 +26,19 @@
|
|||||||
ref="imageClipRef"
|
ref="imageClipRef"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:ratio="data.ratio"
|
:ratio="data.ratio"
|
||||||
|
:fixedBox="type !== 'apparel'"
|
||||||
:url="data.url"
|
:url="data.url"
|
||||||
@change="(v) => (data.preview_url = v)"
|
@change="(v) => (data.preview_url = v)"
|
||||||
/>
|
/>
|
||||||
<div class="preview" v-if="data.isPreview">
|
<div
|
||||||
|
class="preview"
|
||||||
|
:class="{
|
||||||
|
'is-product': data.isProduct,
|
||||||
|
'is-apprael': type === 'apprael',
|
||||||
|
'is-cover': type === 'cover'
|
||||||
|
}"
|
||||||
|
v-if="data.isPreview"
|
||||||
|
>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span class="icon"><svg-icon name="seller-preview" size="24" /></span>
|
<span class="icon"><svg-icon name="seller-preview" size="24" /></span>
|
||||||
<span class="label">Crop Preview</span>
|
<span class="label">Crop Preview</span>
|
||||||
@@ -46,27 +56,35 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
import ImageClip from "./image-clip.vue"
|
import ImageClip from "./image-clip.vue"
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: () => false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
url: "",
|
url: "",
|
||||||
title: "Crop Image",
|
title: "Crop Image",
|
||||||
preview_url: "",
|
preview_url: "",
|
||||||
ratio: [1, 1],
|
ratio: [1, 1],
|
||||||
isPreview: true,
|
isPreview: true,
|
||||||
callback: null
|
callback: null,
|
||||||
|
isProduct: false // 是否商品编辑
|
||||||
})
|
})
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
const open = (url, callback, options) => {
|
const open = (url, callback, options) => {
|
||||||
if (!url || !callback) return
|
if (!url || !callback) return
|
||||||
data.url = url
|
data.url = url
|
||||||
data.callback = callback
|
data.callback = callback
|
||||||
data.ratio = [1, 1]
|
data.ratio = options.ratio || [1, 1]
|
||||||
data.isPreview = true
|
data.isPreview = true
|
||||||
data.preview_url = ""
|
data.preview_url = ""
|
||||||
data.title = "Crop Image"
|
data.title = options.title || "Crop Image"
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options.hasOwnProperty("isPreview")) data.isPreview = options.isPreview
|
if (options.hasOwnProperty("isPreview")) data.isPreview = options.isPreview
|
||||||
if (options.hasOwnProperty("ratio")) data.ratio = options.ratio
|
data.isProduct = options.isProduct
|
||||||
if (options.hasOwnProperty("title")) data.title = options.title
|
|
||||||
}
|
}
|
||||||
show.value = true
|
show.value = true
|
||||||
}
|
}
|
||||||
@@ -137,6 +155,10 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
> .image-clip {
|
> .image-clip {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
&.is-product {
|
||||||
|
width: initial;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
> .preview {
|
> .preview {
|
||||||
margin-left: 6rem;
|
margin-left: 6rem;
|
||||||
@@ -146,6 +168,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 2.4rem;
|
gap: 2.4rem;
|
||||||
|
|
||||||
> .title {
|
> .title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -161,6 +184,25 @@
|
|||||||
height: auto;
|
height: auto;
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
&.is-product {
|
||||||
|
margin-left: 0;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
justify-content: flex-start;
|
||||||
|
img {
|
||||||
|
width: 20.8rem;
|
||||||
|
height: 36.7rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
box-shadow: 4px 4px 16px 0px #0000000f;
|
||||||
|
border: 1px solid #ededed;
|
||||||
|
}
|
||||||
|
&.is-cover{
|
||||||
|
img{
|
||||||
|
// width: 29.7rem;
|
||||||
|
// height: 37.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
fixed
|
fixed
|
||||||
movable
|
movable
|
||||||
centerBox
|
centerBox
|
||||||
|
:fixedBox="fixedBox"
|
||||||
@realTime="onChange"
|
@realTime="onChange"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
outputType="png"
|
outputType="png"
|
||||||
@@ -50,6 +51,10 @@ const props = defineProps({
|
|||||||
isProduct: {
|
isProduct: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
fixedBox: {
|
||||||
|
type: Boolean,
|
||||||
|
default:true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<div
|
<div
|
||||||
v-if="previewImageMap[type]"
|
v-if="previewImageMap[type]"
|
||||||
class="crop-tool flex flex-center"
|
class="crop-tool flex flex-center"
|
||||||
@click="handleClickCrop(previewImageMap[type])"
|
@click="handleClickCrop(previewImageMap[type], type)"
|
||||||
>
|
>
|
||||||
<SvgIcon name="CCrop" color="#fff" size="12" />
|
<SvgIcon name="CCrop" color="#fff" size="12" />
|
||||||
</div>
|
</div>
|
||||||
@@ -128,7 +128,10 @@
|
|||||||
class="sketch-element flex flex-center"
|
class="sketch-element flex flex-center"
|
||||||
>
|
>
|
||||||
<img class="img-src" :src="item.url" alt="" />
|
<img class="img-src" :src="item.url" alt="" />
|
||||||
<div class="crop-tool flex flex-center">
|
<div
|
||||||
|
class="crop-tool flex flex-center"
|
||||||
|
@click="handleClickCrop(item.url, 'apparel')"
|
||||||
|
>
|
||||||
<SvgIcon name="CCrop" color="#fff" size="12" />
|
<SvgIcon name="CCrop" color="#fff" size="12" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -222,6 +225,8 @@
|
|||||||
isProduct
|
isProduct
|
||||||
:info="false"
|
:info="false"
|
||||||
:autoCropWidth="90"
|
:autoCropWidth="90"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:type="cropType"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -394,14 +399,21 @@ const handleSelectProdImg = (index: number) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClickCrop = (data) => {
|
const cropType = ref("")
|
||||||
console.log(data)
|
const handleClickCrop = (data, type) => {
|
||||||
|
console.log(data, type)
|
||||||
|
const titleList = {
|
||||||
|
sketch: "Crop Sketch",
|
||||||
|
mainProductImage: "Crop Main Product Image",
|
||||||
|
cover: "Crop Cover"
|
||||||
|
}
|
||||||
|
cropType.value = type
|
||||||
imageClipDialogRef.value.open(
|
imageClipDialogRef.value.open(
|
||||||
data,
|
data,
|
||||||
(file) => {
|
(file) => {
|
||||||
selectList.value[currentIndex.value].sketch = URL.createObjectURL(file)
|
selectList.value[currentIndex.value].sketch = URL.createObjectURL(file)
|
||||||
},
|
},
|
||||||
{ ratio: [9, 16], isPreview: true, title: "Crop Brand Banner" }
|
{ ratio: [9, 16], isPreview: true, title: titleList[type], isProduct: true }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user