175 lines
4.7 KiB
JavaScript
175 lines
4.7 KiB
JavaScript
import { ref, watch, computed, nextTick, onMounted, onBeforeUnmount, defineComponent, getCurrentInstance, createVNode as _createVNode, resolveDirective as _resolveDirective, mergeProps as _mergeProps, withDirectives as _withDirectives } from "vue";
|
|
import { isDef, addUnit, inBrowser, truthProp, numericProp, makeStringProp, createNamespace } from "../utils/index.mjs";
|
|
import { Icon } from "../icon/index.mjs";
|
|
const [name, bem] = createNamespace("image");
|
|
const imageProps = {
|
|
src: String,
|
|
alt: String,
|
|
fit: String,
|
|
position: String,
|
|
round: Boolean,
|
|
block: Boolean,
|
|
width: numericProp,
|
|
height: numericProp,
|
|
radius: numericProp,
|
|
lazyLoad: Boolean,
|
|
iconSize: numericProp,
|
|
showError: truthProp,
|
|
errorIcon: makeStringProp("photo-fail"),
|
|
iconPrefix: String,
|
|
showLoading: truthProp,
|
|
loadingIcon: makeStringProp("photo"),
|
|
crossorigin: String,
|
|
referrerpolicy: String
|
|
};
|
|
var stdin_default = defineComponent({
|
|
name,
|
|
props: imageProps,
|
|
emits: ["load", "error"],
|
|
setup(props, {
|
|
emit,
|
|
slots
|
|
}) {
|
|
const error = ref(false);
|
|
const loading = ref(true);
|
|
const imageRef = ref();
|
|
const {
|
|
$Lazyload
|
|
} = getCurrentInstance().proxy;
|
|
const style = computed(() => {
|
|
const style2 = {
|
|
width: addUnit(props.width),
|
|
height: addUnit(props.height)
|
|
};
|
|
if (isDef(props.radius)) {
|
|
style2.overflow = "hidden";
|
|
style2.borderRadius = addUnit(props.radius);
|
|
}
|
|
return style2;
|
|
});
|
|
watch(() => props.src, () => {
|
|
error.value = false;
|
|
loading.value = true;
|
|
});
|
|
const onLoad = (event) => {
|
|
if (loading.value) {
|
|
loading.value = false;
|
|
emit("load", event);
|
|
}
|
|
};
|
|
const triggerLoad = () => {
|
|
const loadEvent = new Event("load");
|
|
Object.defineProperty(loadEvent, "target", {
|
|
value: imageRef.value,
|
|
enumerable: true
|
|
});
|
|
onLoad(loadEvent);
|
|
};
|
|
const onError = (event) => {
|
|
error.value = true;
|
|
loading.value = false;
|
|
emit("error", event);
|
|
};
|
|
const renderIcon = (name2, className, slot) => {
|
|
if (slot) {
|
|
return slot();
|
|
}
|
|
return _createVNode(Icon, {
|
|
"name": name2,
|
|
"size": props.iconSize,
|
|
"class": className,
|
|
"classPrefix": props.iconPrefix
|
|
}, null);
|
|
};
|
|
const renderPlaceholder = () => {
|
|
if (loading.value && props.showLoading) {
|
|
return _createVNode("div", {
|
|
"class": bem("loading")
|
|
}, [renderIcon(props.loadingIcon, bem("loading-icon"), slots.loading)]);
|
|
}
|
|
if (error.value && props.showError) {
|
|
return _createVNode("div", {
|
|
"class": bem("error")
|
|
}, [renderIcon(props.errorIcon, bem("error-icon"), slots.error)]);
|
|
}
|
|
};
|
|
const renderImage = () => {
|
|
if (error.value || !props.src) {
|
|
return;
|
|
}
|
|
const attrs = {
|
|
alt: props.alt,
|
|
class: bem("img"),
|
|
style: {
|
|
objectFit: props.fit,
|
|
objectPosition: props.position
|
|
},
|
|
crossorigin: props.crossorigin,
|
|
referrerpolicy: props.referrerpolicy
|
|
};
|
|
if (props.lazyLoad) {
|
|
return _withDirectives(_createVNode("img", _mergeProps({
|
|
"ref": imageRef
|
|
}, attrs), null), [[_resolveDirective("lazy"), props.src]]);
|
|
}
|
|
return _createVNode("img", _mergeProps({
|
|
"ref": imageRef,
|
|
"src": props.src,
|
|
"onLoad": onLoad,
|
|
"onError": onError
|
|
}, attrs), null);
|
|
};
|
|
const onLazyLoaded = ({
|
|
el
|
|
}) => {
|
|
const check = () => {
|
|
if (el === imageRef.value && loading.value) {
|
|
triggerLoad();
|
|
}
|
|
};
|
|
if (imageRef.value) {
|
|
check();
|
|
} else {
|
|
nextTick(check);
|
|
}
|
|
};
|
|
const onLazyLoadError = ({
|
|
el
|
|
}) => {
|
|
if (el === imageRef.value && !error.value) {
|
|
onError();
|
|
}
|
|
};
|
|
if ($Lazyload && inBrowser) {
|
|
$Lazyload.$on("loaded", onLazyLoaded);
|
|
$Lazyload.$on("error", onLazyLoadError);
|
|
onBeforeUnmount(() => {
|
|
$Lazyload.$off("loaded", onLazyLoaded);
|
|
$Lazyload.$off("error", onLazyLoadError);
|
|
});
|
|
}
|
|
onMounted(() => {
|
|
nextTick(() => {
|
|
var _a;
|
|
if (((_a = imageRef.value) == null ? void 0 : _a.complete) && !props.lazyLoad) {
|
|
triggerLoad();
|
|
}
|
|
});
|
|
});
|
|
return () => {
|
|
var _a;
|
|
return _createVNode("div", {
|
|
"class": bem({
|
|
round: props.round,
|
|
block: props.block
|
|
}),
|
|
"style": style.value
|
|
}, [renderImage(), renderPlaceholder(), (_a = slots.default) == null ? void 0 : _a.call(slots)]);
|
|
};
|
|
}
|
|
});
|
|
export {
|
|
stdin_default as default,
|
|
imageProps
|
|
};
|