Skip to content

Commit d0fbaf7

Browse files
authored
[improvement] Uploader: support preview network image (#3899)
1 parent 0d68c62 commit d0fbaf7

File tree

10 files changed

+181
-82
lines changed

10 files changed

+181
-82
lines changed

src/uploader/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ export default {
3636
export default {
3737
data() {
3838
return {
39-
fileList: []
39+
fileList: [
40+
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' }
41+
]
4042
}
4143
}
4244
};

src/uploader/README.zh-CN.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ export default {
4141
export default {
4242
data() {
4343
return {
44-
fileList: []
44+
fileList: [
45+
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' }
46+
]
4547
}
4648
}
4749
};

src/uploader/demo/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export default {
6363
6464
data() {
6565
return {
66-
fileList: [],
66+
fileList: [{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' }],
6767
fileList2: [],
6868
fileList3: []
6969
};

src/uploader/index.js

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createNamespace, addUnit } from '../utils';
2-
import { toArray, readFile, isOversize, isImageDataUrl } from './utils';
2+
import { toArray, readFile, isOversize, isImageFile } from './utils';
33
import Icon from '../icon';
44
import Image from '../image';
55
import ImagePreview from '../image-preview';
@@ -54,6 +54,10 @@ export default createComponent({
5454
return {
5555
name: this.name
5656
};
57+
},
58+
59+
previewSizeWithUnit() {
60+
return addUnit(this.previewSize);
5761
}
5862
},
5963

@@ -145,12 +149,12 @@ export default createComponent({
145149

146150
onPreviewImage(item) {
147151
const imageFiles = this.fileList
148-
.map(item => item.content)
149-
.filter(content => isImageDataUrl(content));
152+
.filter(item => isImageFile(item))
153+
.map(item => item.content || item.url);
150154

151155
ImagePreview({
152156
images: imageFiles,
153-
startPosition: imageFiles.indexOf(item.content)
157+
startPosition: imageFiles.indexOf(item.content || item.url)
154158
});
155159
},
156160

@@ -161,26 +165,31 @@ export default createComponent({
161165

162166
return this.fileList.map((item, index) => (
163167
<div class={bem('preview')}>
164-
<Image
165-
fit="cover"
166-
src={item.content}
167-
class={bem('preview-image')}
168-
width={this.previewSize}
169-
height={this.previewSize}
170-
scopedSlots={{
171-
error() {
172-
return [
173-
<Icon class={bem('file-icon')} name="description" />,
174-
<div class={[bem('file-name'), 'van-ellipsis']}>{item.file.name}</div>
175-
];
176-
}
177-
}}
178-
onClick={() => {
179-
if (isImageDataUrl(item.content)) {
168+
{isImageFile(item) ? (
169+
<Image
170+
fit="cover"
171+
src={item.content || item.url}
172+
class={bem('preview-image')}
173+
width={this.previewSize}
174+
height={this.previewSize}
175+
onClick={() => {
180176
this.onPreviewImage(item);
181-
}
182-
}}
183-
/>
177+
}}
178+
/>
179+
) : (
180+
<div
181+
class={bem('file')}
182+
style={{
183+
width: this.previewSizeWithUnit,
184+
height: this.previewSizeWithUnit
185+
}}
186+
>
187+
<Icon class={bem('file-icon')} name="description" />
188+
<div class={[bem('file-name'), 'van-ellipsis']}>
189+
{item.file ? item.file.name : item.url}
190+
</div>
191+
</div>
192+
)}
184193
<Icon
185194
name="delete"
186195
class={bem('preview-delete')}
@@ -222,7 +231,7 @@ export default createComponent({
222231

223232
let style;
224233
if (this.previewSize) {
225-
const size = addUnit(this.previewSize);
234+
const size = this.previewSizeWithUnit;
226235
style = {
227236
width: size,
228237
height: size

src/uploader/index.less

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,28 @@
6969
}
7070
}
7171

72-
&__file-icon {
73-
color: @gray-darker;
74-
font-size: 20px;
75-
}
72+
&__file {
73+
display: flex;
74+
flex-direction: column;
75+
align-items: center;
76+
justify-content: center;
77+
width: @uploader-size;
78+
height: @uploader-size;
79+
background-color: #f8f8f8;
7680

77-
&__file-name {
78-
box-sizing: border-box;
79-
width: 100%;
80-
margin-top: 5px;
81-
padding: 0 5px;
82-
color: @gray-darker;
83-
font-size: 12px;
84-
text-align: center;
81+
&-icon {
82+
color: @gray-darker;
83+
font-size: 20px;
84+
}
85+
86+
&-name {
87+
box-sizing: border-box;
88+
width: 100%;
89+
margin-top: 5px;
90+
padding: 0 5px;
91+
color: @gray-darker;
92+
font-size: 12px;
93+
text-align: center;
94+
}
8595
}
8696
}

src/uploader/test/__snapshots__/demo.spec.js.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ exports[`renders demo correctly 1`] = `
1313
<div>
1414
<div class="van-uploader">
1515
<div class="van-uploader__wrapper">
16+
<div class="van-uploader__preview">
17+
<div class="van-image van-uploader__preview-image"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: cover;">
18+
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">
19+
<!----></i></div>
20+
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
21+
<!----></i>
22+
</div>
1623
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
1724
<!----></i><input multiple="multiple" type="file" accept="*" class="van-uploader__input"></div>
1825
</div>

src/uploader/test/__snapshots__/index.spec.js.snap

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`click to preview image 1`] = `
4+
<div
5+
class="van-image-preview"
6+
>
7+
<div
8+
class="van-image-preview__index"
9+
>
10+
1/2
11+
</div>
12+
<div
13+
class="van-swipe"
14+
>
15+
<div
16+
class="van-swipe__track"
17+
style="width: 0px; transition-duration: 0ms; transform: translateX(0px);"
18+
>
19+
<div
20+
class="van-swipe-item"
21+
style="width: 0px; height: 100%; transform: translateX(0px);"
22+
>
23+
<img
24+
class="van-image-preview__image"
25+
src="https://img.yzcdn.cn/vant/cat.jpeg"
26+
style="transition: .3s all;"
27+
/>
28+
</div>
29+
<div
30+
class="van-swipe-item"
31+
style="width: 0px; height: 100%; transform: translateX(0px);"
32+
>
33+
<img
34+
class="van-image-preview__image"
35+
src="data:image/test"
36+
/>
37+
</div>
38+
</div>
39+
</div>
40+
</div>
41+
`;
42+
343
exports[`delete preview image 1`] = `
444
<div class="van-uploader">
545
<div class="van-uploader__wrapper">
@@ -32,24 +72,6 @@ exports[`max-count prop 1`] = `
3272
</div>
3373
`;
3474
35-
exports[`preview not image file 1`] = `
36-
<div class="van-uploader">
37-
<div class="van-uploader__wrapper">
38-
<div class="van-uploader__preview">
39-
<div class="van-image van-uploader__preview-image">
40-
<div class="van-image__error"><i class="van-icon van-icon-description van-uploader__file-icon" style="">
41-
<!----></i>
42-
<div class="van-uploader__file-name van-ellipsis">test.md</div>
43-
</div>
44-
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
45-
<!----></i>
46-
</div>
47-
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
48-
<!----></i><input type="file" accept="image/*" class="van-uploader__input"></div>
49-
</div>
50-
</div>
51-
`;
52-
5375
exports[`preview-size prop 1`] = `
5476
<div class="van-uploader">
5577
<div class="van-uploader__wrapper">
@@ -69,6 +91,27 @@ exports[`preview-size prop 1`] = `
6991
exports[`render preview image 1`] = `
7092
<div class="van-uploader">
7193
<div class="van-uploader__wrapper">
94+
<div class="van-uploader__preview">
95+
<div class="van-image van-uploader__preview-image"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img" style="object-fit: cover;">
96+
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">
97+
<!----></i></div>
98+
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
99+
<!----></i>
100+
</div>
101+
<div class="van-uploader__preview">
102+
<div class="van-uploader__file"><i class="van-icon van-icon-description van-uploader__file-icon">
103+
<!----></i>
104+
<div class="van-uploader__file-name van-ellipsis">https://img.yzcdn.cn/vant/test.pdf</div>
105+
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
106+
<!----></i>
107+
</div>
108+
<div class="van-uploader__preview">
109+
<div class="van-uploader__file"><i class="van-icon van-icon-description van-uploader__file-icon">
110+
<!----></i>
111+
<div class="van-uploader__file-name van-ellipsis">test.pdf</div>
112+
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
113+
<!----></i>
114+
</div>
72115
<div class="van-uploader__preview">
73116
<div class="van-image van-uploader__preview-image"><img src="data:image/test" class="van-image__img" style="object-fit: cover;">
74117
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">

src/uploader/test/index.spec.js

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ window.File = function () {
66
};
77

88
const mockFileDataUrl = 'data:image/test';
9-
const mockFile = new File([], '/Users');
9+
const mockFile = new File([], 'test.jpg');
1010
const file = { target: { files: [mockFile] } };
1111
const multiFile = { target: { files: [mockFile, mockFile] } };
1212

@@ -164,7 +164,11 @@ it('render upload-text', () => {
164164
it('render preview image', async () => {
165165
const wrapper = mount(Uploader, {
166166
propsData: {
167-
fileList: []
167+
fileList: [
168+
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' },
169+
{ url: 'https://img.yzcdn.cn/vant/test.pdf' },
170+
{ file: { name: 'test.pdf' } }
171+
]
168172
},
169173
listeners: {
170174
input(fileList) {
@@ -262,7 +266,10 @@ it('delete preview image', async () => {
262266
it('click to preview image', async () => {
263267
const wrapper = mount(Uploader, {
264268
propsData: {
265-
fileList: [],
269+
fileList: [
270+
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' },
271+
{ url: 'https://img.yzcdn.cn/vant/test.pdf' }
272+
],
266273
previewSize: 30
267274
},
268275
listeners: {
@@ -278,25 +285,6 @@ it('click to preview image', async () => {
278285
wrapper.find('.van-image').trigger('click');
279286

280287
const imagePreviewNode = document.querySelector('.van-image-preview');
281-
expect(imagePreviewNode).toBeTruthy();
288+
expect(imagePreviewNode).toMatchSnapshot();
282289
imagePreviewNode.remove();
283290
});
284-
285-
it('preview not image file', async () => {
286-
const wrapper = mount(Uploader, {
287-
propsData: {
288-
fileList: [{
289-
content: 'data:application',
290-
file: {
291-
name: 'test.md'
292-
}
293-
}]
294-
}
295-
});
296-
297-
wrapper.find('img').trigger('error');
298-
wrapper.find('.van-image').trigger('click');
299-
300-
expect(document.querySelector('.van-image-preview')).toBeFalsy();
301-
expect(wrapper).toMatchSnapshot();
302-
});

src/uploader/test/utils.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { isImageFile } from '../utils';
2+
3+
test('isImageFile', () => {
4+
expect(isImageFile({ url: 'https://a.jpg' })).toBeTruthy();
5+
expect(isImageFile({ url: 'https://a.jpeg' })).toBeTruthy();
6+
expect(isImageFile({ url: 'https://a.png' })).toBeTruthy();
7+
expect(isImageFile({ url: 'https://a.svg' })).toBeTruthy();
8+
expect(isImageFile({ url: 'https://a.gif' })).toBeTruthy();
9+
expect(isImageFile({ file: { type: 'image/jpg' } })).toBeTruthy();
10+
expect(isImageFile({ file: { type: 'application/pdf' } })).toBeFalsy();
11+
expect(isImageFile({ content: 'data:image/xxx' })).toBeTruthy();
12+
expect(isImageFile({ content: 'data:application/xxx' })).toBeFalsy();
13+
expect(isImageFile({})).toBeFalsy();
14+
});

src/uploader/utils.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,30 @@ export function isOversize(files: File | File[], maxSize: number): boolean {
2626
return toArray(files).some(file => file.size > maxSize);
2727
}
2828

29-
export function isImageDataUrl(dataUrl: string): boolean {
30-
return dataUrl.indexOf('data:image') === 0;
29+
export type FileListItem = {
30+
url?: string;
31+
file?: File;
32+
content?: string; // dataUrl
33+
};
34+
35+
const IMAGE_EXT = ['jpeg', 'jpg', 'gif', 'png', 'svg'];
36+
37+
export function isImageUrl(url: string): boolean {
38+
return IMAGE_EXT.some(ext => url.indexOf(`.${ext}`) !== -1);
39+
}
40+
41+
export function isImageFile(item: FileListItem): boolean {
42+
if (item.file && item.file.type) {
43+
return item.file.type.indexOf('image') === 0;
44+
}
45+
46+
if (item.url) {
47+
return isImageUrl(item.url);
48+
}
49+
50+
if (item.content) {
51+
return item.content.indexOf('data:image') === 0;
52+
}
53+
54+
return false;
3155
}

0 commit comments

Comments
 (0)