选择框

QSelect 组件有两种类型的选择框:单选和多选。这个组件可以打开一组可操作的菜单列表。对于较长的列表还可以选择过滤功能。

如果您在找一个下拉按钮而不是输入框,那么使用请使用下拉按钮

QSelect API

QSelect API


name
: String
说明
用于指定控件的名称;在处理表单时非常有用;如果未指定,则使用 'for' 属性的值,如果存在的话。
virtual-scroll-horizontal
: Boolean
说明
使虚拟列表在水平模式下工作
error
: Boolean | null
说明
字段是否有验证错误?
rules
: Array
说明
函数/字符串数组;如果是字符串,则必须是内置验证规则之一的名称
reactive-rules
: Boolean
说明
默认情况下,规则的更改不会触发新的验证,直到模型发生变化;如果设置为 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' 属性,则同样用于此属性。
hide-dropdown-icon
: Boolean
说明
隐藏下拉图标
popup-no-route-dismiss
: Boolean
v2.15+
说明
更改路由应用程序不会关闭弹出窗口(菜单或对话框)
fill-input
: Boolean
说明
用当前值填充输入框;与 'hide-selected' 一起使用效果更佳;不适用于 'multiple' 多选。
new-value-mode
: String
说明
启用创建新值并定义添加新值时的行为:'add' 表示添加该值(即使可能重复),'add-unique' 仅添加唯一值,而 'toggle' 则根据该值是否已存在来添加或删除该值;当使用此属性时,监听 @new-value 变得可选(只是为了覆盖由 'new-value-mode' 定义的行为)。
autocomplete
: String
说明
字段的自动完成属性
transition-show
: String
说明
显示菜单/对话框时的过渡效果;Quasar 内置的过渡效果之一
transition-hide
: String
说明
隐藏菜单/对话框时的过渡效果;Quasar 内置的过渡效果之一
transition-duration
: String | Number
说明
隐藏菜单/对话框时的过渡持续时间(以毫秒为单位,无单位)
behavior
: String
说明
在桌面上覆盖默认的动态模式,以菜单形式显示,在移动设备上以对话框形式显示

外观设计

Overview

WARNING

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



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

      <q-select filled v-model="model" :options="options" label="Filled" />

      <q-select outlined v-model="model" :options="options" label="Outlined" />

      <q-select standout v-model="model" :options="options" label="Standout" />

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

      <q-select borderless v-model="model" :options="options" label="Borderless" />

      <q-select rounded filled v-model="model" :options="options" label="Rounded filled" />

      <q-select rounded outlined v-model="model" :options="options" label="Rounded outlined" />

      <q-select rounded standout v-model="model" :options="options" label="Rounded standout" />

      <q-select square filled v-model="model" :options="options" label="Square filled" />

      <q-select square outlined v-model="model" :options="options" label="Square outlined" />

      <q-select square standout v-model="model" :options="options" label="Square standout" />
    </div>
  </div>
</template>

装饰



<template>
  <div class="q-pa-md">
    <div class="q-pb-lg">
      <q-toggle v-model="dense" label="Dense QSelect" />
      <q-toggle v-model="denseOpts" label="Dense options" />
    </div>

    <div class="q-gutter-md" style="max-width: 300px">
      <q-select filled v-model="model" :options="options" label="Label (stacked)" stack-label :dense="dense" :options-dense="denseOpts" />

      <q-select outlined v-model="model" :options="options" :dense="dense" :options-dense="denseOpts">
        <template v-slot:prepend>
          <q-icon name="event" />
        </template>
      </q-select>

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

      <q-select filled bottom-slots v-model="model" :options="options" label="Label" counter :dense="dense" :options-dense="denseOpts">
        <template v-slot:prepend>
          <q-icon name="place" @click.stop />
        </template>
        <template v-slot:append>
          <q-icon name="close" @click.stop="model = ''" class="cursor-pointer" />
        </template>

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

      <q-select rounded outlined bottom-slots v-model="model" :options="options" label="Label" counter maxlength="12" :dense="dense" :options-dense="denseOpts">
        <template v-slot:before>
          <q-icon name="flight_takeoff" />
        </template>

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

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

      <q-select filled bottom-slots v-model="model" :options="options" label="Label" counter maxlength="12" :dense="dense" :options-dense="denseOpts">
        <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 !== ''" name="close" @click.stop="model = ''" class="cursor-pointer" />
          <q-icon name="schedule" @click.stop />
        </template>

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

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

      <q-select filled bottom-slots v-model="model" :options="options" label="Label" counter maxlength="12" :dense="dense" :options-dense="denseOpts">
        <template v-slot:before>
          <q-icon name="event" />
        </template>

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

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

