[new feature] Uploader: add preview prop

This commit is contained in:
陈嘉涵 2019-06-04 15:16:11 +08:00
parent 39339fdda7
commit 03af04e81e
9 changed files with 140 additions and 26 deletions

View File

@ -19,6 +19,10 @@
- 支持`Number`类型的`input-width`属性 - 支持`Number`类型的`input-width`属性
##### Uploader
- 新增`preview`属性
### [v2.0.0-beta.3](https://github.com/youzan/vant/tree/v2.0.0-beta.3) ### [v2.0.0-beta.3](https://github.com/youzan/vant/tree/v2.0.0-beta.3)
`2019-05-31` `2019-05-31`

View File

@ -1,7 +1,7 @@
<template> <template>
<demo-section> <demo-section>
<demo-block :title="$t('basicUsage')"> <demo-block :title="$t('basicUsage')">
<van-uploader /> <van-uploader preview />
</demo-block> </demo-block>
<demo-block :title="$t('uploadStyle')"> <demo-block :title="$t('uploadStyle')">

View File

@ -13,7 +13,7 @@ Vue.use(Uploader);
### Basic Usage ### Basic Usage
```html ```html
<van-uploader :after-read="onRead" /> <van-uploader preview :after-read="onRead" />
``` ```
```javascript ```javascript
@ -42,6 +42,7 @@ export default {
|------|------|------|------| |------|------|------|------|
| name | Input name | `String` | - | | name | Input name | `String` | - |
| accept | Accepted file type | `String` | `image/*` | | accept | Accepted file type | `String` | `image/*` |
| preview | Whether to show image preview | `Boolean` | `false` |
| multiple | Whether to enable multiple selection pictures | `Boolean` | `false` | | multiple | Whether to enable multiple selection pictures | `Boolean` | `false` |
| disabled | Whether to disabled the upload | `Boolean` | `false` | | disabled | Whether to disabled the upload | `Boolean` | `false` |
| capture | Capturecan be set to `camera` | `String` | - | | capture | Capturecan be set to `camera` | `String` | - |

View File

@ -1,5 +1,6 @@
import { use } from '../utils'; import { use } from '../utils';
import Icon from '../icon'; import Icon from '../icon';
import Image from '../image';
const [sfc, bem] = use('uploader'); const [sfc, bem] = use('uploader');
@ -7,6 +8,7 @@ export default sfc({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
preview: Boolean,
disabled: Boolean, disabled: Boolean,
uploadText: String, uploadText: String,
beforeRead: Function, beforeRead: Function,
@ -25,6 +27,12 @@ export default sfc({
} }
}, },
data() {
return {
previewImages: []
};
},
computed: { computed: {
detail() { detail() {
return { return {
@ -89,48 +97,79 @@ export default sfc({
if (oversize) { if (oversize) {
this.$emit('oversize', files, this.detail); this.$emit('oversize', files, this.detail);
} else { } else {
this.afterRead && this.afterRead(files, this.detail); if (Array.isArray(files)) {
files.forEach(this.addPreviewImage);
} else {
this.addPreviewImage(files);
}
if (this.afterRead) {
this.afterRead(files, this.detail);
}
} }
this.resetInput(); this.resetInput();
}, },
addPreviewImage(file) {
this.previewImages.push(file.content);
},
resetInput() { resetInput() {
/* istanbul ignore else */
if (this.$refs.input) { if (this.$refs.input) {
this.$refs.input.value = ''; this.$refs.input.value = '';
} }
} },
},
render(h) { renderPreview() {
const { slots, accept, disabled, uploadText } = this; if (this.preview) {
return this.previewImages.map(image => (
<Image fit="cover" class={bem('preview')} src={image} />
));
}
},
function Upload() { renderUpload() {
const slot = slots(); const slot = this.slots();
const Input = (
<input
{...{ attrs: this.$attrs }}
ref="input"
type="file"
accept={this.accept}
class={bem('input')}
disabled={this.disabled}
onChange={this.onChange}
/>
);
if (slot) { if (slot) {
return slot; return (
<div class={bem('input-wrapper')}>
{slot}
{Input}
</div>
);
} }
return ( return (
<div class={bem('upload')}> <div class={bem('upload')}>
<Icon name="plus" class={bem('upload-icon')} /> <Icon name="plus" class={bem('upload-icon')} />
{uploadText && <span class={bem('upload-text')}>{uploadText}</span>} {this.uploadText && <span class={bem('upload-text')}>{this.uploadText}</span>}
{Input}
</div> </div>
); );
} }
},
render(h) {
return ( return (
<div class={bem()}> <div class={bem()}>
{Upload()} <div class={bem('wrapper')}>
<input {this.renderPreview()}
{...{ attrs: this.$attrs }} {this.renderUpload()}
ref="input" </div>
type="file"
accept={accept}
class={bem('input')}
disabled={disabled}
onChange={this.onChange}
/>
</div> </div>
); );
} }

View File

@ -4,6 +4,11 @@
position: relative; position: relative;
display: inline-block; display: inline-block;
&__wrapper {
display: flex;
flex-wrap: wrap;
}
&__input { &__input {
position: absolute; position: absolute;
top: 0; top: 0;
@ -13,9 +18,14 @@
overflow: hidden; // to clip file-upload-button overflow: hidden; // to clip file-upload-button
cursor: pointer; cursor: pointer;
opacity: 0; opacity: 0;
&-wrapper {
position: relative;
}
} }
&__upload { &__upload {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -23,6 +33,7 @@
box-sizing: border-box; box-sizing: border-box;
width: 80px; width: 80px;
height: 80px; height: 80px;
margin: 0 10px 10px 0;
background-color: @white; background-color: @white;
border: 1px dashed @gray-light; border: 1px dashed @gray-light;
@ -37,4 +48,10 @@
font-size: 12px; font-size: 12px;
} }
} }
&__preview {
width: 80px;
height: 80px;
margin: 0 10px 10px 0;
}
} }

View File

@ -4,15 +4,21 @@ exports[`renders demo correctly 1`] = `
<div> <div>
<div> <div>
<div class="van-uploader"> <div class="van-uploader">
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon"> <div class="van-uploader__wrapper">
<!----></i></div><input type="file" accept="image/*" class="van-uploader__input"> <div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
<!----></i><input type="file" accept="image/*" class="van-uploader__input"></div>
</div>
</div> </div>
</div> </div>
<div> <div>
<div class="van-uploader"><button class="van-button van-button--primary van-button--normal"><i class="van-icon van-icon-photo van-button__icon"> <div class="van-uploader">
<!----></i><span class="van-button__text"> <div class="van-uploader__wrapper">
<div class="van-uploader__input-wrapper"><button class="van-button van-button--primary van-button--normal"><i class="van-icon van-icon-photo van-button__icon">
<!----></i><span class="van-button__text">
上传图片 上传图片
</span></button><input type="file" accept="image/*" class="van-uploader__input"></div> </span></button><input type="file" accept="image/*" class="van-uploader__input"></div>
</div>
</div>
</div> </div>
</div> </div>
`; `;

View File

@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`render preview image 1`] = `
<div class="van-uploader">
<div class="van-uploader__wrapper">
<div class="van-image van-uploader__preview"><img src="test" class="van-image__img" style="object-fit: cover;">
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">
<!----></i></div>
</div>
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
<!----></i><input type="file" accept="image/*" class="van-uploader__input"></div>
</div>
</div>
`;
exports[`render upload-text 1`] = `
<div class="van-uploader">
<div class="van-uploader__wrapper">
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
<!----></i><span class="van-uploader__upload-text">Text</span><input type="file" accept="image/*" class="van-uploader__input"></div>
</div>
</div>
`;

View File

@ -113,3 +113,26 @@ test('file size overlimit', async () => {
await later(); await later();
expect(wrapper.emitted('oversize')[2]).toBeFalsy(); expect(wrapper.emitted('oversize')[2]).toBeFalsy();
}); });
it('render upload-text', () => {
const wrapper = mount(Uploader, {
propsData: {
uploadText: 'Text'
}
});
expect(wrapper).toMatchSnapshot();
});
it('render preview image', async () => {
const wrapper = mount(Uploader, {
propsData: {
preview: true
}
});
wrapper.vm.onChange(file);
await later();
expect(wrapper).toMatchSnapshot();
});

View File

@ -13,7 +13,7 @@ Vue.use(Uploader);
### 基础用法 ### 基础用法
```html ```html
<van-uploader :after-read="onRead" /> <van-uploader preview :after-read="onRead" />
``` ```
```javascript ```javascript
@ -42,6 +42,7 @@ export default {
|------|------|------|------|------| |------|------|------|------|------|
| name | 标识符,可以在回调函数的第二项参数中获取 | `String` | - | 1.6.13 | | name | 标识符,可以在回调函数的第二项参数中获取 | `String` | - | 1.6.13 |
| accept | 接受的文件类型 | `String` | `image/*` | - | | accept | 接受的文件类型 | `String` | `image/*` | - |
| preview | 是否在上传完成后展示预览图 | `Boolean` | `false` | 2.0.0 |
| multiple | 是否开启图片多选,部分安卓机型不支持 | `Boolean` | `false` | 2.0.0 | | multiple | 是否开启图片多选,部分安卓机型不支持 | `Boolean` | `false` | 2.0.0 |
| disabled | 是否禁用图片上传 | `Boolean` | `false` | - | | disabled | 是否禁用图片上传 | `Boolean` | `false` | - |
| capture | 图片选取模式,可选值为`camera`(直接调起摄像头) | `String` | - | 2.0.0 | | capture | 图片选取模式,可选值为`camera`(直接调起摄像头) | `String` | - | 2.0.0 |