[new feature] Uploader: support multiple files (#480)

This commit is contained in:
neverland 2017-12-25 16:06:27 +08:00 committed by GitHub
parent 30f22b28ed
commit 4b0f4ac426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 66 deletions

View File

@ -10,7 +10,7 @@
<demo-block :title="$t('title2')"> <demo-block :title="$t('title2')">
<div class="demo-uploader-container"> <div class="demo-uploader-container">
<van-uploader :after-read="logContent" accept="image/gif, image/jpeg"> <van-uploader :after-read="logContent" accept="image/gif, image/jpeg" multiple>
<van-icon name="photograph" /> <van-icon name="photograph" />
</van-uploader> </van-uploader>
</div> </div>

View File

@ -30,10 +30,10 @@ export default {
``` ```
#### Set input attr #### Set input attr
You can set native properties such as `accpet` on Uploader, and the input will automatically inherits the attribute. You can set native properties such as `accpet``multiple` on Uploader, and the input will automatically inherits the attribute.
```html ```html
<van-uploader :afterRead="logContent" accept="image/gif, image/jpeg"> <van-uploader :afterRead="logContent" accept="image/gif, image/jpeg" multiple>
<van-icon name="photograph" /> <van-icon name="photograph" />
</van-uploader> </van-uploader>
``` ```

View File

@ -28,10 +28,10 @@ export default {
``` ```
#### 设置 Input 属性 #### 设置 Input 属性
可以直接在 Uploader 上设置 accpet 等原生属性input 会自动继承该属性 可以直接在 Uploader 上设置 accpet、multiple 等原生属性input 会自动继承该属性
```html ```html
<van-uploader :afterRead="logContent" accept="image/gif, image/jpeg"> <van-uploader :afterRead="logContent" accept="image/gif, image/jpeg" multiple>
<van-icon name="photograph" /> <van-icon name="photograph" />
</van-uploader> </van-uploader>
``` ```

View File

@ -7,7 +7,7 @@
class="van-uploader__input" class="van-uploader__input"
v-bind="$attrs" v-bind="$attrs"
:disabled="disabled" :disabled="disabled"
@change="onValueChange" @change="onChange"
/> />
</div> </div>
</template> </template>
@ -29,30 +29,52 @@ export default create({
}, },
methods: { methods: {
onValueChange(event) { onChange(event) {
if (this.disabled) { let { files } = event.target;
if (this.disabled || !files.length) {
return; return;
} }
const file = event.target.files[0]; files = files.length === 1 ? files[0] : [].slice.call(files, 0);
if (!file || (this.beforeRead && !this.beforeRead(file))) { if (!files || (this.beforeRead && !this.beforeRead(files))) {
return; return;
} }
const reader = new FileReader(); if (Array.isArray(files)) {
reader.onload = (e) => { Promise.all(files.map(this.readFile)).then(contents => {
this.afterRead && this.afterRead({ this.onAfterRead(
file, files.map((file, index) => ({
content: e.target.result file: files[index],
content: contents[index]
}))
);
});
} else {
this.readFile(files).then(content => {
this.onAfterRead({ file: files, content });
}); });
this.$refs.input && (this.$refs.input.value = '');
};
if (this.resultType === 'dataUrl') {
reader.readAsDataURL(file);
} else if (this.resultType === 'text') {
reader.readAsText(file);
} }
},
readFile(file) {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = event => {
resolve(event.target.result);
};
if (this.resultType === 'dataUrl') {
reader.readAsDataURL(file);
} else if (this.resultType === 'text') {
reader.readAsText(file);
}
});
},
onAfterRead(file) {
this.afterRead && this.afterRead(file);
this.$refs.input && (this.$refs.input.value = '');
} }
} }
}); });

View File