Dense QSelect
Dense options

着色



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

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

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

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

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

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

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

可清除的

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



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

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

禁用和只读



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

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

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

插槽中使用 “submit” 类型的 QBtn

WARNING

当将类型为 “submit” 的 QBtn 放置在 QField、QInput 或 QSelect 的 “before”、“after” 、“prepend” 或 “append” 插槽中时,您还应该在有问题的 QBtn 上添加 @click 事件。该事件应调用提交表单的方法。此类插槽中的所有点击事件均不会传播到其父元素。

菜单过渡动画

WARNING

请注意,当使用选项 options-cover 属性时,过渡效果不生效。

在下面的示例中,显示部分过渡效果。有关可用过渡效果的完整列表,请转到 过渡效果页面。



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        label="Flip up/down"
        transition-show="flip-up"
        transition-hide="flip-down"
        filled
        v-model="model"
        :options="options"
        style="width: 250px"
      />

      <q-select
        label="Scale"
        transition-show="scale"
        transition-hide="scale"
        filled
        v-model="model"
        :options="options"
        style="width: 250px"
      />

      <q-select
        label="Jump up"
        transition-show="jump-up"
        transition-hide="jump-up"
        filled
        v-model="model"
        :options="options"
        style="width: 250px"
      />
    </div>
  </div>
</template>

选项列表的展示模式

默认情况下,QSelect 在桌面上使用菜单的方式展示选项列表,在手机上使用对话框展示选项列表。但是您可以使用 behavior 来强制控制使用某种模式。

WARNING

请注意,在 iOS 上,菜单模式可能会产生问题,尤其是与 use-input 属性结合使用时。您可以控制在 IOS 设备上只是用对话框模式,例如::behavior="$q.platform.is.ios === true ? 'dialog' : 'menu'"



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        label="Simple select"
        :options="stringOptions"
        style="width: 250px"
        behavior="menu"
      />

      <q-select
        filled
        v-model="model"
        use-input
        input-debounce="0"
        label="Simple filter"
        :options="options"
        @filter="filterFn"
        style="width: 250px"
        behavior="menu"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        label="Simple select"
        :options="stringOptions"
        style="width: 250px"
        behavior="dialog"
      />

      <q-select
        filled
        v-model="model"
        use-input
        input-debounce="0"
        label="Simple filter"
        :options="options"
        @filter="filterFn"
        style="width: 250px"
        behavior="dialog"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

The model

WARNING

model 在单选模式下可以是任意类型(String, Object, …),但是在多选模式下只能是一个数组。



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-select
        filled
        v-model="single"
        :options="options"
        label="Single"
        style="width: 250px"
      />

      <q-select
        filled
        v-model="multiple"
        multiple
        :options="options"
        label="Multiple"
        style="width: 250px"
      />
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-select
        filled
        v-model="model"
        multiple
        :options="options"
        counter
        hint="With counter"
        style="width: 250px"
      />

      <q-select
        filled
        v-model="model2"
        multiple
        :options="options"
        counter
        max-values="2"
        hint="Max 2 selections"
        style="width: 250px"
      />
    </div>
  </div>
</template>

model 的内容可能会受到 emit-value 属性的影响,您将在下面的 “选项” 部分中学习。

选项

选项类型



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select filled v-model="model" :options="options" label="Standard" />
    </div>
  </div>
</template>

Model: ""


<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select filled v-model="model" :options="options" label="Standard" />
    </div>
  </div>
</template>

Model: ""

Affecting model

当使用 emit-value 时,model 会明确的绑定到选项中的 value 属性上,而不是整个对象。只有当选项是对象类型时才有意义。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select
        filled
        v-model="model"
        :options="options"
        label="Standard"
        emit-value
      />
    </div>
  </div>
</template>

Model: ""

当使用 map-options 时,model 可以只包含 value,并且他会根据选项进行映射以确定其 label。这涉及到性能损失,所以只有在绝对必要的情况下才使用它。例如,如果 model 包含整个 Object (因此包含 label 属性) ,就不需要它。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select
        filled
        v-model="model"
        :options="options"
        label="Standard"
        emit-value
        map-options
      />
    </div>
  </div>
