element-plus
Version:
A Component Library for Vue3.0
297 lines (286 loc) • 9.38 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 !== void 0;
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: {
appendToBody: {
type: Boolean,
default: false
},
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: 2e3
}
},
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) => {
if (key.toLowerCase() === "onload")
return;
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);
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)
]) : (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, ["src"])),
(vue.openBlock(), vue.createBlock(vue.Teleport, {
to: "body",
disabled: !_ctx.appendToBody
}, [
_ctx.preview ? (vue.openBlock(), vue.createBlock(vue.Fragment, { key: 0 }, [
_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, ["z-index", "initial-index", "url-list", "hide-on-click-modal", "onClose"])) : vue.createCommentVNode("v-if", true)
], 2112)) : vue.createCommentVNode("v-if", true)
], 8, ["disabled"]))
], 6);
}
script.render = render;
script.__file = "packages/image/src/index.vue";
script.install = (app) => {
app.component(script.name, script);
};
const _Image = script;
exports.default = _Image;
;