Select 选择器
响应式选择器组件。
行内 Tailwind/UnoCSS 用法
使用行内的tailwind/unocss样式构建,复制组件的代码即可使用
查看代码
html
<!-- 基础选择器 -->
<select class="w-full rounded-md border border-solid border-gray-300 bg-white px-4 py-2 text-gray-700 shadow-sm focus:outline-none focus:ring-1 focus:ring-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300">
<option selected>
请选择
</option>
<option>选项 1</option>
<option>选项 2</option>
<option>选项 3</option>
</select>
自定义下拉菜单
需要javascript
控制下拉菜单显示和隐藏
查看代码
html
<div class="tailuno-select group relative w-[200px]" data-open="false">
<button class="select-button flex w-full items-center justify-between rounded-md border border-solid border-gray-300 bg-white px-4 py-2 text-left text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-1 focus:ring-gray-300 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700">
<span>请选择</span>
<svg class="size-5 text-gray-400 transition-transform duration-200 group-data-[open=true]:rotate-180"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div class="select-dropdown absolute z-10 mt-1 hidden max-h-60 w-full overflow-auto rounded-md bg-white shadow-lg group-data-[open=true]:block dark:border-gray-600 dark:bg-gray-800">
<div class="select-option option-item cursor-pointer px-4 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 [&[data-selected='true']]:bg-gray-100 [&[data-selected='true']]:dark:bg-blue-900/50 [&[data-selected='true']]:dark:text-blue-400">
选项 1
</div>
<div class="select-option option-item cursor-pointer px-4 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 [&[data-selected='true']]:bg-gray-100 [&[data-selected='true']]:dark:bg-blue-900/50 [&[data-selected='true']]:dark:text-blue-400">
选项 2
</div>
<div class="select-option option-item cursor-pointer px-4 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 [&[data-selected='true']]:bg-gray-100 [&[data-selected='true']]:dark:bg-blue-900/50 [&[data-selected='true']]:dark:text-blue-400">
选项 3
</div>
<div class="select-option option-item cursor-pointer px-4 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 [&[data-selected='true']]:bg-gray-100 [&[data-selected='true']]:dark:bg-blue-900/50 [&[data-selected='true']]:dark:text-blue-400">
选项 4
</div>
</div>
</div>
js
// 全局事件处理器,引入此文件自动注册,只注册一次
// 全局入口或组件中引入此文件皆可,不限html或vue或react
function initGlobalSelectHandler() {
if (window._selectHandlerInitialized)
return
document.addEventListener('click', (e) => {
const selectContainer = e.target.closest('.tailuno-select')
if (!selectContainer) {
// 点击外部,关闭所有下拉框
document.querySelectorAll('.tailuno-select[data-open="true"]')
.forEach(container => container.dataset.open = 'false')
return
}
const button = e.target.closest('button')
const option = e.target.closest('.option-item')
if (button) {
// 切换下拉框状态
const isOpen = selectContainer.dataset.open === 'true'
selectContainer.dataset.open = !isOpen
}
else if (option) {
// 更新选中状态
selectContainer.querySelectorAll('.option-item').forEach((item) => {
item.removeAttribute('data-selected')
})
option.setAttribute('data-selected', 'true')
// 更新显示文本
selectContainer.querySelector('button span').textContent = option.textContent
// 关闭下拉框
selectContainer.dataset.open = 'false'
}
})
window._selectHandlerInitialized = true
}
initGlobalSelectHandler()
vue
<!-- Vue版本,直接复制此文件使用即可,不使用点击外侧自动收起的话,无需再引入其他js -->
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
const options = [
{ label: '选项 1', value: '1' },
{ label: '选项 2', value: '2' },
{ label: '选项 3', value: '3' },
{ label: '选项 4', value: '4' },
]
const isOpen = ref(false)
const selected = ref('')
function toggleOpen() {
isOpen.value = !isOpen.value
}
function selectOption(option) {
selected.value = option
isOpen.value = false
}
// 可选,点击外部时关闭下拉菜单
const selectRef = ref(null)
const listener = event => (!selectRef.value?.contains(event.target) && (isOpen.value = false))
onMounted(() => document.addEventListener('click', listener))
onUnmounted(() => document.removeEventListener('click', listener))
</script>
<template>
<div ref="selectRef" class="relative w-[200px]">
<button class="flex w-full items-center justify-between rounded-md border border-solid border-gray-300 bg-white px-4 py-2 text-left text-gray-700 shadow-sm hover:bg-gray-50 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-primary dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
@click="toggleOpen">
<span>{{ selected?.label || '请选择' }}</span>
<svg class="size-5 text-gray-400 transition-transform duration-200"
:class="{ 'rotate-180': isOpen }"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div v-show="isOpen"
class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white shadow-lg dark:border-gray-600 dark:bg-gray-800">
<div v-for="option in options"
:key="option"
class="cursor-pointer px-4 py-2 text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"
:class="{ 'bg-blue-50 text-blue-600 dark:bg-blue-900/50 dark:text-blue-400': selected?.value === option.value }"
@click="selectOption(option)">
{{ option.label }}
</div>
</div>
</div>
</template>
CSS 类用法
使用预定义的CSS类。复制index.css的样式即可使用
查看代码
html
<!-- 基础选择器 -->
<select class="select">
<option selected>
请选择
</option>
<option>选项 1</option>
<option>选项 2</option>
<option>选项 3</option>
</select>
<!-- 带图标的选择器 -->
<div class="select-wrapper">
<select class="select">
<option selected>
请选择
</option>
<option>选项 1</option>
<option>选项 2</option>
<option>选项 3</option>
</select>
<svg class="select-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l4-4 4 4m0 6l-4 4-4-4" />
</svg>
</div>
<!-- 自定义下拉菜单 -->
<div class="select-custom-wrapper">
<button class="select-custom-trigger" @click="toggleOpen">
<span>{{ selected || '请选择' }}</span>
<svg class="select-custom-arrow" :class="{ 'rotate-180': isOpen }" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div v-show="isOpen" class="select-custom-dropdown">
<div
v-for="option in options"
:key="option"
class="select-custom-option"
:class="{ 'select-custom-selected': selected === option }"
@click="selectOption(option)">
{{ option }}
</div>
</div>
</div>
css
.select {
@apply block w-full px-4 py-2 text-gray-700 bg-white border border-solid border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-gray-300 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300;
&:disabled {
@apply opacity-50 cursor-not-allowed;
}
}
.select-wrapper {
@apply relative;
}
.select-icon {
@apply absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400 pointer-events-none;
}
.select-custom-wrapper {
@apply relative w-full;
}
.select-custom-trigger {
@apply w-full px-4 py-2 text-left text-gray-700 bg-white border border-solid border-gray-300 rounded-md shadow-sm flex items-center justify-between hover:bg-gray-50 focus:outline-none focus:ring-1 focus:ring-gray-300 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700;
}
.select-custom-arrow {
@apply w-5 h-5 text-gray-400 transition-transform duration-200;
}
.select-custom-dropdown {
@apply absolute z-[10] w-full mt-1 bg-white rounded-md shadow-lg max-h-60 overflow-auto dark:bg-gray-800 dark:border-gray-600;
}
.select-custom-option {
@apply px-4 py-2 text-gray-700 hover:bg-gray-100 cursor-pointer dark:text-gray-300 dark:hover:bg-gray-700;
&.select-custom-selected {
@apply bg-gray-100 dark:bg-blue-900/50 dark:text-blue-400;
}
}