Add sample images section for quick background removal experience

- Add horizontal scrollable sample images gallery below upload area
- Implement click handler to load and process sample images
- Add 10 sample images with 1024x1024 resolution for better quality
- Style thumbnails with hover effects and centered layout
- Ensure symmetric padding and responsive design
This commit is contained in:
jingrow 2025-12-21 19:24:36 +08:00
parent 37350a07e1
commit ea6d1b218c

View File

@ -223,6 +223,60 @@ const isDragging = ref(false)
const dragCounter = ref(0)
const processing = ref(false)
const splitPosition = ref(0)
// - 使
const sampleImages = [
{
id: 'sample-1',
url: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=1024&h=1024&fit=crop&q=80',
name: '人物示例'
},
{
id: 'sample-2',
url: 'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?w=1024&h=1024&fit=crop&q=80',
name: '人物示例'
},
{
id: 'sample-3',
url: 'https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=1024&h=1024&fit=crop&q=80',
name: '产品示例'
},
{
id: 'sample-4',
url: 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=1024&h=1024&fit=crop&q=80',
name: '产品示例'
},
{
id: 'sample-5',
url: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1024&h=1024&fit=crop&q=80',
name: '动物示例'
},
{
id: 'sample-6',
url: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e?w=1024&h=1024&fit=crop&q=80',
name: '物品示例'
},
{
id: 'sample-7',
url: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=1024&h=1024&fit=crop&q=80',
name: '人物示例'
},
{
id: 'sample-8',
url: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=1024&h=1024&fit=crop&q=80',
name: '人物示例'
},
{
id: 'sample-9',
url: 'https://images.unsplash.com/photo-1517841905240-472988babdf9?w=1024&h=1024&fit=crop&q=80',
name: '人物示例'
},
{
id: 'sample-10',
url: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=1024&h=1024&fit=crop&q=80',
name: '人物示例'
}
]
const comparisonContainerRef = ref<HTMLElement | null>(null)
const originalImageRef = ref<HTMLImageElement | null>(null)
const resultImageRef = ref<HTMLImageElement | null>(null)
@ -324,6 +378,54 @@ const processFile = async (file: File) => {
}
}
//
const handleSampleImageClick = async (imageUrl: string) => {
if (processing.value) return
processing.value = true
try {
const response = await fetch(imageUrl, { mode: 'cors' })
if (!response.ok) {
throw new Error(`Failed to load image: ${response.status}`)
}
const blob = await response.blob()
//
const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
if (!validTypes.includes(blob.type)) {
message.warning('不支持的图片格式')
processing.value = false
return
}
//
const maxSize = 10 * 1024 * 1024
if (blob.size > maxSize) {
message.warning('图片大小超过 10MB 限制')
processing.value = false
return
}
// File
const file = new File([blob], 'sample-image.jpg', { type: blob.type })
await processFile(file)
} catch (error: any) {
console.error('加载示例图片失败:', error)
let errorMessage = '加载示例图片失败'
if (error.message?.includes('CORS')) {
errorMessage = '图片服务器不允许跨域访问'
} else if (error.message?.includes('Failed to load')) {
errorMessage = '加载图片失败,请稍后重试'
}
message.error(errorMessage)
processing.value = false
}
}
const handleRemoveBackground = async () => {
if (!uploadedImage.value) {
message.warning('请先上传图片')
@ -893,6 +995,27 @@ onUnmounted(() => {
</div>
</div>
</div>
<!-- 示例图片区块 -->
<div v-if="!uploadedImage" class="sample-images-section">
<p class="sample-images-title">快速体验</p>
<div class="sample-images-container">
<div
v-for="sample in sampleImages"
:key="sample.id"
class="sample-image-item"
@click="handleSampleImageClick(sample.url)"
:class="{ loading: processing }"
>
<div class="sample-image-wrapper">
<img :src="sample.url" :alt="sample.name" loading="lazy" />
<div class="sample-image-overlay">
<Icon icon="tabler:wand" class="overlay-icon" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -1311,6 +1434,122 @@ onUnmounted(() => {
min-height: 600px; /* 设置最小高度确保容器足够大 */
}
/* 示例图片区块 */
.sample-images-section {
margin-top: 24px;
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
border: 1px solid #e5e7eb;
}
.sample-images-title {
font-size: 14px;
font-weight: 600;
color: #64748b;
margin: 0 0 16px 0;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.sample-images-container {
display: flex;
gap: 16px;
overflow-x: auto;
overflow-y: hidden;
padding: 0;
padding-bottom: 8px;
justify-content: center;
scrollbar-width: thin;
scrollbar-color: #cbd5e1 transparent;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
height: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 3px;
&:hover {
background: #94a3b8;
}
}
}
.sample-image-item {
flex-shrink: 0;
width: 100px;
height: 100px;
cursor: pointer;
position: relative;
padding: 4px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
transform: translateY(-4px);
.sample-image-overlay {
opacity: 1;
}
}
&.loading {
pointer-events: none;
opacity: 0.6;
}
}
.sample-image-wrapper {
width: 100%;
height: 100%;
position: relative;
background: #f1f5f9;
border: 2px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.sample-image-item:hover & {
border-color: #1fc76f;
box-shadow: 0 8px 16px rgba(31, 199, 111, 0.2);
}
}
.sample-image-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(31, 199, 111, 0.9), rgba(13, 104, 75, 0.9));
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
.overlay-icon {
font-size: 32px;
color: white;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
}
.upload-section {
flex: 1;
display: flex;
@ -1973,6 +2212,25 @@ onUnmounted(() => {
padding: 8px 12px;
}
.sample-images-section {
padding: 16px;
margin-top: 16px;
}
.sample-images-title {
font-size: 12px;
margin-bottom: 12px;
}
.sample-image-item {
width: 100px;
height: 100px;
}
.sample-image-overlay .overlay-icon {
font-size: 24px;
}
.upload-section {
padding: 16px;
}