diff --git a/example/app.json b/example/app.json
index 0232bc70..4abb3230 100644
--- a/example/app.json
+++ b/example/app.json
@@ -10,6 +10,7 @@
"pages/dialog/index",
"pages/field/index",
"pages/icon/index",
+ "pages/image/index",
"pages/loading/index",
"pages/nav-bar/index",
"pages/notice-bar/index",
@@ -70,6 +71,7 @@
"van-goods-action-icon": "./dist/goods-action-icon/index",
"van-goods-action-button": "./dist/goods-action-button/index",
"van-icon": "./dist/icon/index",
+ "van-image": "./dist/image/index",
"van-loading": "./dist/loading/index",
"van-nav-bar": "./dist/nav-bar/index",
"van-notice-bar": "./dist/notice-bar/index",
diff --git a/example/config.js b/example/config.js
index f650ef67..a01b2d26 100644
--- a/example/config.js
+++ b/example/config.js
@@ -15,6 +15,10 @@ export default [
path: '/icon',
title: 'Icon 图标'
},
+ {
+ path: '/image',
+ title: 'Image 图片'
+ },
{
path: '/col',
title: 'Layout 布局'
diff --git a/example/pages/image/index.js b/example/pages/image/index.js
new file mode 100644
index 00000000..caa17bd7
--- /dev/null
+++ b/example/pages/image/index.js
@@ -0,0 +1,8 @@
+import Page from '../../common/page';
+
+Page({
+ data: {
+ fits: ['contain', 'cover', 'fill', 'none', 'scale-down'],
+ src: 'https://img.yzcdn.cn/vant/cat.jpeg',
+ }
+});
diff --git a/example/pages/image/index.json b/example/pages/image/index.json
new file mode 100644
index 00000000..22a4374d
--- /dev/null
+++ b/example/pages/image/index.json
@@ -0,0 +1,3 @@
+{
+ "navigationBarTitleText": "Image 图片"
+}
diff --git a/example/pages/image/index.wxml b/example/pages/image/index.wxml
new file mode 100644
index 00000000..0fd6d052
--- /dev/null
+++ b/example/pages/image/index.wxml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ fit }}
+
+
+
+
+
+
+
+
+ {{ fit }}
+
+
+
+
+
+
+
+
+ 默认提示
+
+
+
+
+
+
+ 自定义提示
+
+
+
+
+
+
+
+
+ 默认提示
+
+
+
+
+ 加载失败
+
+ 自定义提示
+
+
+
+
diff --git a/example/pages/image/index.wxss b/example/pages/image/index.wxss
new file mode 100644
index 00000000..c093ba10
--- /dev/null
+++ b/example/pages/image/index.wxss
@@ -0,0 +1,7 @@
+.text {
+ width: 100%;
+ margin-top: 5px;
+ color: #7d7e80;
+ font-size: 14px;
+ text-align: center;
+}
diff --git a/packages/common/style/var.less b/packages/common/style/var.less
index dc986b16..0421beb9 100644
--- a/packages/common/style/var.less
+++ b/packages/common/style/var.less
@@ -138,6 +138,11 @@
@count-down-font-size: @font-size-md;
@count-down-line-height: 20px;
+// Image
+@image-placeholder-text-color: @gray-dark;
+@image-placeholder-font-size: @font-size-md;
+@image-placeholder-background-color: @background-color;
+
// Info
@info-size: 16px;
@info-color: @white;
diff --git a/packages/image/README.md b/packages/image/README.md
new file mode 100644
index 00000000..85a125f8
--- /dev/null
+++ b/packages/image/README.md
@@ -0,0 +1,142 @@
+# Image 图片
+
+### 引入
+
+在`app.json`或`index.json`中引入组件,详细介绍见[快速上手](#/quickstart#yin-ru-zu-jian)
+
+```json
+"usingComponents": {
+ "van-image": "path/to/vant-weapp/dist/image/index"
+}
+```
+
+## 代码演示
+
+### 基础用法
+
+基础用法与[原生](https://developers.weixin.qq.com/miniprogram/dev/component/image.html)image一致,可以设置`src`、`width`、`height`等原生属性
+
+```html
+
+```
+
+### 填充模式
+
+通过`fit`属性可以设置图片填充模式,可选值见下方表格
+
+```html
+
+```
+
+### 圆形图片
+
+通过`round`属性可以设置图片变圆,注意当图片宽高不相等且`fit`为`contain`或`scale-down`时,将无法填充一个完整的圆形。
+
+```html
+
+```
+
+### 图片懒加载
+
+图片懒加载,在即将进入一定范围(上下三屏)时才开始加载
+
+```html
+
+```
+
+### 加载中提示
+
+`Image`组件提供了默认的加载中提示,支持通过`loading`插槽自定义内容
+
+```html
+
+
+
+```
+
+### 加载失败提示
+
+`Image`组件提供了默认的加载失败提示,支持通过`error`插槽自定义内容
+
+```html
+
+ 加载失败
+
+```
+
+## API
+
+### Props
+
+| 参数 | 说明 | 类型 | 默认值 | 版本 |
+|------|------|------|------|------|
+| src | 图片链接 | `string` | - | - |
+| fit | 图片填充模式 | `string` | `fill` | - |
+| alt | 替代文本 | `string` | - | - |
+| width | 宽度,默认单位为`px` | `string | number` | - | - |
+| height | 高度,默认单位为`px` | `string | number` | - | - |
+| round | 是否显示为圆形 | `boolean` | `false` | - |
+| lazy-load | 是否懒加载 | `boolean` | `false` | - |
+| show-error | 是否展示图片加载失败提示 | `boolean` | `true` | - |
+| show-loading | 是否展示图片加载中提示 | `boolean` | `true` | - |
+| show-menu-by-longpress | 开启长按图片显示识别小程序码菜单 | `boolean` | `false` | - |
+| use-loading-slot | 是否使用了loading slot | `boolean` | `false` | - |
+| use-error-slot | 是否使用了error slot | `boolean` | `false` | - |
+
+### 图片填充模式
+
+| 名称 | 含义 |
+|------|------|
+| contain | 保持宽高缩放图片,使图片的长边能完全显示出来 |
+| cover | 保持宽高缩放图片,使图片的短边能完全显示出来,裁剪长边 |
+| fill | 拉伸图片,使图片填满元素 |
+| none | 保持图片原有尺寸 |
+| scale-down | 由于小程序原生不支持这个属性,所以暂时和contain保持一致 |
+
+### Events
+
+| 事件名 | 说明 | 回调参数 |
+|------|------|------|
+| click | 点击图片时触发 | event: Event |
+| load | 图片加载完毕时触发 | event: Event |
+| error | 图片加载失败时触发 | event: Event |
+
+### Slots
+
+| 名称 | 说明 |
+|------|------|
+| loading | 自定义加载中的提示内容 |
+| error | 自定义加载失败时的提示内容 |
+
+### 外部样式类
+
+| 类名 | 说明 |
+|-----------|-----------|
+| custom-class | 根节点样式类 |
+| image-class | 图片样式类 |
+| loading-class | loading样式类 |
+| error-class | error样式类 |
diff --git a/packages/image/index.json b/packages/image/index.json
new file mode 100644
index 00000000..e00a5887
--- /dev/null
+++ b/packages/image/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "usingComponents": {
+ "van-icon": "../icon/index",
+ "van-loading": "../loading/index"
+ }
+}
diff --git a/packages/image/index.less b/packages/image/index.less
new file mode 100644
index 00000000..7de5fe00
--- /dev/null
+++ b/packages/image/index.less
@@ -0,0 +1,37 @@
+@import '../common/style/var.less';
+
+.van-image {
+ position: relative;
+ display: inline-block;
+
+ &--round {
+ overflow: hidden;
+ border-radius: 50%;
+
+ .van-image__img {
+ border-radius: inherit;
+ }
+ }
+
+ &__img,
+ &__error,
+ &__loading {
+ display: block;
+ width: 100%;
+ height: 100%;
+ }
+
+ &__error,
+ &__loading {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: @image-placeholder-text-color;
+ font-size: @image-placeholder-font-size;
+ background-color: @image-placeholder-background-color;
+ }
+}
diff --git a/packages/image/index.ts b/packages/image/index.ts
new file mode 100644
index 00000000..b8679c21
--- /dev/null
+++ b/packages/image/index.ts
@@ -0,0 +1,110 @@
+import { addUnit, isDef } from '../common/utils';
+import { VantComponent } from '../common/component';
+import { button } from '../mixins/button';
+import { openType } from '../mixins/open-type';
+
+VantComponent({
+ mixins: [button, openType],
+
+ classes: ['custom-class', 'loading-class', 'error-class', 'image-class'],
+
+ props: {
+ src: String,
+ width: String,
+ height: String,
+ fit: {
+ type: String,
+ value: 'fill'
+ },
+ round: Boolean,
+ lazyLoad: Boolean,
+ showError: {
+ type: Boolean,
+ value: true
+ },
+ showLoading: {
+ type: Boolean,
+ value: true
+ },
+ showMenuByLongpress: Boolean,
+
+ // 受小程序slot限制所需要的属性
+ useLoadingSlot: Boolean,
+ useErrorSlot: Boolean,
+ },
+
+ data: {
+ fitWeapp: 'aspectFit',
+ FIT_MODE_MAP: {
+ contain: 'aspectFit',
+ cover: 'aspectFill',
+ fill: 'scaleToFill',
+ none: 'center',
+
+ // TODO: 这个没有原生的属性,需要后面实现,暂时先用contain;
+ 'scale-down': 'aspectFit'
+ },
+ loading: true,
+ error: false
+ },
+
+ watch: {
+ src() {
+ this.setData({
+ loading: true,
+ error: false
+ });
+ }
+ },
+
+ mounted() {
+ this.init();
+ },
+
+ methods: {
+ init() {
+ const { FIT_MODE_MAP, fit } = this.data;
+
+ this.setData({
+ mode: FIT_MODE_MAP[fit],
+ style: this.getStyle(),
+ });
+ },
+
+ getStyle() {
+ const { width, height } = this.data;
+ let style = '';
+
+ if (isDef(width)) {
+ style += `width: ${addUnit(width)};`;
+ }
+
+ if (isDef(height)) {
+ style += `height: ${addUnit(height)};`;
+ }
+
+ return style;
+ },
+
+ onLoad(event) {
+ this.setData({
+ loading: false
+ });
+
+ this.$emit('load', event.detail);
+ },
+
+ onError(event) {
+ this.setData({
+ loading: false,
+ error: true,
+ });
+
+ this.$emit('error', event.detail);
+ },
+
+ onClick(event) {
+ this.$emit('click', event.detail);
+ },
+ }
+});
diff --git a/packages/image/index.wxml b/packages/image/index.wxml
new file mode 100644
index 00000000..1a43652f
--- /dev/null
+++ b/packages/image/index.wxml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+