文件选择器

QFile 是一个处理用户交互以选取文件的组件。

TIP

如果您还希望组件也为您处理上传,请考虑改用 QUploader

QFile API

QFile API


name
: String
说明
用于指定控件的名称;在处理表单时非常有用;如果未指定,则使用 'for' 属性的值,如果存在的话。
multiple
: Boolean
说明
允许多个文件上传
accept
: String
说明
逗号分隔的唯一文件类型规范列表。映射到原生输入类型为 file 的元素的 'accept' 属性
capture
: String
说明
可选地,指定应捕获新文件,并指定用于捕获由 'accept' 属性定义的新媒体的设备。映射到原生 input type=file 元素的 'capture' 属性。
max-file-size
: Number | String
说明
单个文件的最大大小(以字节为单位)
max-total-size
: Number | String
说明
所有文件组合的最大大小(以字节为单位)
max-files
: Number | String
说明
包含的文件数量上限
filter
: (files) => Array
说明
自定义过滤器用于添加的文件;只有通过此过滤器的文件才会被添加到队列并上传;为了获得最佳性能,请从您的作用域中引用它,不要内联定义。
error
: Boolean | null
说明
字段是否有验证错误?
rules
: Array
说明
函数/字符串数组;如果是字符串,则必须是内置验证规则之一的名称
reactive-rules
: Boolean
说明
默认情况下,规则的更改不会触发新的验证,直到发生 model 数据变化;如果设置为 true,则规则的更改将触发验证;这会带来性能损失,所以只在真正需要时使用。
lazy-rules
: Boolean | String
说明
如果设置为布尔值 true,则仅在字段第一次失去焦点后,根据 'rules' 检查验证状态;如果设置为 'ondemand',则只有在手动调用组件的 validate() 方法或者当包装器 QForm 提交自身时才会触发。
loading
: Boolean
说明
通过显示一个旋转器来向用户表示进程正在进行中;可以使用 'loading' 插槽自定义旋转器。
clearable
: Boolean
说明
当设置了一个值(不是 undefined 或 null)时,添加可清除的图标;点击后,model 数据变为 null
autofocus
: Boolean
说明
在初始组件渲染时聚焦字段
for
: String
说明
用于指定控件的 'id',同时也是包裹它的标签的 'for' 属性;如果未指定 'name' 属性,则也将用于此属性。
append
: Boolean
说明
将文件添加到当前模型而不是替换它们;仅在使用 'multiple' 模式时有效
counter-label
: (props) => String
说明
计数器的标签;'counter' 属性是启用此功能所必需的。

Design

WARNING

您只能给 QFile 使用一种主要的外观设计款式(filled, outlined, standout, borderless),不能使用多个,因为它们是互相排斥的。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-file v-model="model" label="Standard" />

      <q-file filled v-model="model" label="Filled" />

      <q-file outlined v-model="model" label="Outlined" />

      <q-file standout v-model="model" label="Standout" />

      <q-file standout="bg-teal text-white" v-model="model" label="Custom standout" />

      <q-file borderless v-model="model" label="Borderless" />

      <q-file rounded filled v-model="model" label="Rounded filled" />

      <q-file rounded outlined v-model="model" label="Rounded outlined" />

      <q-file rounded standout v-model="model" label="Rounded standout" />

      <q-file square filled v-model="model" label="Square filled" />

      <q-file square outlined v-model="model" label="Square outlined" />

      <q-file square standout v-model="model" label="Square standout" />
    </div>
  </div>
</template>

装饰



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md" style="max-width: 300px">
      <q-file filled v-model="model" label="Label (stacked)" stack-label />

      <q-file outlined v-model="model">
        <template v-slot:prepend>
          <q-icon name="attach_file" />
        </template>
      </q-file>

      <q-file standout v-model="model">
        <template v-slot:append>
          <q-avatar>
            <img src="https://cdn.quasar.dev/logo-v2/svg/logo.svg">
          </q-avatar>
        </template>
      </q-file>

      <q-file filled bottom-slots v-model="model" label="Label" counter>
        <template v-slot:prepend>
          <q-icon name="cloud_upload" @click.stop />
        </template>
        <template v-slot:append>
          <q-icon name="close" @click.stop="model = null" class="cursor-pointer" />
        </template>

        <template v-slot:hint>
          Field hint
        </template>
      </q-file>

      <q-file rounded outlined bottom-slots v-model="model" label="Label" counter max-files="12">
        <template v-slot:before>
          <q-icon name="attachment" />
        </template>

        <template v-slot:append>
          <q-icon v-if="model !== null" name="close" @click.stop="model = null" class="cursor-pointer" />
          <q-icon name="search" @click.stop />
        </template>

        <template v-slot:hint>
          Field hint
        </template>
      </q-file>

      <q-file filled bottom-slots v-model="model" label="Label" counter max-files="12">
        <template v-slot:before>
          <q-avatar>
            <img src="https://cdn.quasar.dev/img/avatar5.jpg">
          </q-avatar>
        </template>

        <template v-slot:append>
          <q-icon v-if="model !== null" name="close" @click.stop="model = null" class="cursor-pointer" />
          <q-icon name="create_new_folder" @click.stop />
        </template>

        <template v-slot:hint>
          Field hint
        </template>

        <template v-slot:after>
          <q-btn round dense flat icon="send" />
        </template>
      </q-file>

      <q-file filled bottom-slots v-model="model" label="Label" counter max-files="12">
        <template v-slot:before>
          <q-icon name="folder_open" />
        </template>

        <template v-slot:hint>
          Field hint
        </template>

        <template v-slot:append>
          <q-btn round dense flat icon="add" @click.stop />
        </template>
      </q-file>
    </div>
  </div>