</template>

Model: ""

自定义属性名

默认情况下,QSelect 会寻找并使用每个选项中的 label, value, disablesanitize 属性,但是您也可以重写它们:

WARNING

如果您将函数用于自定义 props,请始终检查该选项是否为 null。这些函数既用于列表中的选项,也用于选定的选项。



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <div class="col-12">
        <q-badge color="secondary" multi-line>
          Model: "{{ model }}"
        </q-badge>
      </div>

      <q-select
        filled
        v-model="model"
        :options="options"
        option-value="id"
        option-label="desc"
        option-disable="inactive"
        emit-value
        map-options
        style="min-width: 250px; max-width: 300px"
      />

      <q-select
        filled
        v-model="model"
        :options="options"
        :option-value="opt => Object(opt) === opt && 'id' in opt ? opt.id : null"
        :option-label="opt => Object(opt) === opt && 'desc' in opt ? opt.desc : '- Null -'"
        :option-disable="opt => Object(opt) === opt ? opt.inactive === true : true"
        emit-value
        map-options
        style="min-width: 250px; max-width: 300px"
      />
    </div>
  </div>
</template>

Model: ""

自定义菜单选项

WARNING

使用虚拟滚动渲染选项列表,因此,如果您为一个选项渲染多个元素,则必须在所有元素上设置 q-virtual-scroll--with-prev CSS 类,除了第一个元素。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select
        filled
        v-model="model"
        :options="options"
        label="Standard"
        color="teal"
        clearable
        options-selected-class="text-deep-orange"
      >
        <template v-slot:option="scope">
          <q-item v-bind="scope.itemProps">
            <q-item-section avatar>
              <q-icon :name="scope.opt.icon" />
            </q-item-section>
            <q-item-section>
              <q-item-label>{{ scope.opt.label }}</q-item-label>
              <q-item-label caption>{{ scope.opt.description }}</q-item-label>
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

Model: ""

这里是另一个例子,我们为每个选项添加一个 QToggle 。可能性是无穷的。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select
          filled
          v-model="model"
          :options="options"
          label="Multi with toggle"
          multiple
          emit-value
          map-options
      >
        <template v-slot:option="{ itemProps, opt, selected, toggleOption }">
          <q-item v-bind="itemProps">
            <q-item-section>
              <q-item-label v-html="opt.label" />
            </q-item-section>
            <q-item-section side>
              <q-toggle :model-value="selected" @update:model-value="toggleOption(opt)" />
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

Model: "[]"

默认情况下,如果没有选项,则不会出现菜单。但是您可以自定义此情况并指定菜单应显示的内容。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-select
        filled
        v-model="model"
        :options="options"
        label="No options"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-italic text-grey">
              No options slot
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

懒加载

下面的示例展示了如何使用懒加载选项。这意味着,第一次渲染时不需要 options 属性。



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <q-select
        filled
        v-model="model"
        use-chips
        label="Lazy load opts"
        :options="options"
        @filter="filterFn"
        @filter-abort="abortFilterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>

      <q-btn
        v-if="options"
        label="Reset"
        color="primary"
        @click="options = null"
      />
    </div>
  </div>
</template>

当滚动到达终点时,您可以动态加载新选项:



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <q-select
      filled
      v-model="model"
      multiple
      :options="options"
      :loading="loading"
      @virtual-scroll="onScroll"
    />
  </div>
</template>

覆盖模式



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-select
        filled
        v-model="model"
        :options="options"
        options-cover
        stack-label
        label="Standard"
      />
    </div>
  </div>
</template>

展示的值



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select
        filled
        v-model="model"
        :options="options"
        stack-label
        label="Standard"
        :display-value="`Company: ${model ? model : '*none*'}`"
      >
        <template v-slot:append>
          <q-icon
            v-if="model !== null"
            class="cursor-pointer"
            name="clear"
            @click.stop="model = null"
          />
        </template>
      </q-select>
    </div>
  </div>
</template>

Model: "Twitter"


