Skip to content

Select 选择器

下拉选择器。

何时使用

  • 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。
  • 当选项少时(少于 5 项),建议直接将选项平铺,使用 Radio 是更好的选择。

基本使用

基本使用。

vue
<template>
  <g-select
    ref="select"
    v-model:value="value"
    style="width: 120px"
    @focus="focus"
    @blur="blur"
    @change="handleChange"
  >
    <g-select-option value="jack">Jack</g-select-option>
    <g-select-option value="lucy">Lucy</g-select-option>
    <g-select-option value="disabled" disabled>Disabled</g-select-option>
    <g-select-option value="Yiminghe">yiminghe</g-select-option>
  </g-select>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const value = ref('lucy')
    
    const focus = () => {
      console.log('focus')
    }
    
    const blur = () => {
      console.log('blur')
    }
    
    const handleChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    return {
      value,
      focus,
      blur,
      handleChange
    }
  }
}
</script>

带搜索框

展开后可对选项进行搜索。

vue
<template>
  <g-select
    show-search
    placeholder="Select a person"
    option-filter-prop="children"
    style="width: 200px"
    :filter-option="filterOption"
    @focus="onFocus"
    @blur="onBlur"
    @search="onSearch"
    @change="onChange"
  >
    <g-select-option value="jack">Jack</g-select-option>
    <g-select-option value="lucy">Lucy</g-select-option>
    <g-select-option value="tom">Tom</g-select-option>
  </g-select>
</template>

<script>
export default {
  setup() {
    const onFocus = () => {
      console.log('focus')
    }
    
    const onBlur = () => {
      console.log('blur')
    }
    
    const onSearch = (val) => {
      console.log('search:', val)
    }
    
    const onChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    const filterOption = (input, option) => {
      return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
    }
    
    return {
      onFocus,
      onBlur,
      onSearch,
      onChange,
      filterOption
    }
  }
}
</script>

多选

多选,从已有条目中选择。

vue
<template>
  <div>
    <g-select
      v-model:value="value1"
      mode="multiple"
      style="width: 100%"
      placeholder="select one country"
      :default-value="['china']"
      @change="handleChange"
    >
      <g-select-option v-for="i in children" :key="i.value" :value="i.value">
        {{ i.label }}
      </g-select-option>
    </g-select>
    <br />
    <g-select
      v-model:value="value2"
      mode="multiple"
      disabled
      style="width: 100%"
      placeholder="select one country"
      :default-value="['china']"
    >
      <g-select-option v-for="i in children" :key="i.value" :value="i.value">
        {{ i.label }}
      </g-select-option>
    </g-select>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const children = []
    for (let i = 10; i < 36; i++) {
      children.push({
        label: i.toString(36) + i,
        value: i.toString(36) + i,
      })
    }
    
    const value1 = ref(['china'])
    const value2 = ref(['china'])
    
    const handleChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    return {
      children,
      value1,
      value2,
      handleChange
    }
  }
}
</script>

标签

tags select,随意输入的内容(scroll the menu)

vue
<template>
  <g-select
    v-model:value="value"
    mode="tags"
    style="width: 100%"
    placeholder="Tags Mode"
    @change="handleChange"
  >
    <g-select-option v-for="i in children" :key="i.value" :value="i.value">
      {{ i.label }}
    </g-select-option>
  </g-select>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const children = []
    for (let i = 10; i < 36; i++) {
      children.push({
        label: i.toString(36) + i,
        value: i.toString(36) + i,
      })
    }
    
    const value = ref(['a10', 'c12'])
    
    const handleChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    return {
      children,
      value,
      handleChange
    }
  }
}
</script>

三种大小

三种大小的选择框,当 size 分别为 largesmall 时,输入框高度为 40px24px ,默认高度为 32px

