mirror of https://github.com/ElemeFE/element
Image: add image component (#15117)
parent
686595627e
commit
d9462ab771
|
@ -70,5 +70,6 @@
|
|||
"footer": "./packages/footer/index.js",
|
||||
"timeline": "./packages/timeline/index.js",
|
||||
"timeline-item": "./packages/timeline-item/index.js",
|
||||
"divider": "./packages/divider/index.js"
|
||||
"divider": "./packages/divider/index.js",
|
||||
"image": "./packages/image/index.js"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
@keyframes dot {
|
||||
0% { width: 0; margin-right: 1em; }
|
||||
100% { width: 1em; margin-right: 0; }
|
||||
}
|
||||
|
||||
.demo-image {
|
||||
.block {
|
||||
padding: 30px 0;
|
||||
text-align: center;
|
||||
border-right: solid 1px #eff2f6;
|
||||
display: inline-block;
|
||||
width: 20%;
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
display: block;
|
||||
color: #8492a6;
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-image__placeholder, .demo-image__error {
|
||||
@extend .demo-image;
|
||||
|
||||
.block {
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.el-image {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.image-slot {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #f5f7fa;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-image__placeholder {
|
||||
.dot {
|
||||
animation: dot 2s infinite steps(3, start);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-image__error {
|
||||
.image-slot {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-image__lazy {
|
||||
height: 400px;
|
||||
overflow-y: auto;
|
||||
|
||||
.el-image {
|
||||
display: block;
|
||||
min-height: 200px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,3 +39,4 @@
|
|||
@import "./typography.scss";
|
||||
@import "./upload.scss";
|
||||
@import "./divider.scss";
|
||||
@import "./image.scss";
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
## Image
|
||||
Besides the native features of img, support lazy load, custom placeholder and load failure, etc.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
:::demo Indicate how the image should be resized to fit its container by `fit`, same as native [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)。
|
||||
```html
|
||||
<div class="demo-image">
|
||||
<div class="block" v-for="fit in fits" :key="fit">
|
||||
<span class="demonstration">{{ fit }}</span>
|
||||
<el-image
|
||||
style="width: 100px; height: 100px"
|
||||
:src="url"
|
||||
:fit="fit"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fits: ['fill', 'contain', 'cover', 'none', 'scale-down'],
|
||||
url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Placeholder
|
||||
|
||||
:::demo Custom placeholder content when image hasn't loaded yet by `slot = placeholder`
|
||||
```html
|
||||
<div class="demo-image__placeholder">
|
||||
<div class="block">
|
||||
<span class="demonstration">Default</span>
|
||||
<el-image :src="src"></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Custom</span>
|
||||
<el-image :src="src">
|
||||
<div slot="placeholder" class="image-slot">
|
||||
Loading<span class="dot">...</span>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Load Failed
|
||||
|
||||
:::demo Custom failed content when error occurs to image load by `slot = error`
|
||||
```html
|
||||
<div class="demo-image__error">
|
||||
<div class="block">
|
||||
<span class="demonstration">Default</span>
|
||||
<el-image></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Custom</span>
|
||||
<el-image>
|
||||
<div slot="error" class="image-slot">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
:::
|
||||
|
||||
### Lazy Load
|
||||
|
||||
:::demo Use lazy load by `lazy = true`. Image will load until scroll into view when set. You can indicate scroll container that adds scroll listener to by `scroll-container`. If undefined, will be the nearest parent container whose overflow property is auto or scroll.
|
||||
```html
|
||||
<div class="demo-image__lazy">
|
||||
<el-image v-for="url in urls" :key="url" :src="url" lazy></el-image>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
urls: [
|
||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Attributes
|
||||
| Attribute | Description | Type | Accepted values | Default |
|
||||
|---------- |-------- |---------- |------------- |-------- |
|
||||
| src | Image source, same as native | string | — | - |
|
||||
| fit | Indicate how the image should be resized to fit its container, same as [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) | fill / contain / cover / none / scale-down | — | - |
|
||||
| alt | Native alt | string | - | - |
|
||||
| lazy | Whether to use lazy load | boolean | — | false |
|
||||
| scroll-container | The container to add scroll listener when using lazy load | string / HTMLElement | — | The nearest parent container whose overflow property is auto or scroll |
|
||||
|
||||
### Events
|
||||
| Event Name | Description | Parameters |
|
||||
|---------- |-------- |---------- |
|
||||
| load | Same as native load | (e: Event) |
|
||||
| error | Same as native error | (e: Error) |
|
||||
|
||||
### Slots
|
||||
| Slot Name | Description |
|
||||
|---------|-------------|
|
||||
| placeholder | Triggers when image load |
|
||||
| error | Triggers when image load failed |
|
||||
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
## Image
|
||||
Besides the native features of img, support lazy load, custom placeholder and load failure, etc.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
:::demo Indicate how the image should be resized to fit its container by `fit`, same as native [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)。
|
||||
```html
|
||||
<div class="demo-image">
|
||||
<div class="block" v-for="fit in fits" :key="fit">
|
||||
<span class="demonstration">{{ fit }}</span>
|
||||
<el-image
|
||||
style="width: 100px; height: 100px"
|
||||
:src="url"
|
||||
:fit="fit"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fits: ['fill', 'contain', 'cover', 'none', 'scale-down'],
|
||||
url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Placeholder
|
||||
|
||||
:::demo Custom placeholder content when image hasn't loaded yet by `slot = placeholder`
|
||||
```html
|
||||
<div class="demo-image__placeholder">
|
||||
<div class="block">
|
||||
<span class="demonstration">Default</span>
|
||||
<el-image :src="src"></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Custom</span>
|
||||
<el-image :src="src">
|
||||
<div slot="placeholder" class="image-slot">
|
||||
Loading<span class="dot">...</span>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Load Failed
|
||||
|
||||
:::demo Custom failed content when error occurs to image load by `slot = error`
|
||||
```html
|
||||
<div class="demo-image__error">
|
||||
<div class="block">
|
||||
<span class="demonstration">Default</span>
|
||||
<el-image></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Custom</span>
|
||||
<el-image>
|
||||
<div slot="error" class="image-slot">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
:::
|
||||
|
||||
### Lazy Load
|
||||
|
||||
:::demo Use lazy load by `lazy = true`. Image will load until scroll into view when set. You can indicate scroll container that adds scroll listener to by `scroll-container`. If undefined, will be the nearest parent container whose overflow property is auto or scroll.
|
||||
```html
|
||||
<div class="demo-image__lazy">
|
||||
<el-image v-for="url in urls" :key="url" :src="url" lazy></el-image>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
urls: [
|
||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Attributes
|
||||
| Attribute | Description | Type | Accepted values | Default |
|
||||
|---------- |-------- |---------- |------------- |-------- |
|
||||
| src | Image source, same as native | string | — | - |
|
||||
| fit | Indicate how the image should be resized to fit its container, same as [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) | fill / contain / cover / none / scale-down | — | - |
|
||||
| alt | Native alt | string | - | - |
|
||||
| lazy | Whether to use lazy load | boolean | — | false |
|
||||
| scroll-container | The container to add scroll listener when using lazy load | string / HTMLElement | — | The nearest parent container whose overflow property is auto or scroll |
|
||||
|
||||
### Events
|
||||
| Event Name | Description | Parameters |
|
||||
|---------- |-------- |---------- |
|
||||
| load | Same as native load | (e: Event) |
|
||||
| error | Same as native error | (e: Error) |
|
||||
|
||||
### Slots
|
||||
| Slot Name | Description |
|
||||
|---------|-------------|
|
||||
| placeholder | Triggers when image load |
|
||||
| error | Triggers when image load failed |
|
||||
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
## Image
|
||||
Besides the native features of img, support lazy load, custom placeholder and load failure, etc.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
:::demo Indicate how the image should be resized to fit its container by `fit`, same as native [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)。
|
||||
```html
|
||||
<div class="demo-image">
|
||||
<div class="block" v-for="fit in fits" :key="fit">
|
||||
<span class="demonstration">{{ fit }}</span>
|
||||
<el-image
|
||||
style="width: 100px; height: 100px"
|
||||
:src="url"
|
||||
:fit="fit"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fits: ['fill', 'contain', 'cover', 'none', 'scale-down'],
|
||||
url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Placeholder
|
||||
|
||||
:::demo Custom placeholder content when image hasn't loaded yet by `slot = placeholder`
|
||||
```html
|
||||
<div class="demo-image__placeholder">
|
||||
<div class="block">
|
||||
<span class="demonstration">Default</span>
|
||||
<el-image :src="src"></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Custom</span>
|
||||
<el-image :src="src">
|
||||
<div slot="placeholder" class="image-slot">
|
||||
Loading<span class="dot">...</span>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Load Failed
|
||||
|
||||
:::demo Custom failed content when error occurs to image load by `slot = error`
|
||||
```html
|
||||
<div class="demo-image__error">
|
||||
<div class="block">
|
||||
<span class="demonstration">Default</span>
|
||||
<el-image></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Custom</span>
|
||||
<el-image>
|
||||
<div slot="error" class="image-slot">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
:::
|
||||
|
||||
### Lazy Load
|
||||
|
||||
:::demo Use lazy load by `lazy = true`. Image will load until scroll into view when set. You can indicate scroll container that adds scroll listener to by `scroll-container`. If undefined, will be the nearest parent container whose overflow property is auto or scroll.
|
||||
```html
|
||||
<div class="demo-image__lazy">
|
||||
<el-image v-for="url in urls" :key="url" :src="url" lazy></el-image>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
urls: [
|
||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Attributes
|
||||
| Attribute | Description | Type | Accepted values | Default |
|
||||
|---------- |-------- |---------- |------------- |-------- |
|
||||
| src | Image source, same as native | string | — | - |
|
||||
| fit | Indicate how the image should be resized to fit its container, same as [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) | fill / contain / cover / none / scale-down | — | - |
|
||||
| alt | Native alt | string | - | - |
|
||||
| lazy | Whether to use lazy load | boolean | — | false |
|
||||
| scroll-container | The container to add scroll listener when using lazy load | string / HTMLElement | — | The nearest parent container whose overflow property is auto or scroll |
|
||||
|
||||
### Events
|
||||
| Event Name | Description | Parameters |
|
||||
|---------- |-------- |---------- |
|
||||
| load | Same as native load | (e: Event) |
|
||||
| error | Same as native error | (e: Error) |
|
||||
|
||||
### Slots
|
||||
| Slot Name | Description |
|
||||
|---------|-------------|
|
||||
| placeholder | Triggers when image load |
|
||||
| error | Triggers when image load failed |
|
||||
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
## Image 图片
|
||||
图片容器,在保留原生img的特性下,支持懒加载,自定义占位、加载失败等
|
||||
|
||||
### 基础用法
|
||||
|
||||
:::demo 可通过`fit`确定图片如何适应到容器框,同原生 [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)。
|
||||
```html
|
||||
<div class="demo-image">
|
||||
<div class="block" v-for="fit in fits" :key="fit">
|
||||
<span class="demonstration">{{ fit }}</span>
|
||||
<el-image
|
||||
style="width: 100px; height: 100px"
|
||||
:src="url"
|
||||
:fit="fit"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fits: ['fill', 'contain', 'cover', 'none', 'scale-down'],
|
||||
url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### 占位内容
|
||||
|
||||
:::demo 可通过`slot = placeholder`可自定义占位内容
|
||||
```html
|
||||
<div class="demo-image__placeholder">
|
||||
<div class="block">
|
||||
<span class="demonstration">默认</span>
|
||||
<el-image :src="src"></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">自定义</span>
|
||||
<el-image :src="src">
|
||||
<div slot="placeholder" class="image-slot">
|
||||
加载中<span class="dot">...</span>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### 加载失败
|
||||
|
||||
:::demo 可通过`slot = error`可自定义加载失败内容
|
||||
```html
|
||||
<div class="demo-image__error">
|
||||
<div class="block">
|
||||
<span class="demonstration">默认</span>
|
||||
<el-image></el-image>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">自定义</span>
|
||||
<el-image>
|
||||
<div slot="error" class="image-slot">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</div>
|
||||
</el-image>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
:::
|
||||
|
||||
### 懒加载
|
||||
|
||||
:::demo 可通过`lazy`开启懒加载功能,当图片滚动到可视范围内才会加载。可通过`scroll-container`来设置滚动容器,若未定义,则为最近一个`overflow`值为`auto`或`scroll`的父元素。
|
||||
```html
|
||||
<div class="demo-image__lazy">
|
||||
<el-image v-for="url in urls" :key="url" :src="url" lazy></el-image>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
urls: [
|
||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Attributes
|
||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
||||
|---------- |-------- |---------- |------------- |-------- |
|
||||
| src | 图片源,同原生 | string | — | - |
|
||||
| fit | 确定图片如何适应容器框,同原生 [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) | fill / contain / cover / none / scale-down | — | - |
|
||||
| alt | 原生 alt | string | - | - |
|
||||
| lazy | 是否开启懒加载 | boolean | — | false |
|
||||
| scroll-container | 开启懒加载后,监听 scroll 事件的容器 | string / HTMLElement | — | 最近一个 overflow 值为 auto 或 scroll 的父元素 |
|
||||
|
||||
### Events
|
||||
| 事件名称 | 说明 | 回调参数 |
|
||||
|---------- |-------- |---------- |
|
||||
| load | 图片加载成功触发 | (e: Event) |
|
||||
| error | 图片加载失败触发 | (e: Error) |
|
||||
|
||||
### Slots
|
||||
| 名称 | 说明 |
|
||||
|---------|-------------|
|
||||
| placeholder | 图片未加载的占位内容 |
|
||||
| error | 加载失败的内容 |
|
||||
|
||||
|
|
@ -255,6 +255,10 @@
|
|||
{
|
||||
"path": "/divider",
|
||||
"title": "Divider 分割线"
|
||||
},
|
||||
{
|
||||
"path": "/image",
|
||||
"title": "Image"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -517,6 +521,10 @@
|
|||
{
|
||||
"path": "/divider",
|
||||
"title": "Divider"
|
||||
},
|
||||
{
|
||||
"path": "/image",
|
||||
"title": "Image"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -779,6 +787,10 @@
|
|||
{
|
||||
"path": "/divider",
|
||||
"title": "Divider"
|
||||
},
|
||||
{
|
||||
"path": "/image",
|
||||
"title": "Image"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1041,6 +1053,10 @@
|
|||
{
|
||||
"path": "/divider",
|
||||
"title": "Divider"
|
||||
},
|
||||
{
|
||||
"path": "/image",
|
||||
"title": "Image 图片"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import Image from './src/main';
|
||||
|
||||
/* istanbul ignore next */
|
||||
Image.install = function(Vue) {
|
||||
Vue.component(Image.name, Image);
|
||||
};
|
||||
|
||||
export default Image;
|
|
@ -0,0 +1,123 @@
|
|||
<template>
|
||||
<div class="el-image">
|
||||
<slot v-if="loading" name="placeholder">
|
||||
<div class="el-image__placeholder"></div>
|
||||
</slot>
|
||||
<slot v-else-if="error" name="error">
|
||||
<div class="el-image__error">{{ t('el.image.error') }}</div>
|
||||
</slot>
|
||||
<img
|
||||
v-else
|
||||
class="el-image__inner"
|
||||
:src="src"
|
||||
:alt="alt"
|
||||
:style="{ 'object-fit': fit }">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import { on, off, getScrollContainer, isInContainer } from 'element-ui/src/utils/dom';
|
||||
import { isString, isHtmlElement } from 'element-ui/src/utils/types';
|
||||
import throttle from 'throttle-debounce/throttle';
|
||||
|
||||
export default {
|
||||
name: 'ElImage',
|
||||
|
||||
mixins: [Locale],
|
||||
|
||||
props: {
|
||||
src: String,
|
||||
fit: String,
|
||||
lazy: Boolean,
|
||||
scrollContainer: [String, HTMLElement],
|
||||
alt: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
error: false,
|
||||
show: !this.lazy
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
src: {
|
||||
handler(val) {
|
||||
this.show && this.loadImage(val);
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
show(val) {
|
||||
val && this.loadImage(this.src);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.lazy && this.addLazyLoadListener();
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.lazy && this.removeLazyLoadListener();
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadImage(val) {
|
||||
// reset status
|
||||
this.loading = true;
|
||||
this.error = false;
|
||||
|
||||
const img = new Image();
|
||||
img.onload = this.handleLoad.bind(this);
|
||||
img.onerror = this.handleError.bind(this);
|
||||
img.src = val;
|
||||
},
|
||||
handleLoad(e) {
|
||||
this.loading = false;
|
||||
this.$emit('load', e);
|
||||
},
|
||||
handleError(e) {
|
||||
this.loading = false;
|
||||
this.error = true;
|
||||
this.$emit('error', e);
|
||||
},
|
||||
handleLazyLoad() {
|
||||
if (isInContainer(this.$el, this._scrollContainer)) {
|
||||
this.show = true;
|
||||
this.removeLazyLoadListener();
|
||||
}
|
||||
},
|
||||
addLazyLoadListener() {
|
||||
if (this.$isServer) return;
|
||||
|
||||
const { scrollContainer } = this;
|
||||
let _scrollContainer = null;
|
||||
|
||||
if (isHtmlElement(scrollContainer)) {
|
||||
_scrollContainer = scrollContainer;
|
||||
} else if (isString(scrollContainer)) {
|
||||
_scrollContainer = document.querySelector(scrollContainer);
|
||||
} else {
|
||||
_scrollContainer = getScrollContainer(this.$el);
|
||||
}
|
||||
|
||||
if (_scrollContainer) {
|
||||
this._scrollContainer = _scrollContainer;
|
||||
this._lazyLoadHandler = throttle(200, this.handleLazyLoad);
|
||||
on(_scrollContainer, 'scroll', this._lazyLoadHandler);
|
||||
this.handleLazyLoad();
|
||||
}
|
||||
},
|
||||
removeLazyLoadListener() {
|
||||
const { _scrollContainer, _lazyLoadHandler } = this;
|
||||
|
||||
if (this.$isServer || !_scrollContainer || !_lazyLoadHandler) return;
|
||||
|
||||
off(_scrollContainer, 'scroll', _lazyLoadHandler);
|
||||
this._scrollContainer = null;
|
||||
this._lazyLoadHandler = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,32 @@
|
|||
@import "mixins/mixins";
|
||||
@import "common/var";
|
||||
|
||||
%size {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@include b(image) {
|
||||
display: inline-block;
|
||||
|
||||
@include e(inner) {
|
||||
@extend %size;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@include e(placeholder) {
|
||||
@extend %size;
|
||||
background: $--background-color-base;
|
||||
}
|
||||
|
||||
@include e(error) {
|
||||
@extend %size;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
background: $--background-color-base;
|
||||
color: $--color-text-placeholder;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
|
@ -68,3 +68,4 @@
|
|||
@import "./timeline.scss";
|
||||
@import "./timeline-item.scss";
|
||||
@import "./divider.scss";
|
||||
@import "./image.scss";
|
||||
|
|
|
@ -72,6 +72,7 @@ import Footer from '../packages/footer/index.js';
|
|||
import Timeline from '../packages/timeline/index.js';
|
||||
import TimelineItem from '../packages/timeline-item/index.js';
|
||||
import Divider from '../packages/divider/index.js';
|
||||
import Image from '../packages/image/index.js';
|
||||
import locale from 'element-ui/src/locale';
|
||||
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';
|
||||
|
||||
|
@ -144,6 +145,7 @@ const components = [
|
|||
Timeline,
|
||||
TimelineItem,
|
||||
Divider,
|
||||
Image,
|
||||
CollapseTransition
|
||||
];
|
||||
|
||||
|
@ -254,5 +256,6 @@ export default {
|
|||
Footer,
|
||||
Timeline,
|
||||
TimelineItem,
|
||||
Divider
|
||||
Divider,
|
||||
Image
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Voer sleutelwoord in',
|
||||
noCheckedFormat: '{total} items',
|
||||
hasCheckedFormat: '{checked}/{total} gekies'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'ادخل كلمة',
|
||||
noCheckedFormat: '{total} عناصر',
|
||||
hasCheckedFormat: '{checked}/{total} مختار'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Introdueix la paraula clau',
|
||||
noCheckedFormat: '{total} ítems',
|
||||
hasCheckedFormat: '{checked}/{total} seleccionats'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -106,6 +106,9 @@ export default {
|
|||
filterPlaceholder: 'Klíčové slovo',
|
||||
noCheckedFormat: '{total} položek',
|
||||
hasCheckedFormat: '{checked}/{total} vybráno'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Indtast søgeord',
|
||||
noCheckedFormat: '{total} emner',
|
||||
hasCheckedFormat: '{checked}/{total} valgt'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -105,6 +105,9 @@ export default {
|
|||
filterPlaceholder: 'Einträge filtern',
|
||||
noCheckedFormat: '{total} Einträge',
|
||||
hasCheckedFormat: '{checked}/{total} ausgewählt'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Sisesta märksõna',
|
||||
noCheckedFormat: '{total} objekti',
|
||||
hasCheckedFormat: '{checked}/{total} valitud'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Αναζήτηση',
|
||||
noCheckedFormat: '{total} Αντικείμενα',
|
||||
hasCheckedFormat: '{checked}/{total} επιλεγμένα'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Ingresar palabra clave',
|
||||
noCheckedFormat: '{total} artículos',
|
||||
hasCheckedFormat: '{checked}/{total} revisados'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Sartu gako-hitza', // to be translated
|
||||
noCheckedFormat: '{total} elementu', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} hautatuta' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'کلید واژه هارو وارد کن',
|
||||
noCheckedFormat: '{total} مورد',
|
||||
hasCheckedFormat: '{checked} مورد از {total} مورد انتخاب شده است'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Syötä hakusana',
|
||||
noCheckedFormat: '{total} kohdetta',
|
||||
hasCheckedFormat: '{checked}/{total} valittu'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Entrer un mot clef',
|
||||
noCheckedFormat: '{total} elements',
|
||||
hasCheckedFormat: '{checked}/{total} coché(s)'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'הקלד',
|
||||
noCheckedFormat: 'פריטים {total}',
|
||||
hasCheckedFormat: ' אישור {checked}/{total}'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Unesite ključnu riječ', // to be translated
|
||||
noCheckedFormat: '{total} stavki', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Kulcsszó',
|
||||
noCheckedFormat: '{total} elem',
|
||||
hasCheckedFormat: '{checked}/{total} kiválasztva'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Մուտքագրեք բանալի բառ',
|
||||
noCheckedFormat: '{total} միաւոր',
|
||||
hasCheckedFormat: '{checked}/{total} ընտրուած է'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Masukan kata kunci',
|
||||
noCheckedFormat: '{total} butir',
|
||||
hasCheckedFormat: '{checked}/{total} terpilih'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Inserisci filtro',
|
||||
noCheckedFormat: '{total} elementi',
|
||||
hasCheckedFormat: '{checked}/{total} selezionati'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'キーワードを入力',
|
||||
noCheckedFormat: '総計 {total} 件',
|
||||
hasCheckedFormat: '{checked}/{total} を選択した'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Сураныч, издөө кирет',
|
||||
noCheckedFormat: 'бүтүндөй {total} сан',
|
||||
hasCheckedFormat: 'Тандалган {checked}/{total} сан'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'បញ្ចូលពាក្យ',
|
||||
noCheckedFormat: '{total} ធាតុ',
|
||||
hasCheckedFormat: '{checked}/{total} បានគូសធីក'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: ' 입력하세요',
|
||||
noCheckedFormat: '{total} 항목',
|
||||
hasCheckedFormat: '{checked}/{total} 선택됨'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Binivîse',
|
||||
noCheckedFormat: '{total} lib',
|
||||
hasCheckedFormat: '{checked}/{total} bijartin'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Кілт сөзді енгізіңіз',
|
||||
noCheckedFormat: '{total} элэмэнт',
|
||||
hasCheckedFormat: '{checked}/{total} құсбелгісі қойылды'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Įvesk raktažodį',
|
||||
noCheckedFormat: 'Viso: {total}',
|
||||
hasCheckedFormat: 'Pažymėta {checked} iš {total}'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Ievadīt atslēgvārdu',
|
||||
noCheckedFormat: '{total} vienības',
|
||||
hasCheckedFormat: '{checked}/{total} atzīmēti'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Утга оруул',
|
||||
noCheckedFormat: '{total} өгөгдөл',
|
||||
hasCheckedFormat: '{checked}/{total} сонгосон'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Geef zoekwoerd',
|
||||
noCheckedFormat: '{total} items',
|
||||
hasCheckedFormat: '{checked}/{total} geselecteerd'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Wpisz szukaną frazę',
|
||||
noCheckedFormat: 'razem: {total}',
|
||||
hasCheckedFormat: 'wybranych: {checked}/{total}'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Digite uma palavra-chave',
|
||||
noCheckedFormat: '{total} itens',
|
||||
hasCheckedFormat: '{checked}/{total} selecionados'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Introduceți cuvântul cheie',
|
||||
noCheckedFormat: '{total} elemente',
|
||||
hasCheckedFormat: '{checked}/{total} verificate'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Введите ключевое слово',
|
||||
noCheckedFormat: '{total} пунктов',
|
||||
hasCheckedFormat: '{checked}/{total} выбрано'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -106,6 +106,9 @@ export default {
|
|||
filterPlaceholder: 'Filtrovať podľa',
|
||||
noCheckedFormat: '{total} položiek',
|
||||
hasCheckedFormat: '{checked}/{total} označených'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Vnesi ključno besedo',
|
||||
noCheckedFormat: '{total} elementov',
|
||||
hasCheckedFormat: '{checked}/{total} izbranih'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Унеси кључну реч', // to be translated
|
||||
noCheckedFormat: '{total} ставки', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} обележених' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
|||
filterPlaceholder: 'சொல்லை உள்ளீடு செய்',
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} தேர்வு செய்யப்பட்டவைகள்'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Gözleg sözlerini giriziň',
|
||||
noCheckedFormat: '{total} sany',
|
||||
hasCheckedFormat: '{checked}/{total} saýlanan'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Anahtar kelimeleri gir',
|
||||
noCheckedFormat: '{total} adet',
|
||||
hasCheckedFormat: '{checked}/{total} seçildi'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Введіть ключове слово',
|
||||
noCheckedFormat: '{total} пунктів',
|
||||
hasCheckedFormat: '{checked}/{total} вибрано'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'ئىزدىمەكچى بولغان مەزمۇننى كىرگۈزۈڭ',
|
||||
noCheckedFormat: 'جەمئىي {total} تۈر',
|
||||
hasCheckedFormat: 'تاللانغىنى {checked}/{total} تۈر'
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Nhập từ khóa',
|
||||
noCheckedFormat: '{total} mục',
|
||||
hasCheckedFormat: '{checked}/{total} đã chọn '
|
||||
},
|
||||
image: {
|
||||
error: 'FAILED' // to be translated
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: '请输入搜索内容',
|
||||
noCheckedFormat: '共 {total} 项',
|
||||
hasCheckedFormat: '已选 {checked}/{total} 项'
|
||||
},
|
||||
image: {
|
||||
error: '加载失败'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -104,6 +104,9 @@ export default {
|
|||
filterPlaceholder: 'Enter keyword', // to be translated
|
||||
noCheckedFormat: '{total} items', // to be translated
|
||||
hasCheckedFormat: '{checked}/{total} checked' // to be translated
|
||||
},
|
||||
image: {
|
||||
error: '加載失敗'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -172,3 +172,56 @@ export function setStyle(element, styleName, value) {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const isScroll = (el, vertical) => {
|
||||
if (isServer) return;
|
||||
|
||||
const determinedDirection = vertical !== null || vertical !== undefined;
|
||||
const overflow = determinedDirection
|
||||
? vertical
|
||||
? getStyle(el, 'overflow-y')
|
||||
: getStyle(el, 'overflow-x')
|
||||
: getStyle(el, 'overflow');
|
||||
|
||||
return overflow.match(/(scroll|auto)/);
|
||||
};
|
||||
|
||||
export const getScrollContainer = (el, vertical) => {
|
||||
if (isServer) return;
|
||||
|
||||
let parent = el;
|
||||
while (parent) {
|
||||
if ([window, document, document.documentElement].includes(parent)) {
|
||||
return window;
|
||||
}
|
||||
if (isScroll(parent, vertical)) {
|
||||
return parent;
|
||||
}
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
|
||||
return parent;
|
||||
};
|
||||
|
||||
export const isInContainer = (el, container) => {
|
||||
if (isServer || !el || !container) return false;
|
||||
|
||||
const elRect = el.getBoundingClientRect();
|
||||
let containerRect;
|
||||
|
||||
if ([window, document, document.documentElement, null, undefined].includes(container)) {
|
||||
containerRect = {
|
||||
top: 0,
|
||||
right: window.innerWidth,
|
||||
bottom: window.innerHeight,
|
||||
left: 0
|
||||
};
|
||||
} else {
|
||||
containerRect = container.getBoundingClientRect();
|
||||
}
|
||||
|
||||
return elRect.top < containerRect.bottom &&
|
||||
elRect.bottom > containerRect.top &&
|
||||
elRect.right > containerRect.left &&
|
||||
elRect.left < containerRect.right;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
export function isString(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object String]';
|
||||
}
|
||||
|
||||
export function isObject(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Object]';
|
||||
}
|
||||
|
||||
export function isHtmlElement(node) {
|
||||
return node && node.nodeType === Node.ELEMENT_NODE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import { createTest, createVue, destroyVM, wait } from '../util';
|
||||
import Image from 'packages/image';
|
||||
|
||||
const src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAFmklEQVR4Xu2ba2wUVRTH/2cWtlaooFQwKpr4CkESTQBNUAkodGeaKFGD2u6WGPyAmmAEEZmpj1VhBghE/KKGBIztDIXAByWBnQ1oQREfARNiDDHiF1+ooBiksVt295hFiqSdxx3KdmcH5uv+z+3//O65c19TwgX+0AWePy4CuFgBISCQ3J6+DFLuVQKmg2k4gK3xuvwr6+9e+Xe57YViCCRttY1ALX2S/asIPLRB1jvLCSEUAFK2egKgYf0T5a6TxdhtmxqXfl8uCBUHMHfP4rqeE0OOeyS4w5T1hsgCmLNTvaWYp299EpxoyvpX5YBQ8QpotlvvkMBfeCbHvMpUjOejCSCjPSYROrySY/B+SzYmRRJA0tZWEfCcJwBGz81yvDZN6eL5hlDxIZCyta8BTPBLjIv5sVbjyp/8dEF/ryiAlL3kJkD6TsQ0STS5vWHZPhFtEE1FAYiUf28yBaZ7OpRle4IkJ6KtGIDZexfU1hyv/QXASBGjBeYpHYrxmYg2iKZiAFIZdSGIVouaLVJx0obE8v2ielFdRQA83pkemc/lDgE0StRopF6CSVuzCGgWTb6ku7T+aHztpLUng8SIaAe9ApJ265MEflvE3P8a/t2UjTHBYsTUgwqgKauOk4p0gAhxMXunVcwfmYpxX6AYQfGgAWjqTNdL3bndRDRe0NsZGYPXWLKxIGiciH5QAJye8r4UWfE5mWbCE1ZCXy+SUFBN2QEo2+fXjKK6zSDcH9Rcr55i0vj2mUsPnmu8V1xZAZxKXhq+G6A7z9U8Mx+zFOOKc433iysbgNKYj3XnNoHoXj8T3r/z+6ZsPDiwNtyjHQE07dTGSAU8QkX4LlSY6Ndh9UfWnT1Ht2QXjeZifC8INw7UOAMfE2MgB6NdhaFo65ih/+bkxRFAMqPuIaK7xM3zu6ZszO3Vt2S1CcwobXPD8TAfoZjU6LSb7AdgWmd6yLW5nqArrm5T1mtDC+A/Y3tNWe/XqY4VkLK1fwBcItp9DGZLNqQwA2DmgiUbQ0Hgs/NyBpBRD4PoqigBKOWSGxuv2XxruscXQNJWDxJoXJQAMPCnJev9XuouQ0D9PMjcXQ1DAIx9pqJP7tupLrOAZhMhEaUKAGOjqehNYgBsdSOBHo0UAOBlU9ZfFwOQUd8honmRAsA8y1SMrWIAbHUFgRZHCUCe6LqNiWU/igHIaCoR9KgAYMZRS9GvFF4Kp7LqU2B6KzoAeKulGLOEASRtrZkAK0IAVEsxlgsDaM6ojRLRtqgAIImntTcYu4UBpLKtU8D8aRQAMJD/uSZeu2t6Oi8MILldHU8SfRMFAG67wN7cHFeCcz5svaZ4koWvosO9FGbdlI1Wt850BNCSXTSMOX4iEhVAaDAT+o5AAEriVEYrgHBmj+8FI7QVwJzLjei+fPOUN0rnG46P66FoMqMdIUK9SBWEGIDvjZIrgFRGOyR6qBlWAMzQLEU3vDrRvQJsdR+BJlZzBYh8VuM1BHYSQehCMpwVwF1mwqjrewYotBk69RK0tS0AHq7eChC7UPEYAto6As6c9VfdLED8tJkwfL9DcH8J2upqgBZWbwXgalPWD/v59wCgvQTgNb8GSr+H7x3AB0zZuF3EuyuA5oz6jET0pkgjYQPAzEstxSh1oO/jVQFzALzn20IIK0CKFa5vm7niBxHvHgsh9QEQfSDSSP8KWDSaOe54GyvS3sA0vMuUjemibbgPgWzrVInZ8RChb+N9AQSdRkXNiul4qikbn4hp4f5/g7N3vDAiXpCOEcj/IwpG0VT02Nl/9NSOshjvGMinMaJJ9OqYeYulGLODxHkml7TVZ8GYT0Q3uDfKXQxaY8n6i06aZnvJDGKaB8JMAo0IYk5UW7r5BbAtNhRz22YYf4jGlXT+vRuktSrUXgRQhZ12Xi1f8BXwL38cy1+mrtJNAAAAAElFTkSuQmCC';
|
||||
|
||||
describe('Image', () => {
|
||||
let vm;
|
||||
|
||||
afterEach(() => {
|
||||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('create', async() => {
|
||||
vm = createTest(Image, {
|
||||
src,
|
||||
fit: 'fill'
|
||||
}, true);
|
||||
const placeholder = vm.$el.querySelector('.el-image__placeholder');
|
||||
const error = vm.$el.querySelector('.el-image__error');
|
||||
let img = vm.$el.querySelector('.el-image__inner');
|
||||
expect(placeholder).to.exist;
|
||||
expect(error).to.be.null;
|
||||
expect(img).to.be.null;
|
||||
|
||||
await wait();
|
||||
img = vm.$el.querySelector('.el-image__inner');
|
||||
expect(img.style.objectFit).to.equal('fill');
|
||||
});
|
||||
|
||||
it('load failed', async() => {
|
||||
vm = createTest(Image, true);
|
||||
await wait();
|
||||
const error = vm.$el.querySelector('.el-image__error');
|
||||
expect(error).to.be.exist;
|
||||
});
|
||||
|
||||
it('lazy load', async() => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<div ref="wrapper" style="height: 200px; overflow: auto;">
|
||||
<el-image
|
||||
v-for="item in 2"
|
||||
:key="item"
|
||||
:src="src"
|
||||
ref="image"
|
||||
style="display: block; height: 200px;"
|
||||
lazy></el-image>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
src
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
const { image, wrapper } = vm.$refs;
|
||||
const [image1, image2] = image;
|
||||
|
||||
await wait();
|
||||
expect(image1.loading).to.be.false;
|
||||
expect(image2.loading).to.be.true;
|
||||
wrapper.scrollTop = 10;
|
||||
|
||||
await wait();
|
||||
expect(image2.loading).to.be.false;
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import { VNode } from 'vue'
|
||||
import { ElementUIComponent } from './component'
|
||||
|
||||
export type ObjectFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
|
||||
|
||||
export interface ImageSlots {
|
||||
/** Placeholder content when image hasn't loaded yet */
|
||||
placeholder: VNode[]
|
||||
|
||||
/** Error content when error occurs to image load */
|
||||
error: VNode[]
|
||||
|
||||
[key: string]: VNode[]
|
||||
}
|
||||
|
||||
/** Image Component */
|
||||
export declare class ElImage extends ElementUIComponent {
|
||||
/** Image source */
|
||||
src: string
|
||||
|
||||
/** Indicate how the image should be resized to fit its container, same as native 'object-fit' */
|
||||
fit: ObjectFit
|
||||
|
||||
/** Whether to use lazy load */
|
||||
lazy: boolean
|
||||
|
||||
/** Scroll container that to add scroll listener when using lazy load */
|
||||
scrollContainer: string | HTMLElement
|
||||
|
||||
/** Native 'alt' attribute */
|
||||
alt: string
|
||||
|
||||
$slots: ImageSlots
|
||||
}
|
Loading…
Reference in New Issue