Files
easy-slides/packages/slidev-theme-easy-jyy/layouts/image-auto.vue
T

75 lines
2.0 KiB
Vue

<script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
import { resolveImageSource } from '../utils/resolve-image'
type ImagePlacement = 'auto' | 'left' | 'right' | 'top' | 'bottom'
const props = withDefaults(defineProps<{
image?: string
imageFit?: string
imagePosition?: string
imagePlacement?: ImagePlacement
}>(), {
imageFit: 'contain',
imagePosition: 'center',
imagePlacement: 'auto',
})
const imagePane = ref<HTMLElement>()
const detectedPlacement = ref<Exclude<ImagePlacement, 'auto'>>('right')
let observedImage: HTMLImageElement | undefined
let observer: MutationObserver | undefined
const placement = computed(() => props.imagePlacement === 'auto'
? detectedPlacement.value
: props.imagePlacement)
function detectPlacement() {
const image = imagePane.value?.querySelector<HTMLImageElement>('img')
if (!image)
return
if (observedImage !== image) {
observedImage?.removeEventListener('load', detectPlacement)
observedImage = image
observedImage.addEventListener('load', detectPlacement)
}
if (image.naturalWidth > 0 && image.naturalHeight > 0)
detectedPlacement.value = image.naturalWidth / image.naturalHeight >= 1.6 ? 'bottom' : 'right'
}
onMounted(async () => {
await nextTick()
detectPlacement()
if (imagePane.value) {
observer = new MutationObserver(detectPlacement)
observer.observe(imagePane.value, { childList: true, subtree: true })
}
})
onBeforeUnmount(() => {
observedImage?.removeEventListener('load', detectPlacement)
observer?.disconnect()
})
</script>
<template>
<div
class="slidev-layout easy-layout-image-split easy-layout-image-auto"
:class="`easy-image-${placement}`"
>
<div class="easy-image-content"><slot /></div>
<div ref="imagePane" class="easy-image-pane">
<slot name="image">
<img
v-if="image"
:src="resolveImageSource(image)"
alt=""
:style="{ objectFit: imageFit, objectPosition: imagePosition }"
>
</slot>
</div>
</div>
</template>