[ vue ] 手动实现el-select简单功能

1. 组件

<template>
  <div class="mg-select">
    <input
      type="text"
      readonly
      @focus="focus"
      placeholder="请选择"
      @blur="blur"
      :value="getValue"
    />

    <Transition name="mg-options">
      <div class="mg_options" v-if="showPopup">
        <div class="option" v-for="item in options" :id="item[id]" @click="select(item)">
          {{ item[label] }}
        </div>
      </div>
    </Transition>
  </div>
</template>

<script setup>
const emits = defineEmits(["update:modelValue"]);
const props = defineProps({
  modelValue: [String, Number],
  options: {
    required: true,
    type: Array,
  },
  id: {
    required: true,
    type: [String, Number],
  },
  value: {
    required: true,
  },
  label: {
    required: true,
  },
});
const getValue = computed(() => {
  if (!props.modelValue) return "";
  const option = props.options.find((item) => item[props.value] === props.modelValue);
  return option ? option[props.label] : "";
});

const showPopup = ref(false);

const focus = () => {
  showPopup.value = true;
  console.log("focus");
};

const blur = () => {
  nextTick(() => {
    showPopup.value = false;
  });
};

const select = (item) => {
  console.log("select", item);
  emits("update:modelValue", item[props.value]);
  showPopup.value = false;
};
</script>

<style lang="scss" scoped>
.mg-select {
  width: 200px;
  height: 38px;
  border: 1px solid #bbb;
  border-radius: 8px;
  position: relative;

  input {
    width: 100%;
    height: 100%;
    border: none;
    outline: none;
    border-radius: inherit;
    padding-left: 14px;
    cursor: pointer;
  }

  .mg_options {
    position: absolute;
    top: 42px;
    left: 0;
    z-index: 1;
    width: inherit;
    border-radius: inherit;
    overflow: hidden;
    background-color: #fff;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
    border: 1px solid #e4e7ed;
    padding: 8px 0;

    .option {
      height: 32px;
      width: inherit;
      line-height: 32px;
      padding-left: 12px;
      cursor: pointer;

      &:hover {
        background: #eee;
      }
    }
  }
}

.mg-options-enter-active,
.mg-options-leave-active {
  transition: all 0.3s ease-in-out;
}

.mg-options-enter-from,
.mg-options-leave-to {
  transform-origin: 50% 0% 0;
  transform: rotateX(90deg);
  opacity: 0;
}
</style>

2. 引用组件

<template>
  <div style="margin: 20px 0">bind value is {{ selected }}</div>

  <div>
    <MgSelect :options="options" id="id" label="name" value="id" v-model="selected" />
  </div>

  <div style="margin: 20px 0">bind value is {{ selected2 }}</div>

  <MgSelect
    :options="[
      { id: 1, name: '张三' },
      { id: 2, name: '李四' },
    ]"
    id="id"
    label="name"
    value="id"
    v-model="selected2"
  />
</template>

<script setup>
import MgSelect from "@/components/mg_select.vue";
const options = [
  { id: 1, name: "周杰伦" },
  { id: 2, name: "王力宏" },
  { id: 3, name: "陈奕迅" },
  { id: 4, name: "刘德华" },
  { id: 5, name: "林俊杰" },
];
const selected = ref("");
const selected2 = ref("");
</script>

<style lang="scss" scoped></style>

 

posted @ 2025-07-15 11:35  深海里的星星i  阅读(26)  评论(0)    收藏  举报