</template>

着色



<template>
  <div class="q-pa-md">
    <div class="q-gutter-y-md column" style="max-width: 300px">
      <q-file color="purple-12" v-model="model" label="Label">
        <template v-slot:prepend>
          <q-icon name="attach_file" />
        </template>
      </q-file>

      <q-file color="teal" filled v-model="model" label="Label">
        <template v-slot:prepend>
          <q-icon name="cloud_upload" />
        </template>
      </q-file>

      <q-file color="grey-3" outlined label-color="orange" v-model="model" label="Label">
        <template v-slot:append>
          <q-icon name="attachment" color="orange" />
        </template>
      </q-file>

      <q-file color="lime-11" bg-color="green" filled v-model="model" label="Label">
        <template v-slot:prepend>
          <q-icon name="attachment" />
        </template>
      </q-file>

      <q-file color="teal" outlined v-model="model" label="Label">
        <template v-slot:append>
          <q-avatar>
            <img src="https://cdn.quasar.dev/logo-v2/svg/logo.svg">
          </q-avatar>
        </template>
      </q-file>

      <q-file clearable color="orange" standout bottom-slots v-model="model" label="Label" counter>
        <template v-slot:prepend>
          <q-icon name="attach_file" />
        </template>
        <template v-slot:append>
          <q-icon name="favorite" />
        </template>

        <template v-slot:hint>
          Field hint
        </template>
      </q-file>
    </div>
  </div>
</template>

可清除的

作为辅助,您可以使用 clearable 属性,这样用户可以通过附加的图标将数据重置为 null。下面第二个示例等价于使用 clearable



<template>
  <div class="q-pa-md">
    <div class="q-gutter-y-md column" style="max-width: 300px">
      <q-file clearable filled color="purple-12" v-model="model" label="Label" />

      <!-- equivalent -->
      <q-file color="orange" filled v-model="model" label="Label">
        <template v-if="model" v-slot:append>
          <q-icon name="cancel" @click.stop.prevent="model = null" class="cursor-pointer" />
        </template>
      </q-file>
    </div>
  </div>
</template>

禁用和只读



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-file
        disable
        filled
        v-model="model"
        hint="Disable"
        style="width: 250px"
      />

      <q-file
        readonly
        filled
        v-model="model"
        hint="Readonly"
        style="width: 250px"
      />

      <q-file
        disable
        readonly
        filled
        v-model="model"
        hint="Disable and readonly"
        style="width: 250px"
      />
    </div>
  </div>
</template>

用法

WARNING

在底层,QFile 使用原生 input 标签。由于浏览器安全策略,不允许以编程方式使用值填充此类输入。因此,即使您将 v-model 从开始设置为一个值,组件虽然也会显示这些文件,但 input 标签本身不会用该值填充。一定要用户主动交互(单击/点击/ 按下 ENTER/按下SPACE),原生 input 标签才能够包含被选中的文件。最好将 model 的初始值设置为 nullundefined/void 0

基础



<template>
  <div class="q-pa-md">
    <q-file
      v-model="file"
      label="Pick one file"
      filled
      style="max-width: 300px"
    />
  </div>
</template>



<template>
  <div class="q-pa-md">
    <q-file
      v-model="files"
      label="Pick files"
      filled
      multiple
      style="max-width: 300px"
    />
  </div>
</template>

追加文件

默认情况下,每次用户通过弹出窗口选择任何文件时, QFile 都会替换 model。但是,当您接受多个文件(multiple 属性)时,您可以更改此行为并将新选择的文件追加到模型中,而不是替换其旧值。

在下面,您可以多次选取文件,QFile 将继续将它们追加到 model 数据中:



<template>
  <div class="q-pa-md">
    <q-file
      v-model="files"
      label="Pick files"
      filled
      multiple
      append
      style="max-width: 300px"
    />
  </div>
</template>

计数器



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-file
        v-model="files"
        label="Pick files"
        filled
        counter
        multiple
        style="max-width: 300px"
      />

      <q-file
        v-model="files"
        label="Pick files"
        filled
        counter
        max-files="3"
        multiple
        style="max-width: 300px"
      />
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-file
        v-model="files"
        label="Pick files"
        filled
        counter
        :counter-label="counterLabelFn"
        max-files="3"
        multiple
        style="max-width: 300px"
      >
        <template v-slot:prepend>
          <q-icon name="attach_file" />
        </template>
      </q-file>
    </div>
  </div>
