You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中如何为select的option标签添加CSS实现自定义下拉框

Vue.js 实现可完全自定义样式的select下拉选择框

原生<select>组件的下拉弹出层、选项样式由浏览器原生控件渲染,CSS无法深度修改,这是你无法给元素加自定义样式的根本原因。要实现和参考图一致的自定义样式,需要放弃原生select标签,用普通DOM元素模拟下拉交互逻辑,所有元素都支持任意CSS修改。

自定义下拉选择框参考样式

核心实现思路

你只需要实现几个基础交互逻辑,就能得到一个完全可控的自定义下拉框:

  • 点击触发区域切换下拉选项的显示/隐藏
  • 点击选项时更新选中值、同步显示文本、自动收起下拉
  • 点击下拉组件外部区域时自动收起下拉
  • 所有结构用div、ul、li这类普通标签实现,样式完全自定义

可直接复用的单文件组件代码

<template>
  <div class="custom-select" ref="selectRef">
    <!-- 选中值展示触发区 -->
    <div class="select-trigger" @click="toggleDropdown">
      <span class="selected-text">{{ selectedLabel || placeholder }}</span>
      <span class="arrow" :class="{ 'arrow-up': isOpen }">▼</span>
    </div>
    <!-- 下拉选项列表 -->
    <ul class="options-list" v-show="isOpen">
      <li
        v-for="option in options"
        :key="option.value"
        class="option-item"
        :class="{ 'is-selected': option.value === modelValue }"
        @click="handleSelect(option)"
      >
        {{ option.label }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
const props = defineProps({
  modelValue: [String, Number],
  options: { type: Array, required: true },
  placeholder: { type: String, default: '请选择' }
})
const emit = defineEmits(['update:modelValue'])
const isOpen = ref(false)
const selectRef = ref(null)
const selectedLabel = ref('')

const toggleDropdown = () => isOpen.value = !isOpen.value

const handleSelect = (option) => {
  emit('update:modelValue', option.value)
  selectedLabel.value = option.label
  isOpen.value = false
}

// 点击组件外部关闭下拉
const handleClickOutside = (e) => {
  if (selectRef.value && !selectRef.value.contains(e.target)) isOpen.value = false
}

onMounted(() => {
  // 初始化回显已选值
  const matched = props.options.find(item => item.value === props.modelValue)
  if (matched) selectedLabel.value = matched.label
  document.addEventListener('click', handleClickOutside)
})

onBeforeUnmount(() => {
  document.removeEventListener('click', handleClickOutside)
})
</script>

<style scoped>
.custom-select {
  position: relative;
  width: 240px;
  font-size: 14px;
}
/* 触发框样式,可任意修改匹配设计稿 */
.select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  cursor: pointer;
  background: #fff;
}
.select-trigger:hover {
  border-color: #409eff;
}
.selected-text {
  color: #303133;
}
.selected-text:empty::after {
  content: attr(placeholder);
  color: #c0c4cc;
}
.arrow {
  font-size: 12px;
  color: #909399;
  transition: transform 0.2s;
}
.arrow-up {
  transform: rotate(180deg);
}
/* 下拉列表容器样式 */
.options-list {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: 100%;
  margin: 0;
  padding: 6px 0;
  list-style: none;
  background: #fff;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
  z-index: 999;
}
/* 单个选项样式 */
.option-item {
  padding: 8px 14px;
  cursor: pointer;
  color: #606266;
}
.option-item:hover {
  background-color: #f5f7fa;
}
/* 选中项高亮样式 */
.option-item.is-selected {
  color: #409eff;
  font-weight: 500;
  background-color: #ecf5ff;
}
</style>

组件使用方式

在需要用到下拉框的页面引入组件即可,支持v-model双向绑定:

<template>
  <CustomSelect
    v-model="selectedCity"
    :options="cityOptions"
    placeholder="请选择城市"
  />
</template>

<script setup>
import { ref } from 'vue'
import CustomSelect from './CustomSelect.vue'
const selectedCity = ref('')
const cityOptions = ref([
  { label: '北京', value: 'beijing' },
  { label: '上海', value: 'shanghai' },
  { label: '广州', value: 'guangzhou' },
  { label: '深圳', value: 'shenzhen' }
])
</script>

补充说明

  • 上述组件的所有样式都可以自由修改,你可以调整圆角、边框、颜色、阴影、间距等所有视觉属性,完全匹配你提供的参考设计图,没有原生select的样式限制
  • 如果需要搜索过滤、多选、选项分组、虚拟滚动等复杂功能,可以直接在这个基础逻辑上扩展
  • 如果不想从零手写,也可以直接使用Element Plus、Naive UI等成熟Vue组件库的Select组件,这类组件同样是用DOM模拟实现,支持任意样式自定义。

内容的提问来源于stack exchange,提问作者Deepshikha Dudi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 21:21:39