<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row items-start">
      <div style="min-width: 250px; max-width: 300px">
        <q-badge color="secondary" class="q-mb-md">
          Model: {{ modelSingle || '*none*' }}
        </q-badge>

        <q-select
          filled
          v-model="modelSingle"
          :options="options"
          use-chips
          stack-label
          label="Single selection"
        />
      </div>

      <div style="min-width: 250px; max-width: 300px">
        <q-badge color="secondary" class="q-mb-md">
          Model: {{ modelMultiple || '[]' }}
        </q-badge>

        <q-select
          filled
          v-model="modelMultiple"
          multiple
          :options="options"
          use-chips
          stack-label
          label="Multiple selection"
        />
      </div>
    </div>
  </div>
</template>

Model: Apple
Model: [ "Facebook" ]


<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>

      <q-select
        filled
        v-model="model"
        :options="options"
        stack-label
        label="Standard"
      >
        <template v-slot:selected>
          Company:
          <q-chip
            v-if="model"
            dense
            square
            color="white"
            text-color="primary"
            class="q-my-none q-ml-xs q-mr-none"
          >
            <q-avatar color="primary" text-color="white" :icon="model.icon" />
            {{ model.label }}
          </q-chip>
          <q-badge v-else>*none*</q-badge>
        </template>
      </q-select>

      <q-select
        filled
        v-model="model"
        :options="options"
        stack-label
        label="Standard"
        color="secondary"
      >
        <template v-slot:selected-item="scope">
          <q-chip
            removable
            dense
            @remove="scope.removeAtIndex(scope.index)"
            :tabindex="scope.tabindex"
            color="white"
            text-color="secondary"
            class="q-ma-none"
          >
            <q-avatar color="secondary" text-color="white" :icon="scope.opt.icon" />
            {{ scope.opt.label }}
          </q-chip>
        </template>
      </q-select>
    </div>
  </div>
</template>

Model: "{ "label": "Google", "value": "goog", "icon": "mail" }"

过滤和自动补全

use-input 和原生属性

所有给 QSelect 设置的属性,如果未在 API 卡片中的 props 部分列出,那么它将会被传递给底层的原生input 标签(请先检查 use-input 属性描述以了解它的作用)以完成过滤/指定补全/添加新选项。例如: autocomplete,placeholder。

更多信息: native input attributes.



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        use-input
        input-debounce="0"
        label="Simple filter"
        :options="options"
        @filter="filterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>

      <q-select
        filled
        v-model="model"
        use-input
        hide-selected
        input-debounce="0"
        label="Hide selected"
        :options="options"
        @filter="filterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        :options="options"
        @filter="filterFn"
        hint="Basic filtering"
        style="width: 250px; padding-bottom: 32px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        :options="options"
        @filter="filterFn"
        hint="Minimum 2 characters to trigger filtering"
        style="width: 250px; padding-bottom: 32px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        :model-value="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        :options="options"
        @filter="filterFn"
        @input-value="setModel"
        hint="Text autocomplete"
        style="width: 250px; padding-bottom: 32px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md">
      <q-select
        filled
        v-model="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        label="Lazy filter"
        :options="options"
        @filter="filterFn"
        @filter-abort="abortFilterFn"
        style="width: 250px"
        hint="With hide-selected and fill-input"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>

      <q-select
        filled
        v-model="model"
        use-input
        use-chips
        input-debounce="0"
        label="Lazy filter"
        :options="options"
        @filter="filterFn"
        @filter-abort="abortFilterFn"
        style="width: 250px"
        hint="With use-chips"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>



<template>
  <div class="q-pa-md">
    <div class="q-gutter-md">
      <q-select
        filled
        v-model="model"
        clearable
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        label="Focus after filtering"
        :options="options"
        @filter="filterFn"
        @filter-abort="abortFilterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>

      <q-select
        filled
        v-model="model"
        clearable
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        label="Autoselect after filtering"
        :options="options"
        @filter="filterFnAutoselect"
        @filter-abort="abortFilterFn"
        style="width: 250px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>

创建新的值

TIP

以下只是一些示例,帮助您开始创建自己的 QSelect。这不是 QSelect 可以提供的全部可能性。 将此功能与 use-input 属性一起使用是很有意义的。

为了创建新的值,您可以使用new-value-mode 属性,或者监听 @new-value 事件,如果您同时使用两者,那么在您的自定义场景中,@new-value 事件应该只用于覆盖 new-value-mode

new-value-mode 属性

new-value-mode 属性指定创建的新值应该怎么样被添加到数据中,可以有以下三种取值:

  1. add 即使数据中已经存在了相同的值仍然添加;
  2. add-unique 不会添加重复数据;
  3. toggle 如果数据中之前没有此数据那么添加它,否则将其删除。

