|
|
@@ -1,25 +1,17 @@
|
|
|
<template>
|
|
|
<div
|
|
|
- ref="wrapperRef"
|
|
|
v-if="getImgSrc"
|
|
|
class="w-full h-full absolute left-0 top-0 z-0 overflow-hidden flex items-center justify-center"
|
|
|
:style="{ opacity: imageStyle?.opacity }"
|
|
|
v-bind="$attrs"
|
|
|
>
|
|
|
- <img v-bind="imageProps" class="absolute z-0" :src="getImgSrc" />
|
|
|
- <img
|
|
|
- v-bind="imageProps"
|
|
|
- ref="imgRef"
|
|
|
- class="absolute z-1"
|
|
|
- :src="getImgSrc"
|
|
|
- :style="shadowImageStyle"
|
|
|
- />
|
|
|
+ <img v-bind="imageProps" ref="imgRef" class="absolute z-0" :src="getImgSrc" />
|
|
|
+ <div v-if="hasCoverColor" class="absolute z-1 pointer-events-none" :style="maskStyle"></div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, computed, ImgHTMLAttributes } from 'vue'
|
|
|
-import { CSSProperties } from 'vue'
|
|
|
+import { ref, computed, type CSSProperties, type ImgHTMLAttributes } from 'vue'
|
|
|
import { useElementSize } from '@vueuse/core'
|
|
|
import { useProjectStore } from '@/store/modules/project'
|
|
|
|
|
|
@@ -34,23 +26,44 @@ defineOptions({
|
|
|
inheritAttrs: false
|
|
|
})
|
|
|
|
|
|
-const wrapperRef = ref<HTMLDivElement>()
|
|
|
const imgRef = ref<HTMLImageElement>()
|
|
|
const projectStore = useProjectStore()
|
|
|
|
|
|
-const wrapperSize = useElementSize(wrapperRef)
|
|
|
const imgSize = useElementSize(imgRef)
|
|
|
|
|
|
// 图片覆盖色样式
|
|
|
-const shadowImageStyle = computed((): CSSProperties => {
|
|
|
- const color = props.imageStyle?.backgroundColor
|
|
|
- const offsetX = wrapperSize.width.value / 2 + imgSize.width.value / 2
|
|
|
+const getCssSize = (value: unknown, fallback: number) => {
|
|
|
+ if (value === undefined || value === null || value === '') {
|
|
|
+ return fallback ? `${fallback}px` : undefined
|
|
|
+ }
|
|
|
+ return typeof value === 'number' ? `${value}px` : String(value)
|
|
|
+}
|
|
|
+
|
|
|
+const getStyleObject = (style: unknown): CSSProperties => {
|
|
|
+ return style && typeof style === 'object' && !Array.isArray(style) ? (style as CSSProperties) : {}
|
|
|
+}
|
|
|
+
|
|
|
+const getCssUrl = (url: string) => `url("${url.replace(/"/g, '\\"')}")`
|
|
|
+
|
|
|
+const hasCoverColor = computed(() => !!props.imageStyle?.backgroundColor)
|
|
|
+
|
|
|
+const maskStyle = computed((): CSSProperties => {
|
|
|
+ const imageUrl = getCssUrl(getImgSrc.value || '')
|
|
|
+ const imagePropStyle = getStyleObject(props.imageProps?.style)
|
|
|
+
|
|
|
return {
|
|
|
- height: 'inherit',
|
|
|
- maxWidth: `${wrapperSize.width.value}px`,
|
|
|
- maxHeight: `${wrapperSize.height.value}px`,
|
|
|
- filter: `drop-shadow(${offsetX}px 0px 0 ${color || 'transparent'})`,
|
|
|
- left: `-${imgSize.width.value}px`
|
|
|
+ ...imagePropStyle,
|
|
|
+ width: getCssSize(props.imageProps?.width, imgSize.width.value),
|
|
|
+ height: getCssSize(props.imageProps?.height, imgSize.height.value),
|
|
|
+ backgroundColor: props.imageStyle?.backgroundColor,
|
|
|
+ maskImage: imageUrl,
|
|
|
+ WebkitMaskImage: imageUrl,
|
|
|
+ maskSize: '100% 100%',
|
|
|
+ WebkitMaskSize: '100% 100%',
|
|
|
+ maskPosition: 'center',
|
|
|
+ WebkitMaskPosition: 'center',
|
|
|
+ maskRepeat: 'no-repeat',
|
|
|
+ WebkitMaskRepeat: 'no-repeat'
|
|
|
}
|
|
|
})
|
|
|
|