@ -1,8 +1,10 @@
import Uploader from 'packages/uploader'; import Uploader from 'packages/uploader';
import { mount } from 'avoriaz'; import { mount } from 'avoriaz';
window.File = function() { window.File = function() {
this.name = 'test'; this.name = 'test';
}; };
window.FileReader = function() { window.FileReader = function() {
this.readAsDataURL = this.readAsText = function() { this.readAsDataURL = this.readAsText = function() {
this.onload && this.onload({ this.onload && this.onload({
@ -12,97 +14,91 @@ window.FileReader = function() {
}); });
}; };
}; };
const mockFile = new File([], '/Users');
describe('Uploader', () => { describe('Uploader', () => {
let wrapper; let wrapper;
afterEach(() => { afterEach(() => {
wrapper && wrapper.destroy(); wrapper && wrapper.destroy();
}); });
it('enabled', () => {
wrapper = mount(Uploader, {
propsData: {
disabled: false
}
});
expect(wrapper.contains('input')).to.equal(true);
expect(wrapper.vm.onValueChange({ target: { files: [] }})).to.equal(undefined);
});
it('disabled', () => { it('disabled', () => {
const afterRead = sinon.spy();
wrapper = mount(Uploader, { wrapper = mount(Uploader, {
propsData: { propsData: {
disabled: true disabled: true,
afterRead
} }
}); });
expect(wrapper.contains('input')).to.equal(true); expect(wrapper.contains('input')).to.equal(true);
expect(wrapper.vm.onValueChange({ target: { files: [] }})).to.equal(undefined); wrapper.vm.onChange({ target: { files: [] }});
expect(afterRead.calledOnce).to.be.false;
}); });
it('before read', () => { it('before read', () => {
const afterRead = sinon.spy();
wrapper = mount(Uploader, { wrapper = mount(Uploader, {
propsData: { propsData: {
disabled: false, beforeRead: () => false,
beforeRead: () => { afterRead
return false;
}
} }
}); });
expect(wrapper.contains('input')).to.equal(true); wrapper.vm.onChange({ target: { files: [mockFile] }});
expect(wrapper.vm.onValueChange({ target: { files: [new File([], '')] }})).to.equal(undefined); expect(afterRead.calledOnce).to.be.false;
}); });
it('read text', () => { it('read text', done => {
wrapper = mount(Uploader, { wrapper = mount(Uploader, {
propsData: { propsData: {
disabled: false,
resultType: 'text', resultType: 'text',
afterRead: (file) => { afterRead: (file) => {
expect(file.content).to.equal('test');
done();
} }
} }
}); });
expect(wrapper.contains('input')).to.equal(true); wrapper.vm.onChange({ target: { files: [mockFile] }});
expect(wrapper.vm.onValueChange({ target: { files: [new File([], '/Users')] }})).to.equal(undefined);
}); });
it('read text no after hook', () => { it('read dataUrl', done => {
wrapper = mount(Uploader, { wrapper = mount(Uploader, {
propsData: { propsData: {
disabled: false,
resultType: 'text'
}
});
expect(wrapper.contains('input')).to.equal(true);
expect(wrapper.vm.onValueChange({ target: { files: [new File([], '/Users')] }})).to.equal(undefined);
});
it('read dataUrl', () => {
wrapper = mount(Uploader, {
propsData: {
disabled: false,
resultType: 'dataUrl',
afterRead: (file) => { afterRead: (file) => {
expect(file.content).to.equal('test');
done();
} }
} }
}); });
expect(wrapper.contains('input')).to.equal(true); wrapper.vm.onChange({ target: { files: [mockFile] }});
expect(wrapper.vm.onValueChange({ target: { files: [new File([], '/Users')] }})).to.equal(undefined);
}); });
it('unknown resultType', () => { it('unknown resultType', () => {
const afterRead = sinon.spy();
wrapper = mount(Uploader, { wrapper = mount(Uploader, {
propsData: { propsData: {
disabled: false, resultType: 'xxxx',
resultType: 'xxxx' afterRead
}
});
wrapper.vm.onChange({ target: { files: [mockFile] }});
expect(afterRead.calledOnce).to.be.false;
});
it('read multiple files', done => {
wrapper = mount(Uploader, {
propsData: {
afterRead: (file) => {
expect(file.length).to.equal(2);
done();
}
} }
}); });
expect(wrapper.contains('input')).to.equal(true); wrapper.vm.onChange({ target: { files: [mockFile, mockFile] }});
expect(wrapper.vm.onValueChange({ target: { files: [new File([], '/Users')] }})).to.equal(undefined);
}); });
}); });