Image: fix ssr and object-fit compatibility. (#15346)

* fix: Image is not defined during ssr

Delay loadImage to mounted hook and add $isServer check

* fix(image): simulate object-fit behavior to compatible with IE11 and other browsers which not suppor

fix #15278

* fix: image inline-flex with overflow will still extend its parent element
pull/15178/head
Simona 2019-05-07 11:57:37 +08:00 committed by Zhi Cun
parent 06dfe16ef6
commit 340da2ff61
2 changed files with 86 additions and 13 deletions

View File

@ -11,7 +11,8 @@
class="el-image__inner"
:src="src"
:alt="alt"
:style="{ 'object-fit': fit }">
:style="imageStyle"
:class="{ 'el-image__inner--center': alignCenter }">
</div>
</template>
@ -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 {};
}
}
}
};

View File

@ -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) {