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" class="el-image__inner"
:src="src" :src="src"
:alt="alt" :alt="alt"
:style="{ 'object-fit': fit }"> :style="imageStyle"
:class="{ 'el-image__inner--center': alignCenter }">
</div> </div>
</template> </template>
@ -21,6 +22,16 @@
import { isString, isHtmlElement } from 'element-ui/src/utils/types'; import { isString, isHtmlElement } from 'element-ui/src/utils/types';
import throttle from 'throttle-debounce/throttle'; 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 { export default {
name: 'ElImage', name: 'ElImage',
@ -38,24 +49,42 @@
return { return {
loading: true, loading: true,
error: false, 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: { watch: {
src: { src(val) {
handler(val) { this.show && this.loadImage();
this.show && this.loadImage(val);
},
immediate: true
}, },
show(val) { show(val) {
val && this.loadImage(this.src); val && this.loadImage();
} }
}, },
mounted() { mounted() {
this.lazy && this.addLazyLoadListener(); if (this.lazy) {
this.addLazyLoadListener();
} else {
this.loadImage();
}
}, },
beforeDestroy() { beforeDestroy() {
@ -63,17 +92,21 @@
}, },
methods: { methods: {
loadImage(val) { loadImage() {
if (this.$isServer) return;
// reset status // reset status
this.loading = true; this.loading = true;
this.error = false; this.error = false;
const img = new Image(); const img = new Image();
img.onload = this.handleLoad.bind(this); img.onload = e => this.handleLoad(e, img);
img.onerror = this.handleError.bind(this); 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.loading = false;
this.$emit('load', e); this.$emit('load', e);
}, },
@ -117,6 +150,36 @@
off(_scrollContainer, 'scroll', _lazyLoadHandler); off(_scrollContainer, 'scroll', _lazyLoadHandler);
this._scrollContainer = null; this._scrollContainer = null;
this._lazyLoadHandler = 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) { @include b(image) {
position: relative;
display: inline-block; display: inline-block;
overflow: hidden;
@include e(inner) { @include e(inner) {
@extend %size; @extend %size;
vertical-align: top; vertical-align: top;
@include m(center) {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: block;
}
} }
@include e(placeholder) { @include e(placeholder) {