Quasar 从 axios 上传文件
Quasar upload file from axios
我有一个包含多个输入的表单,其中也包括文件输入。现在,我想将这些数据传递给 onSubmit
函数。但是,有一个问题,在 quasar 文档中,我没有在脚本部分看到有关 Axios 文件上传的说明。
我读了Uploader in the quasar doc and also I read this one from ,但我没有为我工作
此外,这是我的模板代码:
<template>
<div class="q-pa-md q-mt-md">
<q-card class="my-card">
<q-form
@submit="onSubmit"
class="q-gutter-md"
>
<div class="row justify-center">
<q-uploader
label="Upload your music"
color="purple"
accept=".mp3"
:max-file-size="20000000"
square
flat
@add="file_selected"
bordered
/>
</div>
<div class="row justify-center">
<q-btn label="Edit" type="submit" color="primary" v-if="song_id" class="q-ma-md" />
<q-btn label="Add" type="submit" color="primary" v-else class="q-ma-md" />
<q-btn label="Cancel" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</q-card>
</div>
</template>
方法部分:
file_selected: function (file) {
console.log(file)
this.selected_file = file[0]
this.check_if_document_upload = true
},
onSubmit: function () {
const url = '/core/v1/api/songs/upload'
const fileData = new FormData()
fileData.append('file_data', this.selected_file)
fileData.append('song_id', this.song_id)
this.$axios.post(url, fileData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(function () {
console.log('SUCCESS!!')
})
.catch(function () {
console.log('FAILURE!!')
})
和data
部分:
data: () => ({
selected_file: '',
check_if_document_upload: false,
song_id: '',
song_data: {
status: true
},
dashData: []
}),
如果类星体上传不适合您,并且您正在使用状态管理 vuex,您可以尝试编写自定义代码来完成您想要的。尝试使用 axios
发送 post 请求
createEvents({ commit }, payload) {
const stuff = {
title: payload.title,
location: payload.location,
description: payload.description,
image = payload.image;
};
let formData = new FormData();
bodyFormData.set('title', stuff.title); //done for the text data
formData.append("imageUrl", stuff.image); //done for file data
axios
.post({
method: 'post',
url: 'myurl',
data: formData,
headers: {'Content-Type': 'multipart/form-data' }
})
.then(response => {
commit("createEvents", response.data);
})
.catch(err => err.data);
}
}
对于提交函数(方法),它应该看起来像这样
createEvent(){
const newEvent = {
title: '',
location: '',
description: '',
image: this.image,
};
this.$store.dispatch("createEvents", newEvent);
};
最后,表单本身在您的代码中。图像应该用一个简单的引用
<input type='file' ref='image'>
其余表格可以正常
<form>
<input type='text' v-model='text'>
<-- more of the same -->
<input type='file' ref='image'>
// prevent is to keep the page from reloading when the form gets submitted,
// just a precaution measure
<button type=submit @click.prevent=createEvent()>submit</button>
</form>
希望对您有所帮助
我发现了我的问题。我应该在模板中将 @add
更改为 @added
。
<template>
<div class="q-pa-md q-mt-md">
<q-card class="my-card">
<q-form
@submit="onSubmit"
class="q-gutter-md"
>
<div class="row justify-center">
<q-uploader
label="Upload your music"
color="purple"
accept=".mp3"
:max-file-size="20000000"
square
flat
@added="file_selected"
bordered
/>
</div>
<div class="row justify-center">
<q-btn label="Edit" type="submit" color="primary" v-if="song_id" class="q-ma-md" />
<q-btn label="Add" type="submit" color="primary" v-else class="q-ma-md" />
<q-btn label="Cancel" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</q-card>
</div>
</template>
如果你想保留 QUploader 的功能、状态变化、上传进度,在我的例子中,我做了组件扩展并且它工作正常,也许它效率不高,因为我必须添加我自己的方法:上传,__uploadFiles.
不要添加覆盖 __runFactory 的方法,因为我省略了批量加载选项,而且我将始终使用工厂作为函数。
Q上传源:
Part Code from Quasar Components Uploader -> xhr mixin.js
upload () {
if (this.canUpload === false) {
return
}
const queue = this.queuedFiles.slice(0)
this.queuedFiles = []
if (this.xhrProps.batch(queue)) {
this.__runFactory(queue)
}
else {
queue.forEach(file => {
this.__runFactory([ file ])
})
}
},
__runFactory (files) {
this.workingThreads++
if (typeof this.factory !== 'function') {
this.__uploadFiles(files, {})
return
}
const res = this.factory(files)
if (!res) {
this.$emit(
'factory-failed',
new Error('QUploader: factory() does not return properly'),
files
)
this.workingThreads--
}
else if (typeof res.catch === 'function' && typeof res.then === 'function') {
this.promises.push(res)
const failed = err => {
if (this._isBeingDestroyed !== true && this._isDestroyed !== true) {
this.promises = this.promises.filter(p => p !== res)
if (this.promises.length === 0) {
this.abortPromises = false
}
this.queuedFiles = this.queuedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'failed') })
this.$emit('factory-failed', err, files)
this.workingThreads--
}
}
res.then(factory => {
if (this.abortPromises === true) {
failed(new Error('Aborted'))
}
else if (this._isBeingDestroyed !== true && this._isDestroyed !== true) {
this.promises = this.promises.filter(p => p !== res)
this.__uploadFiles(files, factory)
}
}).catch(failed)
}
else {
this.__uploadFiles(files, res || {})
}
},
__uploadFiles (files, factory) {
const
form = new FormData(),
xhr = new XMLHttpRequest()
const getProp = (name, arg) => {
return factory[name] !== void 0
? getFn(factory[name])(arg)
: this.xhrProps[name](arg)
}
const url = getProp('url', files)
if (!url) {
console.error('q-uploader: invalid or no URL specified')
this.workingThreads--
return
}
const fields = getProp('formFields', files)
fields !== void 0 && fields.forEach(field => {
form.append(field.name, field.value)
})
let
uploadIndex = 0,
uploadIndexSize = 0,
uploadedSize = 0,
maxUploadSize = 0,
aborted
xhr.upload.addEventListener('progress', e => {
if (aborted === true) { return }
const loaded = Math.min(maxUploadSize, e.loaded)
this.uploadedSize += loaded - uploadedSize
uploadedSize = loaded
let size = uploadedSize - uploadIndexSize
for (let i = uploadIndex; size > 0 && i < files.length; i++) {
const
file = files[i],
uploaded = size > file.size
if (uploaded) {
size -= file.size
uploadIndex++
uploadIndexSize += file.size
this.__updateFile(file, 'uploading', file.size)
}
else {
this.__updateFile(file, 'uploading', size)
return
}
}
}, false)
xhr.onreadystatechange = () => {
if (xhr.readyState < 4) {
return
}
if (xhr.status && xhr.status < 400) {
this.uploadedFiles = this.uploadedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'uploaded') })
this.$emit('uploaded', { files, xhr })
}
else {
aborted = true
this.uploadedSize -= uploadedSize
this.queuedFiles = this.queuedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'failed') })
this.$emit('failed', { files, xhr })
}
this.workingThreads--
this.xhrs = this.xhrs.filter(x => x !== xhr)
}
xhr.open(
getProp('method', files),
url
)
if (getProp('withCredentials', files) === true) {
xhr.withCredentials = true
}
const headers = getProp('headers', files)
headers !== void 0 && headers.forEach(head => {
xhr.setRequestHeader(head.name, head.value)
})
const sendRaw = getProp('sendRaw', files)
files.forEach(file => {
this.__updateFile(file, 'uploading', 0)
if (sendRaw !== true) {
form.append(getProp('fieldName', file), file, file.name)
}
file.xhr = xhr
file.__abort = () => { xhr.abort() }
maxUploadSize += file.size
})
this.$emit('uploading', { files, xhr })
this.xhrs.push(xhr)
if (sendRaw === true) {
xhr.send(new Blob(files))
}
else {
xhr.send(form)
}
}
结果:使用 AXIOS - 从 QUploader 扩展的组件 Vue
<script lang="ts">
import { QUploader } from 'quasar';
export default class AxiosUploader extends QUploader {
constructor(props) {
super(props);
}
AxiosUpload() {
if (this.canUpload === false) {
return;
}
const queue = this.queuedFiles.slice(0);
this.queuedFiles = [];
const factory = this.factory(queue);
queue.forEach(file => {
this.workingThreads++;
this.uploadFiles([file], factory);
});
}
uploadFiles(files, factory) {
const form = new FormData(),
headers = {};
factory.headers.forEach(head => {
headers[head.name] = head.value;
});
factory.formFields.forEach(field => {
form.append(field.name, field.value);
});
form.append(factory.fieldName, files[0], files[0].name);
let uploadIndex = 0,
uploadIndexSize = 0,
uploadedSize = 0,
maxUploadSize = 0,
aborted;
const xhr = this.$axios.post(factory.url, form, {
headers,
onUploadProgress: (e: ProgressEvent) => {
if (aborted === true) {
return;
}
const loaded = Math.min(maxUploadSize, e.loaded);
this.uploadedSize += loaded - uploadedSize;
uploadedSize = loaded;
let size = uploadedSize - uploadIndexSize;
for (let i = uploadIndex; size > 0 && i < files.length; i++) {
const file = files[i],
uploaded = size > file.size;
if (uploaded) {
size -= file.size;
uploadIndex++;
uploadIndexSize += file.size;
this.__updateFile(file, 'uploading', file.size);
} else {
this.__updateFile(file, 'uploading', size);
return;
}
}
}
});
this.xhrs.push(xhr);
this.$emit('uploading', { files, xhr });
xhr
.then(res => {
this.uploadedFiles = this.uploadedFiles.concat(files);
files.forEach(f => {
this.__updateFile(f, 'uploaded');
});
this.$emit('uploaded', { files, xhr });
})
.catch(err => {
aborted = true;
this.uploadedSize -= uploadedSize;
this.queuedFiles = this.queuedFiles.concat(files);
files.forEach(f => {
this.__updateFile(f, 'failed');
});
this.$emit('failed', { files, xhr });
})
.finally(() => {
this.workingThreads--;
this.xhrs = this.xhrs.filter(x => x !== xhr);
});
files.forEach(file => {
this.__updateFile(file, 'uploading', 0);
file.xhr = xhr;
file.__abort = () => {
xhr.abort();
};
maxUploadSize += file.size;
});
this.$emit('uploading', { files, xhr });
this.xhrs.push(xhr);
}
}
</script>
The component to use is AxiosUploader instead of q-uploader,
and instead of calling the upload () method, I call the AxiosUpload method. You could adapt to your needs
我有一个包含多个输入的表单,其中也包括文件输入。现在,我想将这些数据传递给 onSubmit
函数。但是,有一个问题,在 quasar 文档中,我没有在脚本部分看到有关 Axios 文件上传的说明。
我读了Uploader in the quasar doc and also I read this one from
此外,这是我的模板代码:
<template>
<div class="q-pa-md q-mt-md">
<q-card class="my-card">
<q-form
@submit="onSubmit"
class="q-gutter-md"
>
<div class="row justify-center">
<q-uploader
label="Upload your music"
color="purple"
accept=".mp3"
:max-file-size="20000000"
square
flat
@add="file_selected"
bordered
/>
</div>
<div class="row justify-center">
<q-btn label="Edit" type="submit" color="primary" v-if="song_id" class="q-ma-md" />
<q-btn label="Add" type="submit" color="primary" v-else class="q-ma-md" />
<q-btn label="Cancel" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</q-card>
</div>
</template>
方法部分:
file_selected: function (file) {
console.log(file)
this.selected_file = file[0]
this.check_if_document_upload = true
},
onSubmit: function () {
const url = '/core/v1/api/songs/upload'
const fileData = new FormData()
fileData.append('file_data', this.selected_file)
fileData.append('song_id', this.song_id)
this.$axios.post(url, fileData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(function () {
console.log('SUCCESS!!')
})
.catch(function () {
console.log('FAILURE!!')
})
和data
部分:
data: () => ({
selected_file: '',
check_if_document_upload: false,
song_id: '',
song_data: {
status: true
},
dashData: []
}),
如果类星体上传不适合您,并且您正在使用状态管理 vuex,您可以尝试编写自定义代码来完成您想要的。尝试使用 axios
发送 post 请求createEvents({ commit }, payload) {
const stuff = {
title: payload.title,
location: payload.location,
description: payload.description,
image = payload.image;
};
let formData = new FormData();
bodyFormData.set('title', stuff.title); //done for the text data
formData.append("imageUrl", stuff.image); //done for file data
axios
.post({
method: 'post',
url: 'myurl',
data: formData,
headers: {'Content-Type': 'multipart/form-data' }
})
.then(response => {
commit("createEvents", response.data);
})
.catch(err => err.data);
}
}
对于提交函数(方法),它应该看起来像这样
createEvent(){
const newEvent = {
title: '',
location: '',
description: '',
image: this.image,
};
this.$store.dispatch("createEvents", newEvent);
};
最后,表单本身在您的代码中。图像应该用一个简单的引用
<input type='file' ref='image'>
其余表格可以正常
<form>
<input type='text' v-model='text'>
<-- more of the same -->
<input type='file' ref='image'>
// prevent is to keep the page from reloading when the form gets submitted,
// just a precaution measure
<button type=submit @click.prevent=createEvent()>submit</button>
</form>
希望对您有所帮助
我发现了我的问题。我应该在模板中将 @add
更改为 @added
。
<template>
<div class="q-pa-md q-mt-md">
<q-card class="my-card">
<q-form
@submit="onSubmit"
class="q-gutter-md"
>
<div class="row justify-center">
<q-uploader
label="Upload your music"
color="purple"
accept=".mp3"
:max-file-size="20000000"
square
flat
@added="file_selected"
bordered
/>
</div>
<div class="row justify-center">
<q-btn label="Edit" type="submit" color="primary" v-if="song_id" class="q-ma-md" />
<q-btn label="Add" type="submit" color="primary" v-else class="q-ma-md" />
<q-btn label="Cancel" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</q-card>
</div>
</template>
如果你想保留 QUploader 的功能、状态变化、上传进度,在我的例子中,我做了组件扩展并且它工作正常,也许它效率不高,因为我必须添加我自己的方法:上传,__uploadFiles.
不要添加覆盖 __runFactory 的方法,因为我省略了批量加载选项,而且我将始终使用工厂作为函数。
Q上传源:
Part Code from Quasar Components Uploader -> xhr mixin.js
upload () {
if (this.canUpload === false) {
return
}
const queue = this.queuedFiles.slice(0)
this.queuedFiles = []
if (this.xhrProps.batch(queue)) {
this.__runFactory(queue)
}
else {
queue.forEach(file => {
this.__runFactory([ file ])
})
}
},
__runFactory (files) {
this.workingThreads++
if (typeof this.factory !== 'function') {
this.__uploadFiles(files, {})
return
}
const res = this.factory(files)
if (!res) {
this.$emit(
'factory-failed',
new Error('QUploader: factory() does not return properly'),
files
)
this.workingThreads--
}
else if (typeof res.catch === 'function' && typeof res.then === 'function') {
this.promises.push(res)
const failed = err => {
if (this._isBeingDestroyed !== true && this._isDestroyed !== true) {
this.promises = this.promises.filter(p => p !== res)
if (this.promises.length === 0) {
this.abortPromises = false
}
this.queuedFiles = this.queuedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'failed') })
this.$emit('factory-failed', err, files)
this.workingThreads--
}
}
res.then(factory => {
if (this.abortPromises === true) {
failed(new Error('Aborted'))
}
else if (this._isBeingDestroyed !== true && this._isDestroyed !== true) {
this.promises = this.promises.filter(p => p !== res)
this.__uploadFiles(files, factory)
}
}).catch(failed)
}
else {
this.__uploadFiles(files, res || {})
}
},
__uploadFiles (files, factory) {
const
form = new FormData(),
xhr = new XMLHttpRequest()
const getProp = (name, arg) => {
return factory[name] !== void 0
? getFn(factory[name])(arg)
: this.xhrProps[name](arg)
}
const url = getProp('url', files)
if (!url) {
console.error('q-uploader: invalid or no URL specified')
this.workingThreads--
return
}
const fields = getProp('formFields', files)
fields !== void 0 && fields.forEach(field => {
form.append(field.name, field.value)
})
let
uploadIndex = 0,
uploadIndexSize = 0,
uploadedSize = 0,
maxUploadSize = 0,
aborted
xhr.upload.addEventListener('progress', e => {
if (aborted === true) { return }
const loaded = Math.min(maxUploadSize, e.loaded)
this.uploadedSize += loaded - uploadedSize
uploadedSize = loaded
let size = uploadedSize - uploadIndexSize
for (let i = uploadIndex; size > 0 && i < files.length; i++) {
const
file = files[i],
uploaded = size > file.size
if (uploaded) {
size -= file.size
uploadIndex++
uploadIndexSize += file.size
this.__updateFile(file, 'uploading', file.size)
}
else {
this.__updateFile(file, 'uploading', size)
return
}
}
}, false)
xhr.onreadystatechange = () => {
if (xhr.readyState < 4) {
return
}
if (xhr.status && xhr.status < 400) {
this.uploadedFiles = this.uploadedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'uploaded') })
this.$emit('uploaded', { files, xhr })
}
else {
aborted = true
this.uploadedSize -= uploadedSize
this.queuedFiles = this.queuedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'failed') })
this.$emit('failed', { files, xhr })
}
this.workingThreads--
this.xhrs = this.xhrs.filter(x => x !== xhr)
}
xhr.open(
getProp('method', files),
url
)
if (getProp('withCredentials', files) === true) {
xhr.withCredentials = true
}
const headers = getProp('headers', files)
headers !== void 0 && headers.forEach(head => {
xhr.setRequestHeader(head.name, head.value)
})
const sendRaw = getProp('sendRaw', files)
files.forEach(file => {
this.__updateFile(file, 'uploading', 0)
if (sendRaw !== true) {
form.append(getProp('fieldName', file), file, file.name)
}
file.xhr = xhr
file.__abort = () => { xhr.abort() }
maxUploadSize += file.size
})
this.$emit('uploading', { files, xhr })
this.xhrs.push(xhr)
if (sendRaw === true) {
xhr.send(new Blob(files))
}
else {
xhr.send(form)
}
}
结果:使用 AXIOS - 从 QUploader 扩展的组件 Vue
<script lang="ts">
import { QUploader } from 'quasar';
export default class AxiosUploader extends QUploader {
constructor(props) {
super(props);
}
AxiosUpload() {
if (this.canUpload === false) {
return;
}
const queue = this.queuedFiles.slice(0);
this.queuedFiles = [];
const factory = this.factory(queue);
queue.forEach(file => {
this.workingThreads++;
this.uploadFiles([file], factory);
});
}
uploadFiles(files, factory) {
const form = new FormData(),
headers = {};
factory.headers.forEach(head => {
headers[head.name] = head.value;
});
factory.formFields.forEach(field => {
form.append(field.name, field.value);
});
form.append(factory.fieldName, files[0], files[0].name);
let uploadIndex = 0,
uploadIndexSize = 0,
uploadedSize = 0,
maxUploadSize = 0,
aborted;
const xhr = this.$axios.post(factory.url, form, {
headers,
onUploadProgress: (e: ProgressEvent) => {
if (aborted === true) {
return;
}
const loaded = Math.min(maxUploadSize, e.loaded);
this.uploadedSize += loaded - uploadedSize;
uploadedSize = loaded;
let size = uploadedSize - uploadIndexSize;
for (let i = uploadIndex; size > 0 && i < files.length; i++) {
const file = files[i],
uploaded = size > file.size;
if (uploaded) {
size -= file.size;
uploadIndex++;
uploadIndexSize += file.size;
this.__updateFile(file, 'uploading', file.size);
} else {
this.__updateFile(file, 'uploading', size);
return;
}
}
}
});
this.xhrs.push(xhr);
this.$emit('uploading', { files, xhr });
xhr
.then(res => {
this.uploadedFiles = this.uploadedFiles.concat(files);
files.forEach(f => {
this.__updateFile(f, 'uploaded');
});
this.$emit('uploaded', { files, xhr });
})
.catch(err => {
aborted = true;
this.uploadedSize -= uploadedSize;
this.queuedFiles = this.queuedFiles.concat(files);
files.forEach(f => {
this.__updateFile(f, 'failed');
});
this.$emit('failed', { files, xhr });
})
.finally(() => {
this.workingThreads--;
this.xhrs = this.xhrs.filter(x => x !== xhr);
});
files.forEach(file => {
this.__updateFile(file, 'uploading', 0);
file.xhr = xhr;
file.__abort = () => {
xhr.abort();
};
maxUploadSize += file.size;
});
this.$emit('uploading', { files, xhr });
this.xhrs.push(xhr);
}
}
</script>
The component to use is AxiosUploader instead of q-uploader, and instead of calling the upload () method, I call the AxiosUpload method. You could adapt to your needs