Quasar 提供了一种通过 QUploader 组件上传文件的方法。
提示
如果您只需要一个文件输入,您可以考虑使用 QFile 文件选择器组件。
用法
警告
QUploader 需要后端服务器来接收文件。以下示例不会实际上传。
提示
QUploader 支持 拖放
。
警告
当使用 vee-validate 时,您必须重命名 vee-validate 的“fieldBagName”配置才能使 q-uploader 正常工作。
设计
上传多个文件
默认情况下,多个文件将被单独上传(每个文件一个线程)。如果您希望所有文件在一个线程中上传,请使用 batch
属性(以下示例中的第二个 QUploader)。
限制上传
提示
在上面的示例中,我们使用了 accept
属性。它的值必须是唯一文件类型说明符的逗号分隔列表。映射到原生 input type=file 元素的“accept”属性。 更多信息.
警告
accept
属性的推荐格式是 <mediatype>/<extension>
。例如:“image/jpeg”、“image/png”。QUploader 在内部使用 <input type="file">
,并且完全依赖于主机浏览器来触发文件选择器。如果 accept
属性(应用于输入)不正确,则屏幕上不会出现文件选择器,或者会出现文件选择器,但会接受所有文件类型。
您还可以应用自定义过滤器(在用户选择文件后执行)。
添加标头
使用 headers
设置要与上传请求一起发送的其他 XHR 标头。如果需要嵌入其他字段,还可以查看 API 中的 form-fields
属性。
提示
这两个属性(headers
和 form-fields
)也可以用作函数((files) => Array
),允许您根据要上传的文件动态设置它们。
还有一个 with-credentials
属性,它将上传过程使用的 XHR 的 withCredentials
设置为 true
。
处理上传
提示
您还可以通过 headers
和 method
属性自定义 HTTP 标头和 HTTP 方法。查看 QUploader API 部分。
工厂函数
有一个 factory
属性,您可以使用它,它必须是一个函数。此函数可以返回一个对象或一个解析为对象的 Promise(如果 Promise 失败,则会发出 @factory-failed
事件)。
上面描述的对象可以覆盖以下 QUploader 属性:url
、method
、headers
、formFields
、fieldName
、withCredentials
、sendRaw
)。此对象中的属性也可以是函数(形式为 (file[s]) => value
)。
您也可以使用 factory
函数属性并立即返回同一个对象。如果您想同时设置多个属性(如上所述),这很有用。
插槽
在下面的示例中,我们展示了默认标题的等效项。还要注意您可以使用的一些布尔范围属性:scope.canAddFiles
、scope.canUpload
、scope.isUploading
。
警告
请注意,您必须安装并使用另一个组件(QUploaderAddTrigger)才能将文件添加到队列。此组件需要放置在具有 position: relative
的 DOM 节点下(提示:QBtn 已经有了它),并且会在用户单击其父级时自动注入必要的事件(不要手动添加 @click="scope.pickFiles"
)。如果触发器不起作用,请检查您是否在它上面渲染了一个元素,并相应地更改 QUploaderAddTrigger 的 zIndex。
服务器端点示例
QUploader 默认使用 HTTP(S) 协议来上传文件(但它并不局限于此,您将在本节后面的内容中看到)。
提示
它不需要像下面一样使用 Nodejs 服务器或 Spring 或 ASP.NET – 您可以根据需要处理文件上传,只要您使用的方法符合 HTTP 协议即可。使用 PHP 的示例。
Nodejs
以下是用 Nodejs 编写的基本服务器示例。它除了接收文件之外什么都不做,所以将其视为一个起点。
const
express = require('express'),
app = express(),
formidable = require('formidable'),
path = require('node:path'),
fs = require('node:fs'),
throttle = require('express-throttle-bandwidth')
const
port = process.env.PORT || 4444,
folder = path.join(__dirname, 'files')
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder)
}
app.set('port', port)
app.use(throttle(1024 * 128)) // throttling bandwidth
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
next()
})
app.post('/upload', (req, res) => {
const form = new formidable.IncomingForm()
form.uploadDir = folder
form.parse(req, (_, fields, files) => {
console.log('\n-----------')
console.log('Fields', fields)
console.log('Received:', Object.keys(files))
console.log()
res.send('Thank you')
})
})
app.listen(port, () => {
console.log('\nUpload server running on http://localhost:' + port)
})
ASP.NET MVC/Core
QUploader 可以与 Microsoft ASP.NET MVC/Core 2.x Web API 后端无缝集成。在您的 Vue 文件中,使用所需的 Web API 端点配置 QUploader 组件
<q-uploader
url="http://localhost:4444/fileuploader/upload"
label="Upload"
style="max-width: 300px"
/>
如果您的服务器需要身份验证,例如 JWT 令牌,请使用 QUploader 的工厂函数指定 QUploader 将使用的 xhr 标头。例如
<template>
<q-uploader
label="Upload"
:factory="factoryFn"
style="max-width: 300px"
/>
</template>
<script>
export default {
methods: {
factoryFn (file) {
return new Promise((resolve, reject) => {
// Retrieve JWT token from your store.
const token = "myToken";
resolve({
url: 'http://localhost:4444/fileuploader/upload',
method: 'POST',
headers: [
{ name: 'Authorization', value: `Bearer ${token}` }
]
})
})
}
}
}
</script>
QUploader 的文件(s) 负载将是一个正确格式的 IFormFileCollection
对象,您可以通过 ASP.NET Web API 控制器的 .Request
属性读取它。ASP.NET Core 2.2 控制器
[Route("api/[controller]")]
[ApiController]
public class FileUploaderController : ControllerBase
{
[HttpPost]
public async Task upload()
{
// Request's .Form.Files property will
// contain QUploader's files.
var files = this.Request.Form.Files;
foreach (var file in files)
{
if (file == null || file.Length == 0)
continue;
// Do something with the file.
var fileName = file.FileName;
var fileSize = file.Length;
// save to server...
// ...
}
}
}
Spring
以下是一个 Spring 示例。属性 fieldName="file"
与 @RequestPart(value = "file")
映射。
// java
@RestController
public class UploadRest {
@PostMapping("/upload")
public void handleFileUpload(@RequestPart(value = "file") final MultipartFile uploadfile) throws IOException {
saveUploadedFiles(uploadfile);
}
private String saveUploadedFiles(final MultipartFile file) throws IOException {
final byte[] bytes = file.getBytes();
final Path path = Paths.get("YOUR_ABSOLUTE_PATH" + file.getOriginalFilename());
Files.write(path, bytes);
}
}
// html
<q-uploader field-name="file" url="YOUR_URL_BACK/upload" with-credentials />
Python/Flask
// python
from flask import Flask, request
from werkzeug import secure_filename
from flask_cors import CORS
import os
app = Flask(__name__)
# This is necessary because QUploader uses an AJAX request
# to send the file
cors = CORS()
cors.init_app(app, resource={r"/api/*": {"origins": "*"}})
@app.route('/upload', methods=['POST'])
def upload():
for fname in request.files:
f = request.files.get(fname)
print(f)
f.save('./uploads/%s' % secure_filename(fname))
return 'Okay!'
if __name__ == '__main__':
if not os.path.exists('./uploads'):
os.mkdir('./uploads')
app.run(debug=True)
Julia/Genie
# Julia Genie
using Genie, Genie.Requests, Genie.Renderer
Genie.config.cors_headers["Access-Control-Allow-Origin"] = "*"
Genie.config.cors_headers["Access-Control-Allow-Headers"] = "Content-Type"
Genie.config.cors_headers["Access-Control-Allow-Methods"] = "GET,POST,PUT,DELETE,OPTIONS"
Genie.config.cors_allowed_origins = ["*"]
#== server ==#
route("/") do
"File Upload"
end
route("/upload", method = POST) do
if infilespayload(:img) # :img is file-name
@info filename(filespayload(:img)) # file-name="img"
@info filespayload(:img).data
open("upload/file.jpg", "w") do io
write(io, filespayload(:img).data)
end
else
@info "No image uploaded"
end
Genie.Renderer.redirect(:get)
end
isrunning(:webserver) || up()
Perl/Mojolicious
# Perl
use Mojolicious::Lite -signatures;
# CORS
app->hook(after_dispatch => sub {
my $c = shift;
$c->res->headers->header('Access-Control-Allow-Origin' => '*');
});
options '*' => sub ($c) {
$c->res->headers->header('Access-Control-Allow-Methods' => 'GET, OPTIONS, POST, DELETE, PUT');
$c->res->headers->header('Access-Control-Allow-Headers' => 'Content-Type');
$c->render(text => '');
};
post '/upload' => sub ($c) {
my $uploads = $c->req->uploads('files');
foreach my $f (@{$uploads}) {
$f->move_to('/tmp/' . $f->filename);
}
$c->render(text => 'Saved!');
};
app->start;
支持其他服务
QUploader 目前支持通过 HTTP(S) 协议上传文件。但您可以扩展该组件以支持其他服务,例如 Firebase。以下是实现方法。
欢迎贡献
我们非常乐意接受关于支持其他上传服务的 PR,以便其他人可以从中受益。点击本页面底部的 Edit this page in browser
链接或页面顶部的铅笔图标。
下面是一个示例,其中包含您需要提供给 createUploaderComponent()
Quasar 工具的 API。这将创建一个 Vue 组件,您可以在应用程序中导入它。
import { createUploaderComponent } from 'quasar'
import { computed } from 'vue'
// export a Vue component
export default createUploaderComponent({
// defining the QUploader plugin here
name: 'MyUploader', // your component's name
props: {
// ...your custom props
},
emits: [
// ...your custom events name list
],
injectPlugin ({ props, emit, helpers }) {
// can call any other composables here
// as this function will run in the component's setup()
// [ REQUIRED! ]
// We're working on uploading files
const isUploading = computed(() => {
// return <Boolean>
})
// [ optional ]
// Shows overlay on top of the
// uploader signaling it's waiting
// on something (blocks all controls)
const isBusy = computed(() => {
// return <Boolean>
})
// [ REQUIRED! ]
// Abort and clean up any process
// that is in progress
function abort () {
// ...
}
// [ REQUIRED! ]
// Start the uploading process
function upload () {
// ...
}
return {
isUploading,
isBusy,
abort,
upload
}
}
})
提示
- 有关以插件形式实现的默认 XHR 实现,请查看 源代码.
- 对于 UMD 版本,请使用
Quasar.createUploaderComponent({ ... })
。
然后,您可以在全局范围内注册该组件,或者将其导入并将其添加到 Vue 组件中的“components: {}”中。
// globally registering your component in a boot file
import MyUploader from '../../path/to/MyUploader' // the file from above
export default ({ app }) {
app.component('MyUploader', MyUploader)
}
// or declaring it in a .vue file
import MyUploader from '../../path/to/MyUploader' // the file from above
export default {
// ...
components: {
// ...
MyUploader
}
}
如果您使用的是 TypeScript,则需要注册新的组件类型,以便 Volar 可以为您自动完成 props 和 slots。
import {
GlobalComponentConstructor,
QUploaderProps,
QUploaderSlots,
} from 'quasar';
interface MyUploaderProps extends QUploaderProps {
// .. add custom props
freeze: boolean;
// .. add custom events
onFreeze: boolean;
}
declare module 'vue' {
interface GlobalComponents {
MyUploader: GlobalComponentConstructor<MyUploaderProps, QUploaderSlots>;
}
}