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