image.mjs 8.6 KB

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