使用这个属性时不必监听 @new-value 事件,除非您有特殊的场景需要重写它的行为。



<template>
  <div class="q-pa-md">
    <div class="q-gutter-y-md">
      <q-select
        label="Mode: 'add'"
        filled
        v-model="modelAdd"
        use-input
        use-chips
        multiple
        hide-dropdown-icon
        input-debounce="0"
        new-value-mode="add"
        style="width: 250px"
      />

      <q-select
        label="Mode: 'add-unique'"
        filled
        v-model="modelAddUnique"
        use-input
        use-chips
        multiple
        hide-dropdown-icon
        input-debounce="0"
        new-value-mode="add-unique"
        style="width: 250px"
      />

      <q-select
        label="Mode: 'toggle'"
        filled
        v-model="modelToggle"
        use-input
        use-chips
        multiple
        hide-dropdown-icon
        input-debounce="0"
        new-value-mode="toggle"
        style="width: 250px"
      />
    </div>
  </div>
</template>

@new-value 事件

@new-value 事件中带有被添加的新数据和一个 done 回调函数。done 函数有两个可选的参数:

  • 被添加的数据
  • 添加数据的行为(与 new-value-mode 可设置的值一样,并且会覆盖它)
    • 默认行为(如果未设置 new-value-mode 的话)是即使数据中已经有重复的数据也会添加

不带参数调用 done() 只会清空输入框的值,而不会以任何方式修改 model。



<template>
  <div class="q-pa-md">
    <q-select
      label="Allows duplicates"
      filled
      v-model="model"
      use-input
      use-chips
      multiple
      hide-dropdown-icon
      input-debounce="0"
      @new-value="createValue"
      style="width: 250px"
    />
  </div>
</template>



<template>
  <div class="q-pa-md">
    <q-select
      label="Unique values only"
      filled
      v-model="model"
      use-input
      use-chips
      multiple
      hide-dropdown-icon
      input-debounce="0"
      @new-value="createValue"
      style="width: 250px"
    />
  </div>
</template>

使用菜单和过滤

过滤和给菜单中添加新的值一起使用:



<template>
  <div class="q-pa-md">
    <q-select
      filled
      v-model="model"
      use-input
      use-chips
      multiple
      input-debounce="0"
      @new-value="createValue"
      :options="filterOptions"
      @filter="filterFn"
      style="width: 250px"
    />
  </div>
</template>

过滤但不给菜单添加新的值(下面三个示例中,要添加的值至少需要 3 个字符才能通过):



<template>
  <div class="q-pa-md">
    <q-select
      filled
      v-model="model"
      use-input
      use-chips
      multiple
      input-debounce="0"
      @new-value="createValue"
      :options="filterOptions"
      @filter="filterFn"
      style="width: 250px"
    />
  </div>
</template>

从输入生成多个值:



<template>
  <div class="q-pa-md">
    <q-select
      filled
      label="Select multiple values"
      hint="Separate multiple values by [,;|]"
      v-model="model"
      use-input
      use-chips
      multiple
      input-debounce="0"
      @new-value="createValue"
      :options="filterOptions"
      @filter="filterFn"
      style="width: 250px"
    />
  </div>
</template>

安全处理

默认情况下,所有选项(包括选定的选项)都是经过安全处理的。这意味着以 HTML 格式显示它们是无效的。然而,如果您需要在您的选项上显示 HTML,并且您信任它们的内容,那么有几种方法可以做到这一点。

您可以通过以下方式强制使用菜单选项的 HTML 形式:

  • 将受信任的选项的 html 键设置为 true(用于特定的受信任的选项生效)
  • 或通过设置 QSelect 的 options-html 属性(对于所有选项生效)

QSelect 的显示值会以 HTML 形式显示,如果:

  • 设置了 QSelect 的 display-value-html属性
  • 或者您不使用 display-value
    • 设置了 QSelect 的 options-html 属性
    • 所有被选定的选项的 html 键都被设置为 true

WARNING

如果您使用了 selectedselected-item 插槽,那么您需要自行对展示的值进行安全处理。display-value-html 属性不会被应用。



