为什么捐赠
API 浏览器
联系站长
上传器

Quasar 通过 QUploader 组件提供了一种上传文件的方式。

TIP

如果您只是想要一个输入文件的组件,那么您可能需要考虑使用 QFile 文件选择器组件。

正在加载 QUploader API...

用法

WARNING

QUploader 需要一个后端服务器来接收文件。下面的示例不会真正地上传。

TIP

QUploader 兼容"拖放"操作。

WARNING

当使用 vee-validate 时,您需要重命名 vee-validate 的 “fieldBagName” 配置以使 q-uploader 正常工作。

设计

基础



强制暗色模式



上传多个文件

默认情况下,多个文件将被单独上传(每个文件一个线程)。如果您希望所有文件都在单个线程中上传,请使用 batch 属性(下面示例中的第二个 QUploader)。

多个文件



限制上传

基础限制



TIP

在上面的示例中,我们使用的是 accept 属性。其值必须是以逗号分隔的唯一文件类型说明符列表。映射到原生 input type=file 元素的 ‘accept’ 属性。更多信息

WARNING

accept 属性的推荐格式为 <mediatype>/<extension>。示例:“image/jpeg”、“image/png”。QUploader 在底层使用了一个 <input type="file">,它完全依赖于宿主浏览器来触发文件选择器。如果 accept 属性(应用于 input)不正确,则不会在屏幕上显示文件选择器,或者它会出现但会接受所有文件类型。

您还可以应用自定义过滤器(在用户选择文件后执行):

过滤



添加请求头

使用 headers 来设置要与上传请求一起发送的额外 XHR 请求头。如果您需要嵌入其他字段,也请查看 API 中的 form-fields 属性。

请求头



TIP

这两个属性(headersform-fields)也可以用作函数((files) => Array),允许您根据要上传的文件动态设置它们。

还有 with-credentials 属性,它将上传过程中使用的 XHR 的 withCredentials 设置为 true

处理上传

选择文件后自动上传



自定义上传 URL



TIP

您还可以通过 headersmethod 属性自定义 HTTP 请求头和 HTTP 方法。查看 QUploader API 部分。

工厂函数

有一个 factory 属性,它必须是一个函数。此函数可以返回一个对象或解析为对象的 Promise(如果 Promise 失败,则会触发 @factory-failed 事件)。

上述对象可以覆盖以下 QUploader 属性:urlmethodheadersformFieldsfieldNamewithCredentialssendRaw。此对象的属性也可以是函数(形式为 (file[s]) => value):

基于 Promise 的工厂函数



您也可以使用 factory 函数属性并立即返回相同的对象。如果您想同时设置多个属性(如上所述),这很有用:

立即返回的工厂函数



插槽

在下面的示例中,我们展示了默认头部的等效实现。还注意一些您可以使用的布尔作用域属性:scope.canAddFilesscope.canUploadscope.isUploading

WARNING

请注意,您必须安装并使用另一个组件(QUploaderAddTrigger)才能将文件添加到队列中。此组件需要放置在具有 position: relative 的 DOM 节点下(提示:QBtn 已经具有此属性),并且当用户点击其父元素时会自动注入必要的事件(不要手动添加 @click="scope.pickFiles")。如果触发器不起作用,请检查是否有元素渲染在其上方,并相应地更改 QUploaderAddTrigger 的 zIndex。

自定义头部



自定义列表



服务器端点示例

QUploader 默认使用 HTTP(S) 协议上传文件(但不限于此,您将在下一节中看到)。

TIP

您并不一定要像下面那样使用 Nodejs 服务器、Spring 或 ASP.NET – 您可以使用任何您想要的方式来处理文件上传,只要您使用的方法符合 HTTP 协议即可。例如 PHP

Nodejs

下面是一个用 Nodejs 编写的基本服务器示例。它除了接收文件之外什么都不做,所以请将它作为起点。

import fs from "node:fs";
import path from "node:path";
import express from "express";
import formidable from "formidable";
import throttle from "express-throttle-bandwidth";

const app = express();

const port = process.env.PORT || 4444;
const folder = fileURLToPath(new URL("./files", import.meta.url));

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 文件中,配置 QUploader 组件并设置所需的 Web API 端点:

<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 的文件载荷将是一个格式正确的 IFormFileCollection 对象,您可以通过 ASP.NET Web API 控制器的 .Request 属性读取它。 ASP.NET Core 2.2 Controller:

[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 组件,您可以在应用程序中导入它。

MyUploader.js

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,
    };
  },
});

TIPS

  • 对于这种插件形式的默认 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>;
  }
}