diff --git a/packages/image/src/main.vue b/packages/image/src/main.vue index 3463abd4d0..4cbccf0dc2 100644 --- a/packages/image/src/main.vue +++ b/packages/image/src/main.vue @@ -11,7 +11,8 @@ class="el-image__inner" :src="src" :alt="alt" - :style="{ 'object-fit': fit }"> + :style="imageStyle" + :class="{ 'el-image__inner--center': alignCenter }"> @@ -21,6 +22,16 @@ import { isString, isHtmlElement } from 'element-ui/src/utils/types'; import throttle from 'throttle-debounce/throttle'; + const isSupportObjectFit = () => document.documentElement.style.objectFit !== undefined; + + const ObjectFit = { + NONE: 'none', + CONTAIN: 'contain', + COVER: 'cover', + FILL: 'fill', + SCALE_DOWN: 'scale-down' + }; + export default { name: 'ElImage', @@ -38,24 +49,42 @@ return { loading: true, error: false, - show: !this.lazy + show: !this.lazy, + imageWidth: 0, + imageHeight: 0 }; }, + computed: { + imageStyle() { + const { fit } = this; + if (!this.$isServer && fit) { + return isSupportObjectFit() + ? { 'object-fit': fit } + : this.getImageStyle(fit); + } + return {}; + }, + alignCenter() { + return !this.$isServer && !isSupportObjectFit() && this.fit !== ObjectFit.FILL; + } + }, + watch: { - src: { - handler(val) { - this.show && this.loadImage(val); - }, - immediate: true + src(val) { + this.show && this.loadImage(); }, show(val) { - val && this.loadImage(this.src); + val && this.loadImage(); } }, mounted() { - this.lazy && this.addLazyLoadListener(); + if (this.lazy) { + this.addLazyLoadListener(); + } else { + this.loadImage(); + } }, beforeDestroy() { @@ -63,17 +92,21 @@ }, methods: { - loadImage(val) { + loadImage() { + if (this.$isServer) return; + // reset status this.loading = true; this.error = false; const img = new Image(); - img.onload = this.handleLoad.bind(this); + img.onload = e => this.handleLoad(e, img); img.onerror = this.handleError.bind(this); - img.src = val; + img.src = this.src; }, - handleLoad(e) { + handleLoad(e, img) { + this.imageWidth = img.width; + this.imageHeight = img.height; this.loading = false; this.$emit('load', e); }, @@ -117,6 +150,36 @@ off(_scrollContainer, 'scroll', _lazyLoadHandler); this._scrollContainer = null; this._lazyLoadHandler = null; + }, + /** + * simulate object-fit behavior to compatible with IE11 and other browsers which not support object-fit + */ + getImageStyle(fit) { + const { imageWidth, imageHeight } = this; + const { + clientWidth: containerWidth, + clientHeight: containerHeight + } = this.$el; + + if (!imageWidth || !imageHeight || !containerWidth || !containerHeight) return {}; + + const vertical = imageWidth / imageHeight < 1; + + 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 vertical ? { width: 'auto' } : { height: 'auto' }; + case ObjectFit.COVER: + return vertical ? { height: 'auto' } : { width: 'auto' }; + default: + return {}; + } } } }; diff --git a/packages/theme-chalk/src/image.scss b/packages/theme-chalk/src/image.scss index 528707bb5c..0065fb2f69 100644 --- a/packages/theme-chalk/src/image.scss +++ b/packages/theme-chalk/src/image.scss @@ -7,11 +7,21 @@ } @include b(image) { + position: relative; display: inline-block; + overflow: hidden; @include e(inner) { @extend %size; vertical-align: top; + + @include m(center) { + position: relative; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + display: block; + } } @include e(placeholder) {