{"version":3,"file":"image.vue.mjs","sources":["../../../../../packages/components/image/src/image.vue"],"sourcesContent":["<template>\n  <div ref=\"container\" :class=\"[ns.b(), $attrs.class]\" :style=\"containerStyle\">\n    <slot v-if=\"loading\" name=\"placeholder\">\n      <div :class=\"ns.e('placeholder')\"></div>\n    </slot>\n    <slot v-else-if=\"hasLoadError\" name=\"error\">\n      <div :class=\"ns.e('error')\">加载失败</div>\n    </slot>\n    <img\n      v-else\n      v-bind=\"attrs\"\n      :src=\"src\"\n      :style=\"imageStyle\"\n      :class=\"[ns.e('inner'), preview ? ns.e('preview') : '']\"\n      @click=\"clickHandler\"\n    />\n    <template v-if=\"preview\">\n      <image-viewer\n        v-if=\"showViewer\"\n        :z-index=\"zIndex\"\n        :initial-index=\"imageIndex\"\n        :url-list=\"previewSrcList\"\n        :hide-on-click-modal=\"hideOnClickModal\"\n        :teleported=\"teleported\"\n        @close=\"closeViewer\"\n        @switch=\"switchViewer\"\n      >\n        <div v-if=\"$slots.viewer\">\n          <slot name=\"viewer\" />\n        </div>\n      </image-viewer>\n    </template>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, computed, ref, onMounted, watch, nextTick } from 'vue'\nimport { isString } from '@vue/shared'\nimport {\n  useEventListener,\n  useThrottleFn,\n  isClient,\n  isBoolean,\n} from '@vueuse/core'\nimport {\n  useAttrs,\n  useNamespace,\n  useDeprecated,\n} from '@element-ultra/hooks'\nimport ImageViewer from '@element-ultra/components/image-viewer'\nimport { getScrollContainer, isInContainer } from '@element-ultra/utils'\nimport { imageEmits, imageProps } from './image'\n\nimport type { CSSProperties, StyleValue } from 'vue'\n\nconst isHtmlElement = (e: any): e is Element =>\n  e && e.nodeType === Node.ELEMENT_NODE\n\nlet prevOverflow = ''\n\nexport default defineComponent({\n  name: 'ElImage',\n  components: {\n    ImageViewer,\n  },\n  inheritAttrs: false,\n\n  props: imageProps,\n  emits: imageEmits,\n\n  setup(props, { emit, attrs: rawAttrs }) {\n    useDeprecated(\n      {\n        scope: 'el-image',\n        from: 'append-to-body',\n        replacement: 'preview-teleported',\n        version: '2.2.0',\n        ref: 'https://element-plus.org/en-US/component/image.html#image-attributess',\n      },\n      computed(() => isBoolean(props.appendToBody))\n    )\n\n    const ns = useNamespace('image')\n\n    const attrs = useAttrs()\n    const hasLoadError = ref(false)\n    const loading = ref(true)\n    const imgWidth = ref(0)\n    const imgHeight = ref(0)\n    const showViewer = ref(false)\n    const container = ref<HTMLElement>()\n\n    const _scrollContainer = ref<HTMLElement | Window>()\n    let stopScrollListener: () => void\n    let stopWheelListener: () => void\n\n    const containerStyle = computed(() => rawAttrs.style as StyleValue)\n\n    const imageStyle = computed<CSSProperties>(() => {\n      const { fit } = props\n      if (isClient && fit) {\n        return { objectFit: fit }\n      }\n      return {}\n    })\n\n    const preview = computed(() => {\n      const { previewSrcList } = props\n      return Array.isArray(previewSrcList) && previewSrcList.length > 0\n    })\n\n    const teleported = computed(() => {\n      return props.appendToBody || props.previewTeleported\n    })\n\n    const imageIndex = computed(() => {\n      const { previewSrcList, initialIndex } = props\n      let previewIndex = initialIndex\n      if (initialIndex > previewSrcList.length - 1) {\n        previewIndex = 0\n      }\n      return previewIndex\n    })\n\n    const loadImage = () => {\n      if (!isClient) return\n\n      // reset status\n      loading.value = true\n      hasLoadError.value = false\n\n      const img = new Image()\n      const currentImageSrc = props.src\n\n      // load & error callbacks are only responsible for currentImageSrc\n      img.addEventListener('load', (e) => {\n        if (currentImageSrc !== props.src) {\n          return\n        }\n        handleLoad(e, img)\n      })\n      img.addEventListener('error', (e) => {\n        if (currentImageSrc !== props.src) {\n          return\n        }\n        handleError(e)\n      })\n\n      // bind html attrs\n      // so it can behave consistently\n      Object.entries(attrs.value).forEach(([key, value]) => {\n        // avoid onload to be overwritten\n        if (key.toLowerCase() === 'onload') return\n        img.setAttribute(key, value as string)\n      })\n      img.src = currentImageSrc\n    }\n\n    function handleLoad(e: Event, img: HTMLImageElement) {\n      imgWidth.value = img.width\n      imgHeight.value = img.height\n      loading.value = false\n      hasLoadError.value = false\n    }\n\n    function handleError(event: Event) {\n      loading.value = false\n      hasLoadError.value = true\n      emit('error', event)\n    }\n\n    function handleLazyLoad() {\n      if (isInContainer(container.value, _scrollContainer.value)) {\n        loadImage()\n        removeLazyLoadListener()\n      }\n    }\n\n    const lazyLoadHandler = useThrottleFn(handleLazyLoad, 200)\n\n    async function addLazyLoadListener() {\n      if (!isClient) return\n\n      await nextTick()\n\n      const { scrollContainer } = props\n      if (isHtmlElement(scrollContainer)) {\n        _scrollContainer.value = scrollContainer\n      } else if (isString(scrollContainer) && scrollContainer !== '') {\n        _scrollContainer.value =\n          document.querySelector<HTMLElement>(scrollContainer) ?? undefined\n      } else if (container.value) {\n        _scrollContainer.value = getScrollContainer(container.value)\n      }\n\n      if (_scrollContainer.value) {\n        stopScrollListener = useEventListener(\n          _scrollContainer,\n          'scroll',\n          lazyLoadHandler\n        )\n        setTimeout(() => handleLazyLoad(), 100)\n      }\n    }\n\n    function removeLazyLoadListener() {\n      if (!isClient || !_scrollContainer.value || !lazyLoadHandler) return\n\n      stopScrollListener()\n      _scrollContainer.value = undefined\n    }\n\n    function wheelHandler(e: WheelEvent) {\n      if (!e.ctrlKey) return\n\n      if (e.deltaY < 0) {\n        e.preventDefault()\n        return false\n      } else if (e.deltaY > 0) {\n        e.preventDefault()\n        return false\n      }\n    }\n\n    function clickHandler() {\n      // don't show viewer when preview is false\n      if (!preview.value) return\n\n      stopWheelListener = useEventListener('wheel', wheelHandler, {\n        passive: false,\n      })\n\n      // prevent body scroll\n      prevOverflow = document.body.style.overflow\n      document.body.style.overflow = 'hidden'\n      showViewer.value = true\n    }\n\n    function closeViewer() {\n      stopWheelListener?.()\n      document.body.style.overflow = prevOverflow\n      showViewer.value = false\n      emit('close')\n    }\n\n    function switchViewer(val: number) {\n      emit('switch', val)\n    }\n\n    watch(\n      () => props.src,\n      () => {\n        if (props.lazy) {\n          // reset status\n          loading.value = true\n          hasLoadError.value = false\n          removeLazyLoadListener()\n          addLazyLoadListener()\n        } else {\n          loadImage()\n        }\n      }\n    )\n\n    onMounted(() => {\n      if (props.lazy) {\n        addLazyLoadListener()\n      } else {\n        loadImage()\n      }\n    })\n\n    return {\n      attrs,\n      loading,\n      hasLoadError,\n      showViewer,\n      containerStyle,\n      imageStyle,\n      preview,\n      imageIndex,\n      container,\n      ns,\n      teleported,\n\n      clickHandler,\n      closeViewer,\n      switchViewer\n    }\n  },\n})\n</script>\n"],"names":["_resolveComponent","_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle","_renderSlot","_createElementVNode","_mergeProps","_Fragment","_createBlock","_withCtx"],"mappings":";;;;;;;kCACEA,iBA+BM,cAAA,CAAA,CAAA;AA/BqB,EAAA,OAAAC,WAAA,EAAAC,kBAAA;AAAA,IAAW,KAAA;AAAA,IAAA;AAAA,MAAgB,GAAK,EAAA,WAAA;AAAA,MAAA,KAAA,EAAAC,cAAA,CAAA,CAAA,IAAA,CAAA,EAAA,CAAA,GAAA,EAAA,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,CAAA;AAAA,aAC7CC,cAAO,CAAA,IAAA,CAAA,cAAA,CAAA;AAAA,KAAA;AAAA;MACjB,IAAA,CAAA,OAAA,GAAAC,UAAA,CAAW,IAAM,CAAA,MAAA,EAAA,eAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA,MAAA;AAAA,QAAAC,kBAAA;AAAA;;;WAEF;AAAA,UAAA,IAAA;AAAA,UAAA,CAAA;AAAA;AAAA,SAAY;AAAA,OAC3B,CAAA,GAAA,IAAA,CAAA,YAAA,GAAAD,UAAW,CAAA,IAAA,kBAAI,EAAE,GAAA,EAAA,CAAA,EAAA,EAAA,MAAA;AAAA,QAAAC,kBAAA;AAAA,UAAe,KAAA;AAAA,UAAA;AAAA,YAAA,OAAAH,cAAA,CAAA,IAAA,CAAA,EAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA;AAAA;;;;SAElC;AAAA,OAAA,CAAA,IAAAF,SAIU,EAAA,EAAUC,kBAAA,CAAA,KAAA,EAAAK,UAAA,CAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA,IAAA,CAAA,KAAA,EAAA;AAAA,QACjB,KAAK,IAAG,CAAA,GAAA;AAAA,QACR,OAAK,IAAA,CAAA,UAAA;AAAA,QAAA,KAAA,EAAA,CAAA,IAAA,CAAA,EAAA,CAAA,EAAA,OAAA,CAAA,EAAA,IAAA,CAAA,OAAA,GAAA,IAAA,CAAA,EAAA,CAAA,CAAA,CAAA,SAAA,IAAA,EAAA,CAAA;AAAA,QAEQ,OAAO,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,OAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,YAAA,IAAA,IAAA,CAAA,YAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,OAAA,CAAA,EAAA,IAAA,EAAA,EAAA,EAAvB,UAeW,CAAA,CAAA;AAAA,MAAA,IAAA,CAAA,OAAA,IAAAN,SAAA,EAAA,EAAAC,kBAAA;AAAA,QADMM,QAAA;AAAA,QAAA,EAAA,KAAA,CAAA,EAAA;AAAA,QAAA;AAAA,UAAA,IAAA,CAAA,UAAA,IAAAP,SAXL,EAAA,EAAEQ,YAAM,uBAAA,EAAA;AAAA,YACf,GAAA,EAAA,CAAA;AAAA,YACA,WAAQ,IAAE,CAAA,MAAA;AAAA,YACV,iBAAmB,IAAA,CAAA,UAAA;AAAA,YACnB,YAAY,IAAA,CAAA,cAAA;AAAA,YACZ,uBAAO,IAAW,CAAA,gBAAA;AAAA,YAClB,YAAQ,IAAA,CAAA,UAAA;AAAA,YAAA,SAAA,IAAA,CAAA,WAAA;AAAA;;YAET,OAAA,EAAAC,QAAA,MAAA;AAAA,cACE,KAAA,MAAA,CAAA,MAAA,IAAAT,WAAA,EAAAC,kBAAA,CAAA,OAAA,UAAA,EAAA;AAAA;;;;;;;;;;;;;;;;;;;"}