mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[improvement] Uploader: support preview network image (#3899)
This commit is contained in:
parent
0d68c628ca
commit
d0fbaf7325
@ -36,7 +36,9 @@ export default {
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
fileList: []
|
fileList: [
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -41,7 +41,9 @@ export default {
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
fileList: []
|
fileList: [
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -63,7 +63,7 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
fileList: [],
|
fileList: [{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' }],
|
||||||
fileList2: [],
|
fileList2: [],
|
||||||
fileList3: []
|
fileList3: []
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createNamespace, addUnit } from '../utils';
|
import { createNamespace, addUnit } from '../utils';
|
||||||
import { toArray, readFile, isOversize, isImageDataUrl } from './utils';
|
import { toArray, readFile, isOversize, isImageFile } from './utils';
|
||||||
import Icon from '../icon';
|
import Icon from '../icon';
|
||||||
import Image from '../image';
|
import Image from '../image';
|
||||||
import ImagePreview from '../image-preview';
|
import ImagePreview from '../image-preview';
|
||||||
@ -54,6 +54,10 @@ export default createComponent({
|
|||||||
return {
|
return {
|
||||||
name: this.name
|
name: this.name
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
previewSizeWithUnit() {
|
||||||
|
return addUnit(this.previewSize);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -145,12 +149,12 @@ export default createComponent({
|
|||||||
|
|
||||||
onPreviewImage(item) {
|
onPreviewImage(item) {
|
||||||
const imageFiles = this.fileList
|
const imageFiles = this.fileList
|
||||||
.map(item => item.content)
|
.filter(item => isImageFile(item))
|
||||||
.filter(content => isImageDataUrl(content));
|
.map(item => item.content || item.url);
|
||||||
|
|
||||||
ImagePreview({
|
ImagePreview({
|
||||||
images: imageFiles,
|
images: imageFiles,
|
||||||
startPosition: imageFiles.indexOf(item.content)
|
startPosition: imageFiles.indexOf(item.content || item.url)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -161,26 +165,31 @@ export default createComponent({
|
|||||||
|
|
||||||
return this.fileList.map((item, index) => (
|
return this.fileList.map((item, index) => (
|
||||||
<div class={bem('preview')}>
|
<div class={bem('preview')}>
|
||||||
<Image
|
{isImageFile(item) ? (
|
||||||
fit="cover"
|
<Image
|
||||||
src={item.content}
|
fit="cover"
|
||||||
class={bem('preview-image')}
|
src={item.content || item.url}
|
||||||
width={this.previewSize}
|
class={bem('preview-image')}
|
||||||
height={this.previewSize}
|
width={this.previewSize}
|
||||||
scopedSlots={{
|
height={this.previewSize}
|
||||||
error() {
|
onClick={() => {
|
||||||
return [
|
|
||||||
<Icon class={bem('file-icon')} name="description" />,
|
|
||||||
<div class={[bem('file-name'), 'van-ellipsis']}>{item.file.name}</div>
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
if (isImageDataUrl(item.content)) {
|
|
||||||
this.onPreviewImage(item);
|
this.onPreviewImage(item);
|
||||||
}
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
) : (
|
||||||
|
<div
|
||||||
|
class={bem('file')}
|
||||||
|
style={{
|
||||||
|
width: this.previewSizeWithUnit,
|
||||||
|
height: this.previewSizeWithUnit
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon class={bem('file-icon')} name="description" />
|
||||||
|
<div class={[bem('file-name'), 'van-ellipsis']}>
|
||||||
|
{item.file ? item.file.name : item.url}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<Icon
|
<Icon
|
||||||
name="delete"
|
name="delete"
|
||||||
class={bem('preview-delete')}
|
class={bem('preview-delete')}
|
||||||
@ -222,7 +231,7 @@ export default createComponent({
|
|||||||
|
|
||||||
let style;
|
let style;
|
||||||
if (this.previewSize) {
|
if (this.previewSize) {
|
||||||
const size = addUnit(this.previewSize);
|
const size = this.previewSizeWithUnit;
|
||||||
style = {
|
style = {
|
||||||
width: size,
|
width: size,
|
||||||
height: size
|
height: size
|
||||||
|
@ -69,18 +69,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__file-icon {
|
&__file {
|
||||||
color: @gray-darker;
|
display: flex;
|
||||||
font-size: 20px;
|
flex-direction: column;
|
||||||
}
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: @uploader-size;
|
||||||
|
height: @uploader-size;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
|
||||||
&__file-name {
|
&-icon {
|
||||||
box-sizing: border-box;
|
color: @gray-darker;
|
||||||
width: 100%;
|
font-size: 20px;
|
||||||
margin-top: 5px;
|
}
|
||||||
padding: 0 5px;
|
|
||||||
color: @gray-darker;
|
&-name {
|
||||||
font-size: 12px;
|
box-sizing: border-box;
|
||||||
text-align: center;
|
width: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 0 5px;
|
||||||
|
color: @gray-darker;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,13 @@ exports[`renders demo correctly 1`] = `
|
|||||||
<div>
|
<div>
|
||||||
<div class="van-uploader">
|
<div class="van-uploader">
|
||||||
<div class="van-uploader__wrapper">
|
<div class="van-uploader__wrapper">
|
||||||
|
<div class="van-uploader__preview">
|
||||||
|
<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;">
|
||||||
|
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">
|
||||||
|
<!----></i></div>
|
||||||
|
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
|
||||||
|
<!----></i>
|
||||||
|
</div>
|
||||||
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
|
<div class="van-uploader__upload"><i class="van-icon van-icon-plus van-uploader__upload-icon">
|
||||||
<!----></i><input multiple="multiple" type="file" accept="*" class="van-uploader__input"></div>
|
<!----></i><input multiple="multiple" type="file" accept="*" class="van-uploader__input"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,45 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`click to preview image 1`] = `
|
||||||
|
<div
|
||||||
|
class="van-image-preview"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="van-image-preview__index"
|
||||||
|
>
|
||||||
|
1/2
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="van-swipe"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="van-swipe__track"
|
||||||
|
style="width: 0px; transition-duration: 0ms; transform: translateX(0px);"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="van-swipe-item"
|
||||||
|
style="width: 0px; height: 100%; transform: translateX(0px);"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="van-image-preview__image"
|
||||||
|
src="https://img.yzcdn.cn/vant/cat.jpeg"
|
||||||
|
style="transition: .3s all;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="van-swipe-item"
|
||||||
|
style="width: 0px; height: 100%; transform: translateX(0px);"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="van-image-preview__image"
|
||||||
|
src="data:image/test"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`delete preview image 1`] = `
|
exports[`delete preview image 1`] = `
|
||||||
<div class="van-uploader">
|
<div class="van-uploader">
|
||||||
<div class="van-uploader__wrapper">
|
<div class="van-uploader__wrapper">
|
||||||
@ -32,24 +72,6 @@ exports[`max-count prop 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`preview not image file 1`] = `
|
|
||||||
<div class="van-uploader">
|
|
||||||
<div class="van-uploader__wrapper">
|
|
||||||
<div class="van-uploader__preview">
|
|
||||||
<div class="van-image van-uploader__preview-image">
|
|
||||||
<div class="van-image__error"><i class="van-icon van-icon-description van-uploader__file-icon" style="">
|
|
||||||
<!----></i>
|
|
||||||
<div class="van-uploader__file-name van-ellipsis">test.md</div>
|
|
||||||
</div>
|
|
||||||
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
|
|
||||||
<!----></i>
|
|
||||||
</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[`preview-size prop 1`] = `
|
exports[`preview-size prop 1`] = `
|
||||||
<div class="van-uploader">
|
<div class="van-uploader">
|
||||||
<div class="van-uploader__wrapper">
|
<div class="van-uploader__wrapper">
|
||||||
@ -69,6 +91,27 @@ exports[`preview-size prop 1`] = `
|
|||||||
exports[`render preview image 1`] = `
|
exports[`render preview image 1`] = `
|
||||||
<div class="van-uploader">
|
<div class="van-uploader">
|
||||||
<div class="van-uploader__wrapper">
|
<div class="van-uploader__wrapper">
|
||||||
|
<div class="van-uploader__preview">
|
||||||
|
<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;">
|
||||||
|
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">
|
||||||
|
<!----></i></div>
|
||||||
|
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
|
||||||
|
<!----></i>
|
||||||
|
</div>
|
||||||
|
<div class="van-uploader__preview">
|
||||||
|
<div class="van-uploader__file"><i class="van-icon van-icon-description van-uploader__file-icon">
|
||||||
|
<!----></i>
|
||||||
|
<div class="van-uploader__file-name van-ellipsis">https://img.yzcdn.cn/vant/test.pdf</div>
|
||||||
|
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
|
||||||
|
<!----></i>
|
||||||
|
</div>
|
||||||
|
<div class="van-uploader__preview">
|
||||||
|
<div class="van-uploader__file"><i class="van-icon van-icon-description van-uploader__file-icon">
|
||||||
|
<!----></i>
|
||||||
|
<div class="van-uploader__file-name van-ellipsis">test.pdf</div>
|
||||||
|
</div><i class="van-icon van-icon-delete van-uploader__preview-delete">
|
||||||
|
<!----></i>
|
||||||
|
</div>
|
||||||
<div class="van-uploader__preview">
|
<div class="van-uploader__preview">
|
||||||
<div class="van-image van-uploader__preview-image"><img src="data:image/test" class="van-image__img" style="object-fit: cover;">
|
<div class="van-image van-uploader__preview-image"><img src="data:image/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;">
|
<div class="van-image__loading"><i class="van-icon van-icon-photo-o" style="font-size: 22px;">
|
||||||
|
@ -6,7 +6,7 @@ window.File = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mockFileDataUrl = 'data:image/test';
|
const mockFileDataUrl = 'data:image/test';
|
||||||
const mockFile = new File([], '/Users');
|
const mockFile = new File([], 'test.jpg');
|
||||||
const file = { target: { files: [mockFile] } };
|
const file = { target: { files: [mockFile] } };
|
||||||
const multiFile = { target: { files: [mockFile, mockFile] } };
|
const multiFile = { target: { files: [mockFile, mockFile] } };
|
||||||
|
|
||||||
@ -164,7 +164,11 @@ it('render upload-text', () => {
|
|||||||
it('render preview image', async () => {
|
it('render preview image', async () => {
|
||||||
const wrapper = mount(Uploader, {
|
const wrapper = mount(Uploader, {
|
||||||
propsData: {
|
propsData: {
|
||||||
fileList: []
|
fileList: [
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' },
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/test.pdf' },
|
||||||
|
{ file: { name: 'test.pdf' } }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
listeners: {
|
listeners: {
|
||||||
input(fileList) {
|
input(fileList) {
|
||||||
@ -262,7 +266,10 @@ it('delete preview image', async () => {
|
|||||||
it('click to preview image', async () => {
|
it('click to preview image', async () => {
|
||||||
const wrapper = mount(Uploader, {
|
const wrapper = mount(Uploader, {
|
||||||
propsData: {
|
propsData: {
|
||||||
fileList: [],
|
fileList: [
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/cat.jpeg' },
|
||||||
|
{ url: 'https://img.yzcdn.cn/vant/test.pdf' }
|
||||||
|
],
|
||||||
previewSize: 30
|
previewSize: 30
|
||||||
},
|
},
|
||||||
listeners: {
|
listeners: {
|
||||||
@ -278,25 +285,6 @@ it('click to preview image', async () => {
|
|||||||
wrapper.find('.van-image').trigger('click');
|
wrapper.find('.van-image').trigger('click');
|
||||||
|
|
||||||
const imagePreviewNode = document.querySelector('.van-image-preview');
|
const imagePreviewNode = document.querySelector('.van-image-preview');
|
||||||
expect(imagePreviewNode).toBeTruthy();
|
expect(imagePreviewNode).toMatchSnapshot();
|
||||||
imagePreviewNode.remove();
|
imagePreviewNode.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preview not image file', async () => {
|
|
||||||
const wrapper = mount(Uploader, {
|
|
||||||
propsData: {
|
|
||||||
fileList: [{
|
|
||||||
content: 'data:application',
|
|
||||||
file: {
|
|
||||||
name: 'test.md'
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.find('img').trigger('error');
|
|
||||||
wrapper.find('.van-image').trigger('click');
|
|
||||||
|
|
||||||
expect(document.querySelector('.van-image-preview')).toBeFalsy();
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
14
src/uploader/test/utils.spec.js
Normal file
14
src/uploader/test/utils.spec.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { isImageFile } from '../utils';
|
||||||
|
|
||||||
|
test('isImageFile', () => {
|
||||||
|
expect(isImageFile({ url: 'https://a.jpg' })).toBeTruthy();
|
||||||
|
expect(isImageFile({ url: 'https://a.jpeg' })).toBeTruthy();
|
||||||
|
expect(isImageFile({ url: 'https://a.png' })).toBeTruthy();
|
||||||
|
expect(isImageFile({ url: 'https://a.svg' })).toBeTruthy();
|
||||||
|
expect(isImageFile({ url: 'https://a.gif' })).toBeTruthy();
|
||||||
|
expect(isImageFile({ file: { type: 'image/jpg' } })).toBeTruthy();
|
||||||
|
expect(isImageFile({ file: { type: 'application/pdf' } })).toBeFalsy();
|
||||||
|
expect(isImageFile({ content: 'data:image/xxx' })).toBeTruthy();
|
||||||
|
expect(isImageFile({ content: 'data:application/xxx' })).toBeFalsy();
|
||||||
|
expect(isImageFile({})).toBeFalsy();
|
||||||
|
});
|
@ -26,6 +26,30 @@ export function isOversize(files: File | File[], maxSize: number): boolean {
|
|||||||
return toArray(files).some(file => file.size > maxSize);
|
return toArray(files).some(file => file.size > maxSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isImageDataUrl(dataUrl: string): boolean {
|
export type FileListItem = {
|
||||||
return dataUrl.indexOf('data:image') === 0;
|
url?: string;
|
||||||
|
file?: File;
|
||||||
|
content?: string; // dataUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMAGE_EXT = ['jpeg', 'jpg', 'gif', 'png', 'svg'];
|
||||||
|
|
||||||
|
export function isImageUrl(url: string): boolean {
|
||||||
|
return IMAGE_EXT.some(ext => url.indexOf(`.${ext}`) !== -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isImageFile(item: FileListItem): boolean {
|
||||||
|
if (item.file && item.file.type) {
|
||||||
|
return item.file.type.indexOf('image') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.url) {
|
||||||
|
return isImageUrl(item.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.content) {
|
||||||
|
return item.content.indexOf('data:image') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user