vue
<template>
  <div>
    <g-radio-group v-model:value="size">
      <g-radio-button value="large">Large</g-radio-button>
      <g-radio-button value="default">Default</g-radio-button>
      <g-radio-button value="small">Small</g-radio-button>
    </g-radio-group>
    <br />
    <br />
    <g-select
      v-model:value="value1"
      :size="size"
      :default-value="'a1'"
      style="width: 200px"
      @change="handleChange"
    >
      <g-select-option v-for="i in children" :key="i.value" :value="i.value">
        {{ i.label }}
      </g-select-option>
    </g-select>
    <br />
    <g-select
      v-model:value="value2"
      mode="multiple"
      :size="size"
      placeholder="Please select"
      :default-value="['a10', 'c12']"
      style="width: 100%"
      @change="handleChange"
    >
      <g-select-option v-for="i in children" :key="i.value" :value="i.value">
        {{ i.label }}
      </g-select-option>
    </g-select>
    <br />
    <g-select
      v-model:value="value3"
      mode="tags"
      :size="size"
      placeholder="Please select"
      :default-value="['a10', 'c12']"
      style="width: 100%"
      @change="handleChange"
    >
      <g-select-option v-for="i in children" :key="i.value" :value="i.value">
        {{ i.label }}
      </g-select-option>
    </g-select>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const children = []
    for (let i = 10; i < 36; i++) {
      children.push({
        label: i.toString(36) + i,
        value: i.toString(36) + i,
      })
    }
    
    const size = ref('default')
    const value1 = ref('a1')
    const value2 = ref(['a10', 'c12'])
    const value3 = ref(['a10', 'c12'])
    
    const handleChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    return {
      children,
      size,
      value1,
      value2,
      value3,
      handleChange
    }
  }
}
</script>

自定义下拉选项

也可以直接传 Array<{value, label}> 类型的数据。

vue
<template>
  <g-select
    v-model:value="value"
    style="width: 200px"
    :options="options"
    @focus="onFocus"
    @blur="onBlur"
    @change="onChange"
  />
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const value = ref('lucy')
    const options = ref([
      {
        value: 'jack',
        label: 'Jack',
      },
      {
        value: 'lucy',
        label: 'Lucy',
      },
      {
        value: 'tom',
        label: 'Tom',
      },
    ])
    
    const onFocus = () => {
      console.log('focus')
    }
    
    const onBlur = () => {
      console.log('blur')
    }
    
    const onChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    return {
      value,
      options,
      onFocus,
      onBlur,
      onChange
    }
  }
}
</script>

联动

省市联动是典型的例子。

推荐使用 Cascader 组件。

vue
<template>
  <div>
    <g-select
      v-model:value="provinceData[0]"
      style="width: 120px"
      @change="handleProvinceChange"
    >
      <g-select-option v-for="province in provinceData" :key="province" :value="province">
        {{ province }}
      </g-select-option>
    </g-select>
    <g-select
      v-model:value="secondCity"
      style="width: 120px"
      :disabled="!provinceData[0]"
    >
      <g-select-option v-for="city in cityData[provinceData[0]]" :key="city" :value="city">
        {{ city }}
      </g-select-option>
    </g-select>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const provinceData = ['Zhejiang', 'Jiangsu']
    const cityData = {
      Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
      Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang'],
    }
    
    const secondCity = ref(cityData[provinceData[0]][0])
    
    const handleProvinceChange = (value) => {
      secondCity.value = cityData[value][0]
    }
    
    return {
      provinceData,
      cityData,
      secondCity,
      handleProvinceChange
    }
  }
}
</script>

获得选项的文本

默认情况下 onChange 里只能拿到 value,如果需要拿到选中的节点文本 label,可以使用 labelInValue 属性。

选中项的 label 会被包装到 value 中传递给 onChange 等函数,此时 value 是一个对象。

