102 lines
1.9 KiB
Vue
102 lines
1.9 KiB
Vue
<script setup>
|
||
import { ref, onMounted, computed } from 'vue'
|
||
|
||
const props = defineProps({
|
||
src: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
alt: {
|
||
type: String,
|
||
default: '长图'
|
||
},
|
||
sliceHeight: {
|
||
type: Number,
|
||
default: 600
|
||
}
|
||
})
|
||
|
||
const imgLoaded = ref(false)
|
||
const naturalWidth = ref(0)
|
||
const naturalHeight = ref(0)
|
||
const containerWidth = ref(0)
|
||
|
||
const handleLoad = (e) => {
|
||
imgLoaded.value = true
|
||
naturalWidth.value = e.target.naturalWidth
|
||
naturalHeight.value = e.target.naturalHeight
|
||
}
|
||
|
||
const handleContainerResize = (el) => {
|
||
containerWidth.value = el.getBoundingClientRect().width
|
||
}
|
||
|
||
const slices = computed(() => {
|
||
if (!imgLoaded.value) return []
|
||
const count = Math.ceil(naturalHeight.value / props.sliceHeight)
|
||
const arr = []
|
||
for (let i = 0; i < count; i++) {
|
||
arr.push({
|
||
top: i * props.sliceHeight,
|
||
height: Math.min(props.sliceHeight, naturalHeight.value - i * props.sliceHeight)
|
||
})
|
||
}
|
||
return arr
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div
|
||
class="long-pic-img-split"
|
||
@resize="handleContainerResize($event.target)"
|
||
>
|
||
<!-- 用于获取尺寸 -->
|
||
<img
|
||
:src="src"
|
||
:alt="alt"
|
||
@load="handleLoad"
|
||
class="img-hidden"
|
||
>
|
||
|
||
<!-- 正常分段显示,宽度100%,不会被放大 -->
|
||
<img
|
||
v-for="(item, idx) in slices"
|
||
:key="idx"
|
||
:src="src"
|
||
:alt="`${alt}-${idx + 1}`"
|
||
class="split-img"
|
||
:style="{
|
||
height: `${item.height}px`,
|
||
objectPosition: `center ${-item.top}px`,
|
||
}"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.long-pic-img-split {
|
||
width: 100%;
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.img-hidden {
|
||
position: absolute;
|
||
width: 100%;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.split-img {
|
||
display: block;
|
||
width: 100% !important;
|
||
max-width: 100% !important;
|
||
object-fit: cover;
|
||
object-position: top center;
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
</style>
|