Skip to content

Select 选择器

当选项过多时,使用下拉菜单展示并选择内容,支持搜索过滤和远程加载。

基础用法

适用广泛的基础单选 v-model 的值为当前被选中的 option 的 value 属性值。

<script setup>
import { ref } from 'vue'
import Select from '@/components/Select/Select.vue'
const test = ref('')
const options2 = [
  { label: 'hello', value: '1' },
  { label: 'xyz', value: '2' },
  { label: 'testing', value: '3' },
  { label: 'check', value: '4', disabled: true }
]
</script>
<template>
  <Select v-model="test" placeholder="基础选择器,请选择" :options="options2" clearable filterable multiple collapseTags/>
  <span>{{test}}</span>
</template>

自定义选项渲染

通过 renderLabel 属性传入渲染函数,可以自定义选项内容的展示样式,使用 VNode 灵活渲染。

<script setup>
import { h, ref } from 'vue'
import Select from "@/components/Select/Select.vue"
const test = ref('')
const options2 = [
  {label: 'hello', value: '1'},
  {label: 'xyz', value: '2'},
  {label: 'testing', value: '3'},
  {label: 'check', value: '4', disabled: true},
]

const customRender = (option) => {
  return h('div', { className: 'xyz' }, [h('b', option.label), h('span', option.value)])
}
</script>

<template>
  <Select v-model="test" placeholder="基础选择器,请选择" :options="options2" :renderLabel="customRender"></Select>
</template>
<style>
.vk-select__menu-item, .xyz {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}
</style>

远程搜索

当需要从服务器加载数据时,可使用远程搜索功能。通过输入关键字触发搜索,动态加载选项数据。

当前选择:

<template>
  <div>
    <Select
      v-model="selected"
      :options="options"
      placeholder="请输入关键词搜索"
      filterable
      remote
      :remote-method="handleFetch"
      clearable
    />
    <p>当前选择: {{ selected }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import Select from '../../../src/components/Select/Select.vue';
import type { SelectOption } from '../../../src/components/Select/types';

const selected = ref('');
const options = ref<SelectOption[]>([]);

// 模拟远程数据
const remoteData = [
  { label: '北京', value: 'beijing' },
  { label: '上海', value: 'shanghai' },
  { label: '广州', value: 'guangzhou' },
  { label: '深圳', value: 'shenzhen' },
  { label: '杭州', value: 'hangzhou' },
  { label: '南京', value: 'nanjing' },
  { label: '成都', value: 'chengdu' },
  { label: '武汉', value: 'wuhan' },
  { label: '西安', value: 'xian' },
  { label: '重庆', value: 'chongqing' },
  { label: '天津', value: 'tianjin' },
  { label: '苏州', value: 'suzhou' },
  { label: '厦门', value: 'xiamen' },
  { label: '青岛', value: 'qingdao' },
  { label: '大连', value: 'dalian' },
  { label: '长沙', value: 'changsha' },
  { label: '郑州', value: 'zhengzhou' },
  { label: '昆明', value: 'kunming' },
  { label: '济南', value: 'jinan' },
  { label: '合肥', value: 'hefei' },
  { label: '福州', value: 'fuzhou' },
  { label: '沈阳', value: 'shenyang' },
  { label: '长春', value: 'changchun' },
  { label: '贵阳', value: 'guiyang' },
  { label: '南宁', value: 'nanning' },
  { label: '哈尔滨', value: 'harbin' },
  { label: '太原', value: 'taiyuan' },
  { label: '石家庄', value: 'shijiazhuang' },
  { label: '乌鲁木齐', value: 'wulumuqi' },
  { label: '拉萨', value: 'lasa' },
  { label: '南昌', value: 'nanchang' },
  { label: '海口', value: 'haikou' },
  { label: '兰州', value: 'lanzhou' },
  { label: '银川', value: 'yinchuan' },
  { label: '西宁', value: 'xining' },
  { label: '呼和浩特', value: 'huhehaote' },
  { label: '台北', value: 'taipei' },
  { label: '香港', value: 'hongkong' },
  { label: '澳门', value: 'macau' },
  { label: '宁波', value: 'ningbo' },
  { label: '温州', value: 'wenzhou' },
  { label: '无锡', value: 'wuxi' },
  { label: '常州', value: 'changzhou' },
  { label: '东莞', value: 'dongguan' },
  { label: '佛山', value: 'foshan' },
];

// 模拟远程搜索方法
const remoteMethod = (query: string): Promise<SelectOption[]> => {
  return new Promise((resolve) => {
    if (query.trim() === '') {
      resolve([]);
      return;
    }

    // 模拟网络请求延迟
    setTimeout(() => {
      const results = remoteData.filter(item =>
        item.label.toLowerCase().includes(query.toLowerCase())
      );
      resolve(results);
    }, 800);
  });
};

const handleFetch = (query) => {
  if(!query) return Promise.resolve([])
  return fetch(`https://api.github.com/search/repositories?q=${query}`)
  .then(res => res.json())
  .then(({items}) => {
    return items.slice(0, 10).map(item => ({ label: item.name, value: item.node_id }))
  })
}
</script>

Attributes

名称说明类型默认值
model-value / v-model绑定值string | string[]
options下拉选项数组SelectOption[][]
placeholder占位文本string请选择
disabled是否禁用booleanfalse
clearable是否显示清空按钮booleanfalse
filterable是否可搜索booleanfalse
filterMethod自定义搜索方法(value: string) => SelectOption[]
remote是否开启远程搜索booleanfalse
remoteMethod远程搜索方法(value: string) => Promise<SelectOption[]>
renderLabel自定义选项渲染函数(option: SelectOption) => VNode
multiple是否多选booleanfalse
collapseTags多选时是否折叠显示已选标签booleanfalse

SelectOption

属性名说明类型默认值
label选项标签文本string
value选项的值string
disabled是否禁用booleanfalse

Events

事件名说明回调参数
update:modelValue值更新时触发(value: string | string[])
change选中值变化时触发(value: string | string[])
visible-change下拉框显示/隐藏时触发(visible: boolean)
clear点击清空按钮时触发
remove-tag多选模式下移除标签时触发(value: string)