上传

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

TIP

如果您只需要一个输入文件,您可能需要考虑使用QFile picker组件。

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”。

处理上传







TIP

您也可以通过headersmethod属性自定义HTTP头部和HTTP方法。 检查QUploader API部分。

工厂函数

您可以使用一个factory属性,该属性必须是一个函数。 该函数可以返回一个对象或一个用对象解决的Promise(并且如果Promise失败,则会发出@factory-failed事件)。

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




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




插槽

在下面的示例中,我们显示了等效于默认头部的内容。 还要注意一些可以使用的布尔scope属性:scope.canAddFilesscope.canUploadscope.isUploading

WARNING

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







服务器端例子

默认情况下,Quploader与HTTP(S)协议一起使用来上传文件(但不限于此,正如您将在此后面的部分中看到的那样)。

TIP

完全不需要像下面那样使用Nodejs服务器或Spring或ASP.NET-只要您使用的方法适合HTTP协议,就可以根据需要处理文件上传。 PHP的示例。

Nodejs

以下是用Node.js编写的基本服务器示例。 除了接收文件外,它什么也不做,因此请以它为起点。

const
  express = require('express'),
  app = express(),
  formidable = require('formidable'),
  path = require('path'),
  fs = require('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)) // 节流带宽

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) => {
        // 从您的存储中检索JWT令牌。
        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控制器:

[Route("api/[controller]")]
[ApiController]
public class FileUploaderController : ControllerBase
{
    [HttpPost]
    public async Task upload()
    {
        // 请求的.Form.Files属性
        // 将包含QUploader的文件。
        var files = this.Request.Form.Files;
        foreach (var file in files)
        {
            if (file == null || file.Length == 0)
                continue;

            // 对文件进行处理。
            var fileName = file.FileName;
            var fileSize = file.Length;
            // 保存到服务器...
            // ...
        }
    }
}

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()

支持其他服务

QUploader当前支持通过HTTP(S)协议上载。 但是您也可以扩展该组件以支持其他服务。 例如Firebase。 告诉你如何做到。

乐意接受帮助

我们也很乐意接受支持其他上传服务的PR,因此其他人可以从中受益。点击本页底部的 "在浏览器中编辑此页面"链接或页面顶部的铅笔图标。

下面是一个例子,你需要向createUploaderComponent() Quasar util提供API。这将创建一个Vue组件,你可以在你的应用程序中导入。

// MyUploader.js
import { createUploaderComponent } from 'quasar'
import { computed } from 'vue'

// 输出一个Vue组件
export default createUploaderComponent({
  // 在此定义QUploader插件

  name: 'MyUploader', // 您的组件的名称

  props: {
    // ...您的定制属性
  },

  emits: [
    // ...您的自定义事件名称列表
  ],

  injectPlugin ({ props, emit, helpers }) {
    // 可以在这里调用任何其他的组件 
    // 因为这个函数将在组件的setup()中运行。

    // [必需]
    // 我们正在上传文件
    const isUploading = computed(() => {
      // 返回<Boolean>
    })

    // [可选]
    // 显示上传器顶部的覆盖层,
    // 表明它正在等待某件事
    // (阻止所有控件)
    const isBusy = computed(() => {
      // 返回<Boolean>
    })

    // [必需]
    // 中止并清理
    // 正在进行的任何进程
    function abort () {
      // ...
    }

    // [ 必需!]
    // 开始上传过程
    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/runtime-core' {
  interface GlobalComponents {
    MyUploader: GlobalComponentConstructor<MyUploaderProps, QUploaderSlots>;
  }
}