element-plus
Version:
A Component Library for Vue3.0
299 lines (286 loc) • 10.8 kB
JavaScript
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;
;