4c6076079ae34fecc4305176bbf74685942b7b552b76d14ff21efc6c4cc246cb4c7db1b7eb1b8479fd9b0169f0233406780e8fb3a5df8df198932fcd8c79e8 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { defineComponent, useAttrs, computed, ref, watch, onMounted, openBlock, createElementBlock, mergeProps, unref, renderSlot, createElementVNode, normalizeClass, toDisplayString, Fragment, createCommentVNode, createBlock, createSlots, withCtx, normalizeProps, guardReactiveProps, nextTick } from 'vue';
  2. import { isClient, useThrottleFn, useIntersectionObserver } from '@vueuse/core';
  3. import { fromPairs } from 'lodash-unified';
  4. import { ElImageViewer } from '../../image-viewer/index.mjs';
  5. import { imageProps, imageEmits } from './image.mjs';
  6. import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
  7. import { isElement, isWindow } from '../../../utils/types.mjs';
  8. import { useLocale } from '../../../hooks/use-locale/index.mjs';
  9. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  10. import { useAttrs as useAttrs$1 } from '../../../hooks/use-attrs/index.mjs';
  11. import { isArray, isString } from '@vue/shared';
  12. import { getScrollContainer } from '../../../utils/dom/scroll.mjs';
  13. const __default__ = defineComponent({
  14. name: "ElImage",
  15. inheritAttrs: false
  16. });
  17. const _sfc_main = /* @__PURE__ */ defineComponent({
  18. ...__default__,
  19. props: imageProps,
  20. emits: imageEmits,
  21. setup(__props, { expose, emit }) {
  22. const props = __props;
  23. const { t } = useLocale();
  24. const ns = useNamespace("image");
  25. const rawAttrs = useAttrs();
  26. const containerAttrs = computed(() => {
  27. return fromPairs(Object.entries(rawAttrs).filter(([key]) => /^(data-|on[A-Z])/i.test(key) || ["id", "style"].includes(key)));
  28. });
  29. const imgAttrs = useAttrs$1({
  30. excludeListeners: true,
  31. excludeKeys: computed(() => {
  32. return Object.keys(containerAttrs.value);
  33. })
  34. });
  35. const imageSrc = ref();
  36. const hasLoadError = ref(false);
  37. const isLoading = ref(true);
  38. const showViewer = ref(false);
  39. const container = ref();
  40. const _scrollContainer = ref();
  41. const supportLoading = isClient && "loading" in HTMLImageElement.prototype;
  42. let stopScrollListener;
  43. const imageKls = computed(() => [
  44. ns.e("inner"),
  45. preview.value && ns.e("preview"),
  46. isLoading.value && ns.is("loading")
  47. ]);
  48. const imageStyle = computed(() => {
  49. const { fit } = props;
  50. if (isClient && fit) {
  51. return { objectFit: fit };
  52. }
  53. return {};
  54. });
  55. const preview = computed(() => {
  56. const { previewSrcList } = props;
  57. return isArray(previewSrcList) && previewSrcList.length > 0;
  58. });
  59. const imageIndex = computed(() => {
  60. const { previewSrcList, initialIndex } = props;
  61. let previewIndex = initialIndex;
  62. if (initialIndex > previewSrcList.length - 1) {
  63. previewIndex = 0;
  64. }
  65. return previewIndex;
  66. });
  67. const isManual = computed(() => {
  68. if (props.loading === "eager")
  69. return false;
  70. return !supportLoading && props.loading === "lazy" || props.lazy;
  71. });
  72. const loadImage = () => {
  73. if (!isClient)
  74. return;
  75. isLoading.value = true;
  76. hasLoadError.value = false;
  77. imageSrc.value = props.src;
  78. };
  79. function handleLoad(event) {
  80. isLoading.value = false;
  81. hasLoadError.value = false;
  82. emit("load", event);
  83. }
  84. function handleError(event) {
  85. isLoading.value = false;
  86. hasLoadError.value = true;
  87. emit("error", event);
  88. }
  89. function handleLazyLoad(isIntersecting) {
  90. if (isIntersecting) {
  91. loadImage();
  92. removeLazyLoadListener();
  93. }
  94. }
  95. const lazyLoadHandler = useThrottleFn(handleLazyLoad, 200, true);
  96. async function addLazyLoadListener() {
  97. var _a;
  98. if (!isClient)
  99. return;
  100. await nextTick();
  101. const { scrollContainer } = props;
  102. if (isElement(scrollContainer)) {
  103. _scrollContainer.value = scrollContainer;
  104. } else if (isString(scrollContainer) && scrollContainer !== "") {
  105. _scrollContainer.value = (_a = document.querySelector(scrollContainer)) != null ? _a : void 0;
  106. } else if (container.value) {
  107. const scrollContainer2 = getScrollContainer(container.value);
  108. _scrollContainer.value = isWindow(scrollContainer2) ? void 0 : scrollContainer2;
  109. }
  110. const { stop } = useIntersectionObserver(container, ([entry]) => {
  111. lazyLoadHandler(entry.isIntersecting);
  112. }, { root: _scrollContainer });
  113. stopScrollListener = stop;
  114. }
  115. function removeLazyLoadListener() {
  116. if (!isClient || !lazyLoadHandler)
  117. return;
  118. stopScrollListener == null ? void 0 : stopScrollListener();
  119. _scrollContainer.value = void 0;
  120. stopScrollListener = void 0;
  121. }
  122. function clickHandler() {
  123. if (!preview.value)
  124. return;
  125. showViewer.value = true;
  126. emit("show");
  127. }
  128. function closeViewer() {
  129. showViewer.value = false;
  130. emit("close");
  131. }
  132. function switchViewer(val) {
  133. emit("switch", val);
  134. }
  135. watch(() => props.src, () => {
  136. if (isManual.value) {
  137. isLoading.value = true;
  138. hasLoadError.value = false;
  139. removeLazyLoadListener();
  140. addLazyLoadListener();
  141. } else {
  142. loadImage();
  143. }
  144. });
  145. onMounted(() => {
  146. if (isManual.value) {
  147. addLazyLoadListener();
  148. } else {
  149. loadImage();
  150. }
  151. });
  152. expose({
  153. showPreview: clickHandler
  154. });
  155. return (_ctx, _cache) => {
  156. return openBlock(), createElementBlock("div", mergeProps({
  157. ref_key: "container",
  158. ref: container
  159. }, unref(containerAttrs), {
  160. class: [unref(ns).b(), _ctx.$attrs.class]
  161. }), [
  162. hasLoadError.value ? renderSlot(_ctx.$slots, "error", { key: 0 }, () => [
  163. createElementVNode("div", {
  164. class: normalizeClass(unref(ns).e("error"))
  165. }, toDisplayString(unref(t)("el.image.error")), 3)
  166. ]) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
  167. imageSrc.value !== void 0 ? (openBlock(), createElementBlock("img", mergeProps({ key: 0 }, unref(imgAttrs), {
  168. src: imageSrc.value,
  169. loading: _ctx.loading,
  170. style: unref(imageStyle),
  171. class: unref(imageKls),
  172. crossorigin: _ctx.crossorigin,
  173. onClick: clickHandler,
  174. onLoad: handleLoad,
  175. onError: handleError
  176. }), null, 16, ["src", "loading", "crossorigin"])) : createCommentVNode("v-if", true),
  177. isLoading.value ? (openBlock(), createElementBlock("div", {
  178. key: 1,
  179. class: normalizeClass(unref(ns).e("wrapper"))
  180. }, [
  181. renderSlot(_ctx.$slots, "placeholder", {}, () => [
  182. createElementVNode("div", {
  183. class: normalizeClass(unref(ns).e("placeholder"))
  184. }, null, 2)
  185. ])
  186. ], 2)) : createCommentVNode("v-if", true)
  187. ], 64)),
  188. unref(preview) ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
  189. showViewer.value ? (openBlock(), createBlock(unref(ElImageViewer), {
  190. key: 0,
  191. "z-index": _ctx.zIndex,
  192. "initial-index": unref(imageIndex),
  193. infinite: _ctx.infinite,
  194. "zoom-rate": _ctx.zoomRate,
  195. "min-scale": _ctx.minScale,
  196. "max-scale": _ctx.maxScale,
  197. "show-progress": _ctx.showProgress,
  198. "url-list": _ctx.previewSrcList,
  199. scale: _ctx.scale,
  200. crossorigin: _ctx.crossorigin,
  201. "hide-on-click-modal": _ctx.hideOnClickModal,
  202. teleported: _ctx.previewTeleported,
  203. "close-on-press-escape": _ctx.closeOnPressEscape,
  204. onClose: closeViewer,
  205. onSwitch: switchViewer
  206. }, createSlots({
  207. toolbar: withCtx((toolbar) => [
  208. renderSlot(_ctx.$slots, "toolbar", normalizeProps(guardReactiveProps(toolbar)))
  209. ]),
  210. default: withCtx(() => [
  211. _ctx.$slots.viewer ? (openBlock(), createElementBlock("div", { key: 0 }, [
  212. renderSlot(_ctx.$slots, "viewer")
  213. ])) : createCommentVNode("v-if", true)
  214. ]),
  215. _: 2
  216. }, [
  217. _ctx.$slots.progress ? {
  218. name: "progress",
  219. fn: withCtx((progress) => [
  220. renderSlot(_ctx.$slots, "progress", normalizeProps(guardReactiveProps(progress)))
  221. ])
  222. } : void 0,
  223. _ctx.$slots["viewer-error"] ? {
  224. name: "viewer-error",
  225. fn: withCtx((viewerError) => [
  226. renderSlot(_ctx.$slots, "viewer-error", normalizeProps(guardReactiveProps(viewerError)))
  227. ])
  228. } : void 0
  229. ]), 1032, ["z-index", "initial-index", "infinite", "zoom-rate", "min-scale", "max-scale", "show-progress", "url-list", "scale", "crossorigin", "hide-on-click-modal", "teleported", "close-on-press-escape"])) : createCommentVNode("v-if", true)
  230. ], 64)) : createCommentVNode("v-if", true)
  231. ], 16);
  232. };
  233. }
  234. });
  235. var Image = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "image.vue"]]);
  236. export { Image as default };
  237. //# sourceMappingURL=image2.mjs.map