|
11 | 11 | class="el-image__inner"
|
12 | 12 | :src="src"
|
13 | 13 | :alt="alt"
|
14 |
| - :style="{ 'object-fit': fit }"> |
| 14 | + :style="imageStyle" |
| 15 | + :class="{ 'el-image__inner--center': alignCenter }"> |
15 | 16 | </div>
|
16 | 17 | </template>
|
17 | 18 |
|
|
21 | 22 | import { isString, isHtmlElement } from 'element-ui/src/utils/types';
|
22 | 23 | import throttle from 'throttle-debounce/throttle';
|
23 | 24 |
|
| 25 | + const isSupportObjectFit = () => document.documentElement.style.objectFit !== undefined; |
| 26 | +
|
| 27 | + const ObjectFit = { |
| 28 | + NONE: 'none', |
| 29 | + CONTAIN: 'contain', |
| 30 | + COVER: 'cover', |
| 31 | + FILL: 'fill', |
| 32 | + SCALE_DOWN: 'scale-down' |
| 33 | + }; |
| 34 | +
|
24 | 35 | export default {
|
25 | 36 | name: 'ElImage',
|
26 | 37 |
|
|
38 | 49 | return {
|
39 | 50 | loading: true,
|
40 | 51 | error: false,
|
41 |
| - show: !this.lazy |
| 52 | + show: !this.lazy, |
| 53 | + imageWidth: 0, |
| 54 | + imageHeight: 0 |
42 | 55 | };
|
43 | 56 | },
|
44 | 57 |
|
| 58 | + computed: { |
| 59 | + imageStyle() { |
| 60 | + const { fit } = this; |
| 61 | + if (!this.$isServer && fit) { |
| 62 | + return isSupportObjectFit() |
| 63 | + ? { 'object-fit': fit } |
| 64 | + : this.getImageStyle(fit); |
| 65 | + } |
| 66 | + return {}; |
| 67 | + }, |
| 68 | + alignCenter() { |
| 69 | + return !this.$isServer && !isSupportObjectFit() && this.fit !== ObjectFit.FILL; |
| 70 | + } |
| 71 | + }, |
| 72 | +
|
45 | 73 | watch: {
|
46 |
| - src: { |
47 |
| - handler(val) { |
48 |
| - this.show && this.loadImage(val); |
49 |
| - }, |
50 |
| - immediate: true |
| 74 | + src(val) { |
| 75 | + this.show && this.loadImage(); |
51 | 76 | },
|
52 | 77 | show(val) {
|
53 |
| - val && this.loadImage(this.src); |
| 78 | + val && this.loadImage(); |
54 | 79 | }
|
55 | 80 | },
|
56 | 81 |
|
57 | 82 | mounted() {
|
58 |
| - this.lazy && this.addLazyLoadListener(); |
| 83 | + if (this.lazy) { |
| 84 | + this.addLazyLoadListener(); |
| 85 | + } else { |
| 86 | + this.loadImage(); |
| 87 | + } |
59 | 88 | },
|
60 | 89 |
|
61 | 90 | beforeDestroy() {
|
62 | 91 | this.lazy && this.removeLazyLoadListener();
|
63 | 92 | },
|
64 | 93 |
|
65 | 94 | methods: {
|
66 |
| - loadImage(val) { |
| 95 | + loadImage() { |
| 96 | + if (this.$isServer) return; |
| 97 | +
|
67 | 98 | // reset status
|
68 | 99 | this.loading = true;
|
69 | 100 | this.error = false;
|
70 | 101 |
|
71 | 102 | const img = new Image();
|
72 |
| - img.onload = this.handleLoad.bind(this); |
| 103 | + img.onload = e => this.handleLoad(e, img); |
73 | 104 | img.onerror = this.handleError.bind(this);
|
74 |
| - img.src = val; |
| 105 | + img.src = this.src; |
75 | 106 | },
|
76 |
| - handleLoad(e) { |
| 107 | + handleLoad(e, img) { |
| 108 | + this.imageWidth = img.width; |
| 109 | + this.imageHeight = img.height; |
77 | 110 | this.loading = false;
|
78 | 111 | this.$emit('load', e);
|
79 | 112 | },
|
|
117 | 150 | off(_scrollContainer, 'scroll', _lazyLoadHandler);
|
118 | 151 | this._scrollContainer = null;
|
119 | 152 | this._lazyLoadHandler = null;
|
| 153 | + }, |
| 154 | + /** |
| 155 | + * simulate object-fit behavior to compatible with IE11 and other browsers which not support object-fit |
| 156 | + */ |
| 157 | + getImageStyle(fit) { |
| 158 | + const { imageWidth, imageHeight } = this; |
| 159 | + const { |
| 160 | + clientWidth: containerWidth, |
| 161 | + clientHeight: containerHeight |
| 162 | + } = this.$el; |
| 163 | +
|
| 164 | + if (!imageWidth || !imageHeight || !containerWidth || !containerHeight) return {}; |
| 165 | +
|
| 166 | + const vertical = imageWidth / imageHeight < 1; |
| 167 | +
|
| 168 | + if (fit === ObjectFit.SCALE_DOWN) { |
| 169 | + const isSmaller = imageWidth < containerWidth && imageHeight < containerHeight; |
| 170 | + fit = isSmaller ? ObjectFit.NONE : ObjectFit.CONTAIN; |
| 171 | + } |
| 172 | +
|
| 173 | + switch (fit) { |
| 174 | + case ObjectFit.NONE: |
| 175 | + return { width: 'auto', height: 'auto' }; |
| 176 | + case ObjectFit.CONTAIN: |
| 177 | + return vertical ? { width: 'auto' } : { height: 'auto' }; |
| 178 | + case ObjectFit.COVER: |
| 179 | + return vertical ? { height: 'auto' } : { width: 'auto' }; |
| 180 | + default: |
| 181 | + return {}; |
| 182 | + } |
120 | 183 | }
|
121 | 184 | }
|
122 | 185 | };
|
|
0 commit comments