Vue JS通过v-model上的文件上传器设置图像应用空对象

Posted

技术标签:

【中文标题】Vue JS通过v-model上的文件上传器设置图像应用空对象【英文标题】:Vue JS setting image through file uploader on v-model applies empty object 【发布时间】:2022-01-06 10:10:18 【问题描述】:

我正在使用 Vue JS 2 创建图像上传器。我的输入有一个change 函数,它运行一个函数并将我的文件设置在v-model 属性上。

当我console.log 我的数据时,所有设置的是一个空对象而不是图像,这也导致我的 Vee 验证规则失败,因为它认为它是空的。

我错过了什么?

用于上传徽标的 html

<validation-observer ref="brandCreationForm" v-slot=" handleSubmit ">
  <form class="space-y-6" @submit.stop.prevent="handleSubmit(create)">
    <validation-observer :key="1" class="space-y-6">

      <pre>
         form 
      </pre>

      <div>
        <validation-provider
          name="brand"
          rules="required"
          v-slot=" errors, classes "
        >
          <label for="brand" class="block text-sm font-medium text-gray-500 mb-2">Brand name</label>
          <div class="mt-1 relative rounded-md shadow-sm">
            <input v-model="form.brand" type="text" name="brand" id="brand" :class="classes" class="focus:ring-green-500 focus:border-green-500 block w-full py-3 px-4 sm:text-sm border border-gray-300 rounded-md" placeholder="my brand name">
          </div>
          <span class="text-xs text-red-500"> errors[0] </span>
        </validation-provider>
      </div>

      <section v-if="form.brand != '' && form.url != ''" class="space-y-6 pl-6">
        <div>
          <validation-provider
            name="brand_logo"
            rules="mimes:image/jpeg,image/png"
            v-slot=" errors, classes, validate "
          >
            <label for="brand_logo" class="block text-sm font-medium text-gray-500 mb-2">
              Brand logo <em>(PNG or JPG)</em>
            </label>
            <div class="mt-1 relative rounded-md shadow-sm">
              <input @change="uploadImage('brand_logo', $event.target.files[0]); validate()" type="file" name="brand_logo" id="brand_logo" :class="classes" class="focus:ring-green-500 focus:border-green-500 block w-full py-3 px-4 sm:text-sm border border-gray-300 rounded-md" accept="image/png, image/jpeg">
            </div>
            <span class="text-xs text-red-500"> errors[0] </span>
          </validation-provider>
        </div>

        <div>
          <validation-provider
            name="brand_favicon"
            rules="mimes:image/jpeg,image/png"
            v-slot=" errors, classes, validate "
          >
            <label for="brand_favicon" class="block text-sm font-medium text-gray-500 mb-2">
              Brand favicon <em>(PNG or JPG)</em>
            </label>
            <div class="mt-1 relative rounded-md shadow-sm">
              <input @change="uploadImage('brand_favicon', $event.target.files[0]); validate()" type="file" name="brand_favicon" id="brand_favicon" :class="classes" class="focus:ring-green-500 focus:border-green-500 block w-full py-3 px-4 sm:text-sm border border-gray-300 rounded-md" accept="image/png, image/jpeg">
            </div>
            <span class="text-xs text-red-500"> errors[0] </span>
          </validation-provider>
        </div>
      </section>

      <div class="flex justify-end">
        <button type="submit" class="group relative flex justify-center py-3 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-green-500 hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-20">
          <div class="inline-flex">
            <svg v-if="isSaving" class="animate-spin -ml-1 mr-3 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
              <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-></circle>
              <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
            </svg>
            Create brand
          </div>
        </button>
      </div>

      <Alert
        v-if="feedback.isShown"
        :message="feedback.message"
        :variant="feedback.variant" />

    </validation-observer>
  </form>
</validation-observer>

以下函数运行:

<script>
export default 
  layout: 'account',
  data () 
    return 
      isSaving: false,
      form: 
        brand: '',
        url: '',
        telephone: '',
        link_terms: '',
        link_privacy: '',
        brand_logo: null,
        brand_favicon: null,
        seo_description: '',
        text_marketing: '',
        text_promos: '',
        text_broker: '',
        text_footer_1: '',
        text_footer_2: '',
        text_credit_disclaimer: '',
        analytics_system_id: '',
        analytics_brand_id: ''
      ,
      feedback: 
        message: '',
        variant: '',
        isShown: false
      
    
  ,
  methods: 

    /*
    ** Create
    */
    create () 
      this.feedback.isShown = false
      this.isSaving = true

      this.$axios.post(`$this.$config.apiUrl/api/brands`, this.form, 
        timeout: 30 * 1000
      ).then((res) => 
        setTimeout(() => 
          this.$router.push('/account/brands/')
        , 500)
      ).finally(() => 
        this.isSaving = false
      )
    ,

    /*
    ** Select files to upload (file uploader)
    */
    uploadImage (model, file) 
      const form = new FormData()
      form.append(model, file, file.name)
      this.form[model] = form
    

  

</script>

哪个form 现在应该包含与我的图像相关的所有内容,但是在添加图像时,它显示为一个空对象(见附件)

在设置我的模型之前,我也尝试过JSON.stringify,这里也没有运气。

【问题讨论】:

你试过这种东西吗? academind.com/tutorials/vue-image-upload 另外,您需要记住 Vue2 中的 caveats for arrays。尝试将状态设置为单个状态以进行调试。 是的,试过了,我在我的函数中创建了一个form 变量,并完成了form.append('image', file, file.name) 但是当控制台记录form 时,它是空的,我需要将它添加到我的form请求 上次我做这个的时候,我可能遇到过类似的事情。如果通过 HTTP 发送文件会发生什么?你看到请求负载中的内容了吗? 我不能单独发送图像。它们必须是我原始帖子截图中form 对象的一部分。如果通过 http 发送它们将起作用,但是我如何将整个请求与其他所有内容结合起来? 你在使用FormData吗?上次用过,效果不错。也许可以阅读this one。 【参考方案1】:

formData 对象属性都是函数,因此在模板中呈现为空对象。为了在模板中显示 formData 内容,您必须调用其原型函数之一,并显示其结果。

<div v-for="item in form.brand_logo.values()">
   item  
</div>

正如您在codesandbox 中看到的那样,选择文件后,它会显示在模板和控制台中。

由于我已经简化了很多你的代码,并且只保留了 formData 的东西,也许你应该创建一个可重现的示例。

【讨论】:

当然,但是如果是这种情况,为什么(当我提交表单时)它是空的?我的后端,Laravel 甚至在我记录值时说这里也是空的 一个问题可能是不正确的内容类型标题。使用 axios 发布时,它会从发布数据中推断内容类型。在您的情况下,它将是 application/json,因为 form 是一个对象,并且多部分内容将被忽略。我认为您应该尝试将所有 form 对象变成一个 formData 对象,或者拆分请求,并分别发送文件。您不能混合使用 json 和多部分请求正文。

以上是关于Vue JS通过v-model上的文件上传器设置图像应用空对象的主要内容,如果未能解决你的问题,请参考以下文章

从 vue.js 中的 store 获得的计算属性的设置器

记录一下vue3.0与2.0简单使用上的区别

Element+Vue.js 选择器常用属性

Vue.js 范围滑块,设置 v-model 并获取更改

vue.js实战学习——表单与v-model

自定义单选按钮上的 Vue v-model