automated_uniapp/uni_modules/cool-ui/components/cl-image/cl-image.vue

179 lines
3.2 KiB
Vue
Raw Normal View History

2025-01-09 16:16:11 +08:00
<template>
<view
class="cl-image"
:style="[imgStyle, baseStyle]"
:class="[
{
'is-round': round,
'is-error': !src || isError,
},
]"
@tap="onPreview"
>
<view class="cl-image__placeholder" v-if="!src">
<slot name="placeholder">
<text class="icon cl-icon-image"></text>
</slot>
</view>
<view class="cl-image__error" v-else-if="isError">
<slot name="error">
<text class="icon cl-icon-image-error"></text>
</slot>
</view>
<template v-else>
<view class="cl-image__loading" v-if="isLoading">
<cl-loading />
</view>
<image
class="cl-image__target"
:src="src"
:mode="mode"
:lazy-load="lazyLoad"
:webp="webp"
:show-menu-by-longpress="showMenuByLongpress"
@error="handleError"
@load="handleLoad"
/>
<slot></slot>
</template>
</view>
</template>
<script lang="ts">
import { type PropType, computed, defineComponent, ref, watch } from "vue";
import { isNumber, isArray, isString, isNaN } from "lodash-es";
import { parseRpx } from "/@/cool/utils";
import { useStyle } from "../../hooks";
export default defineComponent({
name: "cl-image",
props: {
// 图片地址
src: String,
// 图片裁剪、缩放的模式
mode: {
type: String,
default: "aspectFill",
},
// 图片大小
size: {
type: [String, Number, Array],
default: "100%",
},
// 是否圆角
round: Boolean,
// 当前预览值
previewCurrent: String,
// 预览列表
previewList: Array as PropType<string[]>,
// 懒加载
lazyLoad: Boolean,
fadeShow: {
type: Boolean,
default: true,
},
webp: Boolean,
showMenuByLongpress: Boolean,
},
setup(props, { emit }) {
// 是否加载失败
const isError = ref(false);
// 是否加载中
const isLoading = ref(false);
// 样式
const imgStyle = computed(() => {
const [height, width] = size.value;
let minWidth = "0";
let minHeight = "0";
// 不是有效高
if (isNaN(parseInt(height))) {
minHeight = width;
}
// 不是有效宽
if (isNaN(parseInt(width))) {
minWidth = height;
}
return {
height,
width,
minWidth,
minHeight,
};
});
// 尺寸
const size = computed(() => {
let size: any = ["100%", "100%"];
if (isString(props.size) || isNumber(props.size)) {
size = [props.size, props.size];
} else if (isArray(props.size)) {
size = props.size;
}
return size.map(parseRpx);
});
// 加载失败
function handleError(e: Event) {
isError.value = true;
isLoading.value = false;
emit("error", e);
}
// 加载成功
function handleLoad(e: Event) {
isError.value = false;
isLoading.value = false;
emit("load", e);
}
// 点击是否预览图片
function onPreview(e: Event) {
if (props.previewList) {
uni.previewImage({
urls: props.previewList || [],
current: props.previewCurrent || props.src,
});
e.stopPropagation();
}
}
watch(
() => props.src,
(val) => {
isLoading.value = !!val;
isError.value = false;
},
{
immediate: true,
},
);
return {
isError,
isLoading,
size,
imgStyle,
handleError,
handleLoad,
onPreview,
...useStyle(),
};
},
});
</script>