[new feature] add image component

This commit is contained in:
陈嘉涵 2019-05-17 14:16:45 +08:00
parent 2644689162
commit 1321ba6902
15 changed files with 430 additions and 1 deletions

View File

@ -2,7 +2,7 @@
## 主要变动
- 增加个新组件
- 增加个新组件
- 增加数十个 API
- 全新的卡片风格文档,更直观
- 所有组件支持通过`less`变量自定义样式
@ -12,6 +12,7 @@
在 2.0 版本中,我们按照社区反馈新增以下组件:
- `Image`图片组件
- `Skeleton`骨架屏组件
- `IndexBar``IndexAnchor`索引栏组件
- `DropdownMenu``DropdownItem`下拉菜单组件

View File

@ -22,6 +22,7 @@ export default {
'field': () => wrapper(import('../../packages/field/demo'), 'field'),
'goods-action': () => wrapper(import('../../packages/goods-action/demo'), 'goods-action'),
'icon': () => wrapper(import('../../packages/icon/demo'), 'icon'),
'image': () => wrapper(import('../../packages/image/demo'), 'image'),
'image-preview': () => wrapper(import('../../packages/image-preview/demo'), 'image-preview'),
'index-bar': () => wrapper(import('../../packages/index-bar/demo'), 'index-bar'),
'lazyload': () => wrapper(import('../../packages/lazyload/demo'), 'lazyload'),

View File

@ -89,6 +89,10 @@ module.exports = {
path: '/icon',
title: 'Icon 图标'
},
{
path: '/image',
title: 'Image 图片'
},
{
path: '/col',
title: 'Layout 布局'
@ -408,6 +412,10 @@ module.exports = {
path: '/icon',
title: 'Icon'
},
{
path: '/image',
title: 'Image'
},
{
path: '/col',
title: 'Layout'

View File

@ -51,6 +51,8 @@ export default {
'goods-action.zh-CN': () => import('../../packages/goods-action/zh-CN.md'),
'icon.en-US': () => import('../../packages/icon/en-US.md'),
'icon.zh-CN': () => import('../../packages/icon/zh-CN.md'),
'image.en-US': () => import('../../packages/image/en-US.md'),
'image.zh-CN': () => import('../../packages/image/zh-CN.md'),
'image-preview.en-US': () => import('../../packages/image-preview/en-US.md'),
'image-preview.zh-CN': () => import('../../packages/image-preview/zh-CN.md'),
'index-bar.en-US': () => import('../../packages/index-bar/en-US.md'),

View File

@ -0,0 +1,74 @@
<template>
<demo-section>
<demo-block :title="$t('basicUsage')">
<van-row>
<van-image
width="100"
height="100"
:src="image"
/>
</van-row>
</demo-block>
<demo-block :title="$t('fitMode')">
<van-row gutter="20">
<van-col
v-for="fit in fits"
span="8"
:key="fit"
>
<van-image
:fit="fit"
height="27vw"
:src="image"
/>
<div class="text">{{ fit }}</div>
</van-col>
</van-row>
</demo-block>
</demo-section>
</template>
<script>
export default {
i18n: {
'zh-CN': {
fitMode: '缩放模式'
},
'en-US': {
fitMode: 'Fit Mode'
}
},
data() {
return {
image: 'https://img.yzcdn.cn/vant/cat.jpeg',
fits: ['contain', 'cover', 'fill', 'none', 'scale-down']
};
}
};
</script>
<style lang="less">
@import "../../style/var";
.demo-image {
overflow-x: hidden;
background-color: @white;
.van-row {
padding: 0 15px;
}
.van-col {
margin-bottom: 20px;
}
.text {
margin-top: 5px;
color: @gray-darker;
font-size: 14px;
text-align: center;
}
}
</style>

80
packages/image/en-US.md Normal file
View File

@ -0,0 +1,80 @@
# Image
### Install
``` javascript
import { Image } from 'vant';
Vue.use(Image);
```
## Usage
### Basic Usage
```html
<van-image
width="100"
height="100"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
```
### Fit Mode
```html
<van-image
width="10rem"
height="10rem"
fit="contain"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
```
### Lazy Load
```html
<van-image
width="100"
height="100"
lazy-load
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
```
```js
import { Lazyload } from 'vant';
Vue.use(Lazyload);
```
## API
### Props
| Attribute | Description | Type | Default |
|------|------|------|------|
| src | Src | `String` | - | - |
| fit | Fit mode | `String` | `fill` | - |
| alt | Alt | `String` | - | - |
| width | Width | `String | Number` | - | - |
| height | Height | `String | Number` | - | - |
| lazy-load | Whether to enable lazy loadshould register [Lazyload](#/en-US/lazyload) component | `Boolean` | `false` | - |
### fit optional value
| name | desctription |
|------|------|
| contain | Keep aspect ratio, fully display the long side of the image |
| cover | Keep aspect ratio, fully display the short side of the image, cutting the long side |
| fill | Stretch and resize image to fill the content box |
| none | Not resize image |
| scale-down | Take the smaller of `none` or `contain` |
### Events
| Event | Description | Arguments |
|------|------|------|
| click | Triggered when click image | event: Event |
| load | Triggered when image loaded | - |
| error | Triggered when image load failed | - |

81
packages/image/index.js Normal file
View File

@ -0,0 +1,81 @@
import { use, isDef, suffixPx } from '../utils';
const [sfc, bem] = use('image');
export default sfc({
props: {
src: String,
fit: String,
alt: String,
lazyLoad: Boolean,
width: [String, Number],
height: [String, Number]
},
data() {
return {
loading: true,
error: false
};
},
computed: {
style() {
const style = {};
if (isDef(this.width)) {
style.width = suffixPx(this.width);
}
if (isDef(this.height)) {
style.height = suffixPx(this.height);
}
return style;
}
},
methods: {
onLoad(event) {
this.loading = false;
this.$emit('load', event);
},
onError(event) {
this.error = true;
this.$emit('error', event);
},
onClick(event) {
this.$emit('click', event);
}
},
render(h) {
const imgData = {
class: bem('img'),
attrs: {
alt: this.alt
},
style: {
objectFit: this.fit
},
on: {
load: this.onLoad,
error: this.onError
}
};
const Image = this.lazyLoad ? (
<img vLazy={this.src} {...imgData} />
) : (
<img src={this.src} {...imgData} />
);
return (
<div class={bem()} style={this.style} onClick={this.onClick}>
{Image}
</div>
);
}
});

11
packages/image/index.less Normal file
View File

@ -0,0 +1,11 @@
@import '../style/var';
.van-image {
display: inline-block;
&__img {
display: block;
width: 100%;
height: 100%;
}
}

View File

@ -0,0 +1,35 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders demo correctly 1`] = `
<div>
<div>
<div class="van-row">
<div class="van-image" style="width: 100px; height: 100px;"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img"></div>
</div>
</div>
<div>
<div class="van-row" style="margin-left: -10px; margin-right: -10px;">
<div class="van-col van-col--8" style="padding-left: 10px; padding-right: 10px;">
<div class="van-image" style="height: 27vw;"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: contain;"></div>
<div class="text">contain</div>
</div>
<div class="van-col van-col--8" style="padding-left: 10px; padding-right: 10px;">
<div class="van-image" style="height: 27vw;"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: cover;"></div>
<div class="text">cover</div>
</div>
<div class="van-col van-col--8" style="padding-left: 10px; padding-right: 10px;">
<div class="van-image" style="height: 27vw;"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: fill;"></div>
<div class="text">fill</div>
</div>
<div class="van-col van-col--8" style="padding-left: 10px; padding-right: 10px;">
<div class="van-image" style="height: 27vw;"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: none;"></div>
<div class="text">none</div>
</div>
<div class="van-col van-col--8" style="padding-left: 10px; padding-right: 10px;">
<div class="van-image" style="height: 27vw;"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: scale-down;"></div>
<div class="text">scale-down</div>
</div>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`lazy load 1`] = `<div class="van-image"><img class="van-image__img"></div>`;

View File

@ -0,0 +1,4 @@
import Demo from '../demo';
import demoTest from '../../../test/demo-test';
demoTest(Demo);

View File

@ -0,0 +1,45 @@
import { mount } from '../../../test/utils';
import Image from '..';
test('click event', () => {
const wrapper = mount(Image);
wrapper.trigger('click');
expect(wrapper.emitted('click')[0][0]).toBeTruthy();
});
test('load event', () => {
const wrapper = mount(Image, {
propsData: {
src: 'https://img.yzcdn.cn/vant/cat.jpeg'
}
});
wrapper.find('img').trigger('load');
expect(wrapper.emitted('load')[0][0]).toBeTruthy();
});
test('error event', () => {
const wrapper = mount(Image, {
propsData: {
src: 'https://img.yzcdn.cn/vant/cat.jpeg'
}
});
wrapper.find('img').trigger('error');
expect(wrapper.emitted('error')[0][0]).toBeTruthy();
});
test('lazy load', () => {
const wrapper = mount(Image, {
propsData: {
src: 'https://img.yzcdn.cn/vant/cat.jpeg',
lazyLoad: true
}
});
expect(wrapper).toMatchSnapshot();
});

80
packages/image/zh-CN.md Normal file
View File

@ -0,0 +1,80 @@
# Image 图片
### 引入
``` javascript
import { Image } from 'vant';
Vue.use(Image);
```
## 代码演示
### 基础用法
```html
<van-image
width="100"
height="100"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
```
### 缩放模式
```html
<van-image
width="10rem"
height="10rem"
fit="contain"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
```
### 图片懒加载
```html
<van-image
width="100"
height="100"
lazy-load
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
```
```js
import { Lazyload } from 'vant';
Vue.use(Lazyload);
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|------|------|------|------|------|
| src | 图片链接 | `String` | - | - |
| fit | 图片裁剪、缩放的模式 | `String` | `fill` | - |
| alt | 替代文本 | `String` | - | - |
| width | 宽度,默认单位为 px | `String | Number` | - | - |
| height | 高度,默认单位为 px | `String | Number` | - | - |
| lazy-load | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | `Boolean` | `false` | - |
### fit 可选值
| 名称 | 含义 |
|------|------|
| contain | 保持宽高缩放图片,使图片的长边能完全显示出来 |
| cover | 保持宽高缩放图片,使图片的短边能完全显示出来,裁剪长边 |
| fill | 拉伸图片,使图片填满元素 |
| none | 保持图片原有尺寸 |
| scale-down | 取`none``contain`中较小的一个 |
### Events
| 事件名 | 说明 | 回调参数 |
|------|------|------|
| click | 点击图片时触发 | event: Event |
| load | 图片加载完毕时触发 | - |
| error | 图片加载失败时触发 | - |

View File

@ -8,6 +8,7 @@
/* common components */
@import './col/index';
@import './row/index';
@import './image/index';
@import './circle/index';
@import './collapse-item/index';
@import './list/index';

View File

@ -30,6 +30,7 @@ import GoodsAction from './goods-action';
import GoodsActionButton from './goods-action-button';
import GoodsActionIcon from './goods-action-icon';
import Icon from './icon';
import Image from './image';
import ImagePreview from './image-preview';
import IndexAnchor from './index-anchor';
import IndexBar from './index-bar';
@ -115,6 +116,7 @@ const components = [
GoodsActionButton,
GoodsActionIcon,
Icon,
Image,
ImagePreview,
IndexAnchor,
IndexBar,
@ -205,6 +207,7 @@ export {
GoodsActionButton,
GoodsActionIcon,
Icon,
Image,
ImagePreview,
IndexAnchor,
IndexBar,