vue
<template>
  <g-select
    v-model:value="value"
    label-in-value
    :default-value="{ value: 'lucy', label: 'Lucy (101)' }"
    style="width: 120px"
    @change="handleChange"
  >
    <g-select-option value="jack">Jack (100)</g-select-option>
    <g-select-option value="lucy">Lucy (101)</g-select-option>
  </g-select>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const value = ref({ value: 'lucy', label: 'Lucy (101)' })
    
    const handleChange = (value) => {
      console.log(value) // { value: "lucy", label: "Lucy (101)" }
    }
    
    return {
      value,
      handleChange
    }
  }
}
</script>

自动分词

试下复制 露西,杰克 到输入框里。只在 tags 和 multiple 模式下可用。

vue
<template>
  <g-select
    v-model:value="value"
    mode="tags"
    style="width: 100%"
    :token-separators="[',']"
    @change="handleChange"
  >
    <g-select-option v-for="i in children" :key="i.value" :value="i.value">
      {{ i.label }}
    </g-select-option>
  </g-select>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const children = [
      { label: 'jack', value: 'jack' },
      { label: 'lucy', value: 'lucy' },
    ]
    
    const value = ref(['lucy'])
    
    const handleChange = (value) => {
      console.log(`selected ${value}`)
    }
    
    return {
      children,
      value,
      handleChange
    }
  }
}
</script>

远程搜索

搜索和远程数据结合。

vue
<template>
  <g-select
    v-model:value="value"
    show-search
    :value="value"
    placeholder="Select users"
    style="width: 100%"
    :default-active-first-option="false"
    :show-arrow="false"
    :filter-option="false"
    :not-found-content="null"
    @search="handleSearch"
    @change="handleChange"
  >
    <g-select-option v-for="d in data" :key="d.value" :value="d.value">
      {{ d.text }}
    </g-select-option>
  </g-select>
</template>

<script>
import { ref } from 'vue'
import jsonp from 'fetch-jsonp'
import querystring from 'querystring'

let timeout
let currentValue

function fetch(value, callback) {
  if (timeout) {
    clearTimeout(timeout)
    timeout = null
  }
  currentValue = value

  function fake() {
    const str = querystring.encode({
      code: 'utf-8',
      q: value,
    })
    jsonp(`https://suggest.taobao.com/sug?${str}`)
      .then(response => response.json())
      .then(d => {
        if (currentValue === value) {
          const { result } = d
          const data = []
          result.forEach(r => {
            data.push({
              value: r[0],
              text: r[0],
            })
          })
          callback(data)
        }
      })
  }

  timeout = setTimeout(fake, 300)
}

export default {
  setup() {
    const data = ref([])
    const value = ref()
    
    const handleSearch = (val) => {
      fetch(val, (data) => {
        data.value = data
      })
    }
    
    const handleChange = (val) => {
      value.value = val
    }
    
    return {
      data,
      value,
      handleSearch,
      handleChange
    }
  }
}
</script>

隐藏已选择选项

隐藏下拉列表中已选择的选项。

vue
<template>
  <g-select
    v-model:value="selectedItems"
    mode="multiple"
    placeholder="Inserted are removed"
    style="width: 100%"
    @change="handleChange"
  >
    <g-select-option
      v-for="item in filteredOptions"
      :key="item"
      :value="item"
    >
      {{ item }}
    </g-select-option>
  </g-select>
</template>

<script>
import { ref, computed } from 'vue'

export default {
  setup() {
    const OPTIONS = ['Apples', 'Nails', 'Bananas', 'Helicopters']
    const selectedItems = ref([])
    
    const filteredOptions = computed(() => 
      OPTIONS.filter(o => !selectedItems.value.includes(o))
    )
    
    const handleChange = (value) => {
      selectedItems.value = value
    }
    
    return {
      selectedItems,
      filteredOptions,
      handleChange
    }
  }
}
</script>

API

Select props