</template>

使用 chips



<template>
  <div class="q-pa-md">
    <q-file
      v-model="files"
      label="Pick files"
      outlined
      use-chips
      multiple
      style="max-width: 300px"
    />
  </div>
</template>

使用文件插槽

下面的示例重点介绍如何自定义每个文件的显示,甚至包括上传进度指示器:



<template>
  <div class="q-pa-md column items-start q-gutter-y-md">
    <q-file
      :model-value="files"
      @update:model-value="updateFiles"
      label="Pick files"
      outlined
      multiple
      :clearable="!isUploading"
      style="max-width: 400px"
    >
      <template v-slot:file="{ index, file }">
        <q-chip
          class="full-width q-my-xs"
          :removable="isUploading && uploadProgress[index].percent < 1"
          square
          @remove="cancelFile(index)"
        >
          <q-linear-progress
            class="absolute-full full-height"
            :value="uploadProgress[index].percent"
            :color="uploadProgress[index].color"
            track-color="grey-2"
          />

          <q-avatar>
            <q-icon :name="uploadProgress[index].icon" />
          </q-avatar>

          <div class="ellipsis relative-position">
            {{ file.name }}
          </div>

          <q-tooltip>
            {{ file.name }}
          </q-tooltip>
        </q-chip>
      </template>

      <template v-slot:after v-if="canUpload">
        <q-btn
          color="primary"
          dense
          icon="cloud_upload"
          round
          @click="upload"
          :disable="!canUpload"
          :loading="isUploading"
        />
      </template>
    </q-file>
  </div>
</template>

限制文件格式



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-file
        style="max-width: 300px"
        v-model="filesImages"
        filled
        rounded
        label="Restricted to images"
        multiple
        accept=".jpg, image/*"
        @rejected="onRejected"
      />

      <q-file
        style="max-width: 300px"
        v-model="filesMaxSize"
        outlined
        label="Max file size (2k)"
        multiple
        max-file-size="2048"
        @rejected="onRejected"
      />

      <q-file
        style="max-width: 300px"
        v-model="filesMaxTotalSize"
        standout
        label="Max total upload size (4k)"
        multiple
        max-total-size="4096"
        @rejected="onRejected"
      />

      <q-file
        style="max-width: 300px"
        v-model="filesMaxNumber"
        standout
        label="Max number of files (3)"
        multiple
        max-files="3"
        @rejected="onRejected"
      />
    </div>
  </div>
</template>

您甚至可以把上面的限制结合起来。

TIP

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

WARNING

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

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



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-file
        style="max-width: 300px"
        v-model="filesMaxSize"
        filled
        label="Filtered (for <2k size)"
        multiple
        :filter="checkFileSize"
        @rejected="onRejected"
      />

      <q-file
        style="max-width: 300px"
        v-model="filesPng"
        rounded
        outlined
        label="Filtered (png only)"
        multiple
        :filter="checkFileType"
        @rejected="onRejected"
      />
    </div>
  </div>
</template>

原生表单提交

当处理一个带有 actionmethod 的原生表单时(如:使用 Quasar 和 ASP.NET 控制器时),您需要为 QFile 声明 name 属性,否则表单数据中不会包含它:



<template>
  <div class="q-pa-md">
    <q-form @submit="onSubmit" class="q-gutter-md">
      <q-file
        name="poster_file"
        v-model="file"
        filled
        label="Select poster image"
      />

      <q-file
        name="cover_files"
        v-model="files"
        filled
        multiple
        use-chips
        label="Select cover images"
      />

      <div>
        <q-btn label="Submit" type="submit" color="primary"/>
      </div>
    </q-form>

    <q-card v-if="submitEmpty" flat bordered class="q-mt-md bg-grey-2">
      <q-card-section>
        Submitted form contains empty formData.
      </q-card-section>
    </q-card>
    <q-card v-else-if="submitResult.length > 0" flat bordered class="q-mt-md bg-grey-2">
      <q-card-section>Submitted form contains the following formData (key = value):</q-card-section>
      <q-separator />
      <q-card-section class="row q-gutter-sm items-center">
        <div
          v-for="(item, index) in submitResult"
          :key="index"
          class="q-px-sm q-py-xs bg-grey-8 text-white rounded-borders text-center text-no-wrap"
        >{{ item.name }} = {{ item.value }}</div>
      </q-card-section>
    </q-card>
  </div>
</template>

类型定义

export interface QRejectedEntry {
  failedPropValidation:
    | "accept"
    | "max-file-size"
    | "max-total-size"
    | "filter"
    | "max-files"
    | "duplicate";
  file: File;
}

export type QFileNativeElement = Omit<
  Omit<HTMLInputElement, "files"> & { files: FileList },
  "type"
> & { type: "file" };