UNPKG

element-plus

Version:

A Component Library for Vue3.0

299 lines (286 loc) 10.8 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); var throttle = require('lodash/throttle'); var hooks = require('../hooks'); var isServer = require('../utils/isServer'); var dom = require('../utils/dom'); var locale = require('../locale'); var ImageViewer = require('../el-image-viewer'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var throttle__default = /*#__PURE__*/_interopDefaultLegacy(throttle); var isServer__default = /*#__PURE__*/_interopDefaultLegacy(isServer); var ImageViewer__default = /*#__PURE__*/_interopDefaultLegacy(ImageViewer); /** * Make a map and return a function for checking if a key * is in that map. * IMPORTANT: all calls of this function must be prefixed with * \/\*#\_\_PURE\_\_\*\/ * So that rollup can tree-shake them if necessary. */ const EMPTY_OBJ = (process.env.NODE_ENV !== 'production') ? Object.freeze({}) : {}; const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : []; const isString = (val) => typeof val === 'string'; const isSupportObjectFit = () => document.documentElement.style.objectFit !== undefined; const isHtmlEle = e => e && e.nodeType === 1; const ObjectFit = { NONE: 'none', CONTAIN: 'contain', COVER: 'cover', FILL: 'fill', SCALE_DOWN: 'scale-down', }; let prevOverflow = ''; var script = vue.defineComponent({ name: 'ElImage', components: { ImageViewer: ImageViewer__default['default'], }, inheritAttrs: false, props: { hideOnClickModal: { type: Boolean, default: false, }, src: { type: String, default: '', }, fit: { type: String, default: '', }, lazy: { type: Boolean, default: false, }, scrollContainer: { type: [String, Object], default: null, }, previewSrcList: { type: Array, default: () => [], }, zIndex: { type: Number, default: 2000, }, }, emits: ['error'], setup(props, { emit }) { const attrs = hooks.useAttrs(); const hasLoadError = vue.ref(false); const loading = vue.ref(true); const imgWidth = vue.ref(0); const imgHeight = vue.ref(0); const showViewer = vue.ref(false); const container = vue.ref(null); let _scrollContainer = null; let _lazyLoadHandler = null; const imageStyle = vue.computed(() => { const { fit } = props; if (!isServer__default['default'] && fit) { return isSupportObjectFit() ? { 'object-fit': fit } : getImageStyle(fit); } return {}; }); const alignCenter = vue.computed(() => { const { fit } = props; return !isServer__default['default'] && !isSupportObjectFit() && fit !== ObjectFit.FILL; }); const preview = vue.computed(() => { const { previewSrcList } = props; return Array.isArray(previewSrcList) && previewSrcList.length > 0; }); const imageIndex = vue.computed(() => { const { src, previewSrcList } = props; let previewIndex = 0; const srcIndex = previewSrcList.indexOf(src); if (srcIndex >= 0) { previewIndex = srcIndex; } return previewIndex; }); function getImageStyle(fit) { const imageWidth = imgWidth.value; const imageHeight = imgHeight.value; if (!container.value) return {}; const { clientWidth: containerWidth, clientHeight: containerHeight, } = container.value; if (!imageWidth || !imageHeight || !containerWidth || !containerHeight) return {}; const imageAspectRatio = imageWidth / imageHeight; const containerAspectRatio = containerWidth / containerHeight; if (fit === ObjectFit.SCALE_DOWN) { const isSmaller = imageWidth < containerWidth && imageHeight < containerHeight; fit = isSmaller ? ObjectFit.NONE : ObjectFit.CONTAIN; } switch (fit) { case ObjectFit.NONE: return { width: 'auto', height: 'auto' }; case ObjectFit.CONTAIN: return (imageAspectRatio < containerAspectRatio) ? { width: 'auto' } : { height: 'auto' }; case ObjectFit.COVER: return (imageAspectRatio < containerAspectRatio) ? { height: 'auto' } : { width: 'auto' }; default: return {}; } } const loadImage = () => { if (isServer__default['default']) return; const attributes = attrs.value; loading.value = true; hasLoadError.value = false; const img = new Image(); img.onload = e => handleLoad(e, img); img.onerror = handleError; Object.keys(attributes) .forEach(key => { const value = attributes[key]; img.setAttribute(key, value); }); img.src = props.src; }; function handleLoad(e, img) { imgWidth.value = img.width; imgHeight.value = img.height; loading.value = false; hasLoadError.value = false; } function handleError(e) { loading.value = false; hasLoadError.value = true; emit('error', e); } function handleLazyLoad() { if (dom.isInContainer(container.value, _scrollContainer)) { loadImage(); removeLazyLoadListener(); } } function addLazyLoadListener() { if (isServer__default['default']) return; const { scrollContainer } = props; if (isHtmlEle(scrollContainer)) { _scrollContainer = scrollContainer; } else if (isString(scrollContainer) && scrollContainer !== '') { _scrollContainer = document.querySelector(scrollContainer); } else { _scrollContainer = dom.getScrollContainer(container.value); } if (_scrollContainer) { _lazyLoadHandler = throttle__default['default'](handleLazyLoad, 200); dom.on(_scrollContainer, 'scroll', _lazyLoadHandler); setTimeout(() => handleLazyLoad(), 100); } } function removeLazyLoadListener() { if (isServer__default['default'] || !_scrollContainer || !_lazyLoadHandler) return; dom.off(_scrollContainer, 'scroll', _lazyLoadHandler); _scrollContainer = null; _lazyLoadHandler = null; } function clickHandler() { if (!preview.value) { return; } prevOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; showViewer.value = true; } function closeViewer() { document.body.style.overflow = prevOverflow; showViewer.value = false; } vue.watch(() => props.src, () => { loadImage(); }); vue.onMounted(() => { if (props.lazy) { vue.nextTick(addLazyLoadListener); } else { loadImage(); } }); vue.onBeforeUnmount(() => { props.lazy && removeLazyLoadListener(); }); return { attrs, loading, hasLoadError, showViewer, imgWidth, imgHeight, imageStyle, alignCenter, preview, imageIndex, clickHandler, closeViewer, container, handleError, t: locale.t, }; }, }); const _hoisted_1 = /*#__PURE__*/vue.createVNode("div", { class: "el-image__placeholder" }, null, -1 /* HOISTED */); const _hoisted_2 = { class: "el-image__error" }; function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_image_viewer = vue.resolveComponent("image-viewer"); return (vue.openBlock(), vue.createBlock("div", { ref: "container", class: ['el-image', _ctx.$attrs.class], style: _ctx.$attrs.style }, [ (_ctx.loading) ? vue.renderSlot(_ctx.$slots, "placeholder", { key: 0 }, () => [ _hoisted_1 ]) : (_ctx.hasLoadError) ? vue.renderSlot(_ctx.$slots, "error", { key: 1 }, () => [ vue.createVNode("div", _hoisted_2, vue.toDisplayString(_ctx.t('el.image.error')), 1 /* TEXT */) ]) : (vue.openBlock(), vue.createBlock("img", vue.mergeProps({ key: 2, class: "el-image__inner" }, _ctx.attrs, { src: _ctx.src, style: _ctx.imageStyle, class: { 'el-image__inner--center': _ctx.alignCenter, 'el-image__preview': _ctx.preview }, onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.clickHandler && _ctx.clickHandler(...args))) }), null, 16 /* FULL_PROPS */, ["src"])), (_ctx.preview) ? (vue.openBlock(), vue.createBlock(vue.Fragment, { key: 3 }, [ (_ctx.showViewer) ? (vue.openBlock(), vue.createBlock(_component_image_viewer, { key: 0, "z-index": _ctx.zIndex, "initial-index": _ctx.imageIndex, "url-list": _ctx.previewSrcList, "hide-on-click-modal": _ctx.hideOnClickModal, onClose: _ctx.closeViewer }, null, 8 /* PROPS */, ["z-index", "initial-index", "url-list", "hide-on-click-modal", "onClose"])) : vue.createCommentVNode("v-if", true) ], 64 /* STABLE_FRAGMENT */)) : vue.createCommentVNode("v-if", true) ], 6 /* CLASS, STYLE */)) } script.render = render; script.__file = "packages/image/src/index.vue"; script.install = (app) => { app.component(script.name, script); }; const _Image = script; exports.default = _Image;