Skip to content

封装一个下拉单选组件

319字约1分钟

封装组件

2024-06-05

有些时候需要用到单选功能,使用单选框太占位置了。


@/components/selector.vue

<script setup lang="ts">
  import SvgIcon from "@/components/svgIcon/index.vue"
  import { ref } from "vue"
  import type { SelectorData } from "@/components/selector/type"

  defineOptions({ name: "Selector" })

  // 是否显示下拉内容
  const show = ref(false)
  // 已选择的值
  const showValue = ref("")

  interface SelectorProps {
    placeholder?: string
    data: SelectorData[]
  }

  const props = defineProps<SelectorProps>()

  const modelValue = defineModel<string | number | undefined>({
    default: "",
  })

  if (modelValue.value) {
    const current = props.data.find((item) => {
      return item.id === modelValue.value
    })
    if (current) {
      showValue.value = current.name
    }
  }

  // 选中改变
  const changeSelect = (item: SelectorData) => {
    showValue.value = item.name
    modelValue.value = item.id
  }
</script>

<template>
  <div class="selector" @click="show = !show" :class="{show}">
    <span class="value" :class="{placeholder: modelValue === ''}">
      {{ showValue || placeholder || '请选择...' }}
    </span>
    <SvgIcon
      class="right-icon"
      :name="show ? 'arrow-up' : 'arrow-down'"
    ></SvgIcon>
    <div class="drop-list" :class="{show}">
      <ul>
        <li v-for="item in data" :key="item.id" @click="changeSelect(item)">
          {{item.name}}
        </li>
      </ul>
    </div>
  </div>
</template>

<style scoped lang="scss">
  .selector {
    min-width: 200px;
    height: 40px;
    border: 2px dashed #ccc;
    border-radius: 5px;
    position: relative;
    padding: 0 10px;
    line-height: 40px;
    cursor: pointer;
    display: flex;
    align-items: center;

    .value {
      flex: 1;

      &.placeholder {
        color: #808080;
      }
    }

    .right-icon {
      margin-left: 10px;
    }

    &.show {
      border-bottom-color: transparent;
    }

    .drop-list {
      position: absolute;
      top: 40px;
      left: 0;
      width: 100%;
      background-color: #fff;
      visibility: hidden;
      box-shadow: 0 0 4px #eee;
      border-left: 2px solid #eee;
      border-right: 2px solid #eee;
      border-bottom: 2px solid #eee;
      border-bottom-left-radius: 5px;
      border-bottom-right-radius: 5px;

      &.show {
        visibility: visible;
      }

      ul li {
        padding: 0 10px;
        border-bottom: 1px solid #ccc;

        &:last-child {
          border-bottom: none;
        }

        &:hover {
          color: $primary-color;
        }
      }
    }
  }
</style>

ts 类型

export interface SelectorData {
  id: number
  name: string
}