feat: 裁剪

This commit is contained in:
2026-04-22 10:20:49 +08:00
parent 4394158d30
commit 19ef5b031e
2 changed files with 124 additions and 82 deletions

View File

@@ -28,7 +28,7 @@
ref="imageClipRef" ref="imageClipRef"
v-bind="$attrs" v-bind="$attrs"
:ratio="data.ratio" :ratio="data.ratio"
:fixedBox="type !== 'apparel'" :fixedBox="data.isProduct ? type !== 'apparel' : false"
:url="data.url" :url="data.url"
:type="type" :type="type"
@change="(v) => (data.preview_url = v)" @change="(v) => (data.preview_url = v)"
@@ -47,7 +47,9 @@
<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>
</div> </div>
<div class="preview-image">
<img :src="data.preview_url" /> <img :src="data.preview_url" />
</div>
<div class="submit" @click="onSubmit"> <div class="submit" @click="onSubmit">
<svg-icon name="seller-dui" size="24" /> <svg-icon name="seller-dui" size="24" />
</div> </div>
@@ -175,15 +177,22 @@ defineExpose({
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
&.is-product {
column-gap: 18.6rem; .crop-wrapper {
} width: 100%;
.tips { .tips {
text-align: center; text-align: center;
color: #585858; color: #585858;
font-size: 1.4rem; font-size: 1.4rem;
font-weight: 400; font-weight: 400;
} }
}
&.is-product {
column-gap: 18.6rem;
.crop-wrapper {
width: initial;
}
}
> .image-clip { > .image-clip {
flex: 1; flex: 1;
&.is-product { &.is-product {
@@ -194,11 +203,13 @@ defineExpose({
> .preview { > .preview {
margin-left: 6rem; margin-left: 6rem;
width: 28rem; width: 28rem;
height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: flex-start;
align-items: center; align-items: center;
gap: 2.4rem; gap: 2.4rem;
min-height: 0;
> .title { > .title {
display: flex; display: flex;
@@ -210,32 +221,42 @@ defineExpose({
font-size: 1.6rem; font-size: 1.6rem;
} }
} }
> img { > .preview-image {
width: 100%;
flex: 1;
min-height: 0;
display: flex;
align-items: center;
justify-content: center;
}
> .preview-image > img {
width: 100%; width: 100%;
height: auto; height: auto;
margin-bottom: 3rem; max-height: 100%;
}
> .submit {
margin-top: auto;
flex-shrink: 0;
} }
&.is-product { &.is-product {
margin-left: 0; margin-left: 0;
height: 100%; > .preview-image > img {
justify-content: flex-start;
img {
width: 20.8rem; width: 20.8rem;
height: 36.7rem; height: 36.7rem;
margin-bottom: 0;
box-shadow: 4px 4px 16px 0px #0000000f; box-shadow: 4px 4px 16px 0px #0000000f;
border: 1px solid #ededed; border: 1px solid #ededed;
} }
&.is-cover { &.is-cover {
img { > .preview-image > img {
// width: 29.7rem; // width: 29.7rem;
height: 37.5rem; height: 37.5rem;
} }
} }
&.is-apparel { &.is-apparel {
img { > .preview-image > img {
width: 100%;
height: auto; height: auto;
max-height: 100%;
} }
} }
} }

View File

@@ -7,15 +7,13 @@
crossOrigin="Anonymous" crossOrigin="Anonymous"
:autoCrop="true" :autoCrop="true"
:fixedNumber="ratio" :fixedNumber="ratio"
:fixed="type !== 'apparel'" :fixed="type !== 'apparel' && isProduct"
movable movable
centerBox centerBox
:fixedBox="fixedBox" :fixedBox="fixedBox"
@realTime="onChange" @realTime="onChange"
v-bind="$attrs"
outputType="png" outputType="png"
:autoCropWidth="type === 'cover' ? 297 : 242" v-bind="bindProps"
:autoCropHeight="autoCropHeight"
></VueCropper> ></VueCropper>
</div> </div>
<div class="clip_opterate"> <div class="clip_opterate">
@@ -72,6 +70,17 @@ const autoCropHeight = computed(() => {
return height return height
}) })
const bindProps = computed(() => {
// :autoCropWidth="isProduct ? undefined : type === 'cover' ? 297 : 242"
// :autoCropHeight="isProduct ? undefined : autoCropHeight"
if (props.isProduct) {
return {
autoCropHeight: autoCropHeight.value,
autoCropWidth: props.type === "cover" ? 297 : 242
}
}
})
const onChange = (data) => { const onChange = (data) => {
if (attrs.onChange) { if (attrs.onChange) {
getCropUrl().then((url) => attrs.onChange(url)) getCropUrl().then((url) => attrs.onChange(url))
@@ -95,8 +104,7 @@ const createCropLabel = ({ text, top, className }) => {
label.textContent = text label.textContent = text
label.style.top = top label.style.top = top
label.style.left = className === "label-v" ? "50%" : "0" label.style.left = className === "label-v" ? "50%" : "0"
label.style.transform = label.style.transform = className === "label-v" ? "translate(-50%, -50%)" : "translateY(-50%)"
className === "label-v" ? "translate(-50%, -50%)" : "translateY(-50%)"
return label return label
} }
@@ -126,7 +134,6 @@ const injectCropLabel = () => {
if (!cropperBox) return false if (!cropperBox) return false
clearCropLabels(cropperBox) clearCropLabels(cropperBox)
;(cropLabelMap[props.type] || []).forEach((config) => { ;(cropLabelMap[props.type] || []).forEach((config) => {
cropperBox.appendChild(createCropLabel(config)) cropperBox.appendChild(createCropLabel(config))
}) })
@@ -309,8 +316,16 @@ defineExpose({
linear-gradient(to right, #4ba5ff 50%, transparent 50%), linear-gradient(to right, #4ba5ff 50%, transparent 50%),
linear-gradient(to bottom, #4ba5ff 50%, transparent 50%); linear-gradient(to bottom, #4ba5ff 50%, transparent 50%);
background-repeat: repeat-x, repeat-x, repeat-x, repeat-y; background-repeat: repeat-x, repeat-x, repeat-x, repeat-y;
background-size: 8px 1px, 8px 1px, 8px 1px, 1px 8px; background-size:
background-position: 0 2.67%, 0 63.47%, 0 92.8%, 50% 0; 8px 1px,
8px 1px,
8px 1px,
1px 8px;
background-position:
0 2.67%,
0 63.47%,
0 92.8%,
50% 0;
} }
} }
} }
@@ -324,8 +339,14 @@ defineExpose({
linear-gradient(to right, #4ba5ff 50%, transparent 50%), linear-gradient(to right, #4ba5ff 50%, transparent 50%),
linear-gradient(to bottom, #4ba5ff 50%, transparent 50%); linear-gradient(to bottom, #4ba5ff 50%, transparent 50%);
background-repeat: repeat-x, repeat-x, repeat-y; background-repeat: repeat-x, repeat-x, repeat-y;
background-size: 8px 1px, 8px 1px, 1px 8px; background-size:
background-position: 0 2.67%, 0 97.6%, 50% 0; 8px 1px,
8px 1px,
1px 8px;
background-position:
0 2.67%,
0 97.6%,
50% 0;
} }
} }
} }