参数说明类型默认值版本
allowClear支持清除booleanfalse
autoClearSearchValue是否在选中项后清空搜索框,只在 modemultipletags 时有效。booleantrue
autoFocus默认获取焦点booleanfalse
bordered是否有边框booleantrue
clearIcon自定义的多选框清空图标VNode | slot-
defaultActiveFirstOption是否默认高亮第一个选项。booleantrue
defaultOpen是否默认展开下拉菜单boolean-
disabled是否禁用booleanfalse
dropdownClassName下拉菜单的 className 属性string-
dropdownMatchSelectWidth下拉菜单和选择器同宽。默认将设置 min-width,当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动boolean | numbertrue
dropdownRender自定义下拉框内容({menuNode: VNode, props}) => VNode | v-slot-
dropdownStyle下拉菜单的 style 属性object-
fieldNames自定义节点 label、value、options 的字段object{ label: label, value: value, options: options }3.0.0
filterOption是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 falseboolean or function(inputValue, option)true
firstActiveValue默认高亮的选项string | string[]-
getPopupContainer菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。Function(triggerNode)() => document.body
labelInValue是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 string 变为 {key: string, label: vNodes} 的格式booleanfalse
listHeight设置弹窗滚动高度number256
loading加载中状态Booleanfalse
maxTagCount最多显示多少个 tagnumber-
maxTagPlaceholder隐藏 tag 时显示的内容slot/function(omittedValues)-
maxTagTextLength最大显示的 tag 文本长度number-
menuItemSelectedIcon自定义当前选中的条目图标VNode | slot-
mode设置 Select 的模式为多选或标签'multiple' | 'tags'-
notFoundContent当下拉列表为空时显示的内容string | slot'Not Found'
open是否展开下拉菜单boolean-
option通过 option 插槽,自定义节点v-slot:option="{value, label, [disabled, key, title]}"-2.2.5
optionFilterProp搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索。若通过 options 属性配置选项内容,建议设置 optionFilterProp="label" 来对内容进行搜索。stringvalue
optionLabelProp回填到选择框的 Option 的属性值,默认是 Option 的子元素。比如在子元素需要高亮效果时,此值可以设为 valuestringchildren (combobox 模式下为 value
optionsoptions 数据,如果设置则不需要手动构造 selectOption 节点array<{value, label, [disabled, key, title]}>[]
placeholder选择框默认文字string | slot-
removeIcon自定义的多选框清除图标VNode | slot-
searchValue控制搜索文本string-
showArrow是否显示下拉小箭头booleantrue
showSearch使单选模式可搜索booleanfalse
size选择框大小,可选 large smallstringdefault
suffixIcon自定义的选择框后缀图标VNode | slot-
tagRender自定义 tag 内容 renderslot | (props) => any-
tokenSeparators在 tags 和 multiple 模式下自动分词的分隔符string[]-
value(v-model)指定当前选中的条目string|string[]|number|number[]-
virtual设置 false 时关闭虚拟滚动booleantrue3.0

Select 事件

事件名称说明回调参数
blur失去焦点的时回调function
change选中 option,或 input 的 value 变化(combobox 模式下)时,调用此函数function(value, option:Option/Array<Option>)
deselect取消选中时调用,参数为选中项的 value (或 key) 值,仅在 multiple 或 tags 模式下生效function(value,option:Option)
dropdownVisibleChange展开下拉菜单的回调function(open)
focus获得焦点时回调function
inputKeyDown按键按下时回调function
mouseenter鼠标移入时回调function
mouseleave鼠标移出时回调function
popupScroll下拉列表滚动时的回调function
search文本框值变化时回调function(value: string)
select被选中时调用,参数为选中项的 value (或 key) 值function(value, option:Option)

Select Methods

名称说明
blur()取消焦点
focus()获取焦点

Option props

参数说明类型默认值
disabled是否禁用booleanfalse
key和 value 含义一致。如果 Vue 需要你设置此项,此项值与 value 的值相同,然后可以省略 value 设置string-
title选中该 Option 后,Select 的 titlestring-
value默认根据此属性值进行筛选string|number-

OptGroup props

参数说明类型默认值
keyKeystring-
label组名string|function(h)|slot

Released under the MIT License.