<template>
  <div class="q-pa-md" style="max-width: 300px">
    <q-badge color="secondary" multi-line class="q-mb-md">
      Model: {{ model || 'empty' }}
    </q-badge>

    <div class="q-gutter-md">
      <q-toggle v-model="optionsHtml" label="Options in HTML form" />

      <q-select filled v-model="model" :options="options" label="Standard" :options-html="optionsHtml" />
    </div>
  </div>
</template>

Model: empty
Options in HTML form


<template>
  <div class="q-pa-md" style="max-width: 300px">
    <q-badge color="secondary" multi-line class="q-mb-md">
      Model: {{ model || 'empty' }}
    </q-badge>

    <div class="q-gutter-md">
      <q-toggle v-model="displayHtml" label="Display value in HTML form" />

      <q-select
        filled
        v-model="model"
        :options="options"
        stack-label
        label="Standard"
        :display-value="`Company: ${model ? model.label : '*none*'}`"
        :display-value-html="displayHtml"
      >
        <template v-slot:append>
          <q-icon
            v-if="model !== null"
            class="cursor-pointer"
            name="clear"
            @click.stop="model = null"
          />
        </template>
      </q-select>
    </div>
  </div>
</template>

Model: { "label": "<span class=\"text-primary\">G</span>oogle", "value": "Google" }
Display value in HTML form

渲染性能

渲染性能不会受到选项数量的影响,除非在大的集合中使用 map-options。请注意,当用户在列表中滚动时,虚拟无限滚动将渲染其他选项。

TIP

  • (Composition API) 为了在使用大量选项时获得最佳性能,不要用 ref()/computed()/reactive()/etc来包裹您传递给 options 属性中的数组。这允许 Vue 跳过对列表进行响应式改变。
  • (Options API) 为了在使用大量选项的同时获得最佳性能,请使用 Object.freeze(items) 冻结您传递给 options 属性中的数组。这允许 Vue 跳过对列表进行响应式改变。


<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-select
        filled
        v-model="model"
        multiple
        :options="options"
      />
    </div>
  </div>
</template>

键盘导航

当 QSelect 聚焦时:

  • 按下 ENTER, ARROW DOWN (或者 SPACE 如果没有设置 use-input的话) 将会打开选项列表。
  • 如果设置了 use-chips
    • 按下 SHIFT + TAB 将在 QChips 中向后导航 (如果选择了一个 QChip TAB 键将会在 QChips 中向前导航)
    • 当一个 QChip 被选中时,按下 ENTER 会取消选中该选项。
    • 按下 BACKSPACE 会删除选中列表中的最后一个(如果设置了 use-input 输入应该为空)
  • 按下 TAB 将导航至下一个或页面上的上一个可聚焦元素(如果未设置 use-chips 或选择了第一个 QChip,则按 SHIFT + TAB
  • 如果未设置 use-input,则输入文字(0 - 9 or A - Z)将会:
    • 创建一个搜索缓冲区(当在 1.5 秒内未输入新键时将重置),该缓冲区将用于在选项标签中进行搜索
    • 如果多次输入缓冲区中的第一个键,则选择以该字母开头的下一个选项(在当前焦点之后)
    • 选择与键入的文本匹配的下一个选项(从当前的焦点开始)(匹配是模糊的-选项标签应以第一个字母开头并包含所有字母)

当选项列表打开时:

  • 按下 ARROW UPARROW DOWN将在选项列表中向上或向下导航
  • 按下 PAGE UPPAGE DOWN 将在选项列表中向上或向下导航一页
  • 按下 HOMEEND 将导航到选项列表的开头或结尾(仅当您未使用 use-input 或输入为空时)
  • 使用箭头键进行导航时,导航将在到达列表的开头或结尾时结束
  • 选项在列表中被选中时按下 ENTER (如果未设置 use-input,则按 SPACE;如果未设置 multiple,则按 TAB)将会:
    • 选择选项,并且如果未设置 multiple 则关闭选项列表。
    • 如果设置了 multiple,则切换选项。

原生表单提交

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



<template>
  <div class="q-pa-md">
    <q-form @submit="onSubmit" class="q-gutter-md">
      <q-select
        name="preferred_genre"
        v-model="preferred"
        :options="options"
        color="primary"
        filled
        clearable
        label="Preferred genre"
      />

      <q-select
        name="accepted_genres"
        v-model="accepted"
        multiple
        :options="options"
        color="primary"
        filled
        clearable
        label="Accepted genres"
      />

      <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 type QSelectOption<T = string> = {
  label: string;
  value: T;
};