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 函數
您可以使用 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 https://127.0.0.1:' + port)
})
ASP.NET MVC/Core
QUploader 與 Microsoft ASP.NET MVC/Core 2.x Web API 後端無縫整合。在您的 Vue 檔案中,使用所需的 Web API 端點設定 QUploader 元件
<q-uploader
url="https://127.0.0.1:4444/fileuploader/upload"
label="Upload"
style="max-width: 300px"
/>
如果您的伺服器需要身分驗證 (例如 JWT 權杖),請使用 QUploader 的 factory 函數來指定 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: 'https://127.0.0.1:4444/fileuploader/upload',
method: 'POST',
headers: [
{ name: 'Authorization', value: `Bearer ${token}` }
]
})
})
}
}
}
</script>
QUploader 的檔案酬載將是一個正確格式的 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 中全域註冊此元件,或者匯入它並將其新增至 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 為您自動完成屬性和插槽。
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>;
}
}