mirror of https://github.com/ElemeFE/element
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 elementpull/15178/head
parent
06dfe16ef6
commit
340da2ff61
|
@ -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 {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue