vue 项目写一个下拉菜单效果

vue yekong

vue项目开发中,经常会用到下拉菜单功能,我们经常会使用element这里ui组件来实现,但是在实际开发中经常要自定义样式,这里会遇到一些问题,比如下拉菜单的样式自定义困难以及一些选中白边处理问题,所以这里想着自己实现一个下拉,这样自己想怎么实现样式就可以怎么实现。

vue 项目写一个下拉菜单效果

下拉动画

要实现下拉以及收缩时,为了增加视觉效果,我们需要给下拉收缩增加一个动画,这里我们仍然使用element的动画组件来实现:el-collapse-transition

图标旋转

我们在展开以及收缩时,还需要对下拉三角进行处理,比如下拉后,图标向上,收缩后图标向下。根据show的状态来判断图标的展开收缩,我们还需要一个样式来让图标有一个变化的过程transition: transform 0.3s ease-in-out;

<img class="changeSkinIcon" :style="{ transform: show ? 'rotate(180deg)' : 'rotate(0deg)' }"
           src="./assets/icon_down.png"
           alt="">

父组件使用

vue2写法

<selected :active.sync="active" :list="selectedList"></selected>
active: '1',
selectedList: [{
value: '1',
name: '吉林门站'
}, {
value: '2',
name: '吉林门站2'
}, {
value: '3',
name: '吉林门站3'
}, {
value: '4',
name: '吉林门站4'
}],

vue3写法

<selected v-model:active="active" :list="selectedList"></selected>
active: '1',
selectedList: [{
value: '1',
name: '吉林门站'
}, {
value: '2',
name: '吉林门站2'
}, {
value: '3',
name: '吉林门站3'
}, {
value: '4',
name: '吉林门站4'
}],

实例代码

<template>
  <div class="changeSkins">
    <div class="changeSkin" @click="show = !show">
      <span>{{ activeLabel ? activeLabel : placeholder }}</span>
      <img class="changeSkinIcon" :style="{ transform: show ? 'rotate(180deg)' : 'rotate(0deg)' }"
           src="./assets/icon_down.png"
           alt="">
    </div>
    <el-collapse-transition>
      <div class="dropdown-menu" v-if="show">
        <div class="dropdownMenuItem"
             v-for="(item,index) in list" :key="index"
             :class="{highlight: active === item.value}"
             @click="changeTheme(item.value)"><span>{{ item.name }}</span></div>
      </div>
    </el-collapse-transition>
  </div>
</template>

<script>


export default {
  name: "changeSkin",
  components: {},
  props: {
    list: {
      type: Array,
      default() {
        return [];
      }
    },
    placeholder: {
      type: String,
      default() {
        return '请选择';
      }
    },
    active: {
      type: [Number, String],
      default() {
        return 0;
      }
    },
  },
  data() {
    return {
      value: 0,
      show: false,
    }
  },
  computed: {
    activeLabel: function () {
      const selectedOption = this.list.find(option => option.value === this.active);
      return selectedOption ? selectedOption?.name : '';
    }
  },
  mounted() {
    // 添加全局点击事件监听器
    document.addEventListener('click', this.handleOutsideClick);
  },
  beforeUnmount() {
    // 组件销毁前移除事件监听器
    document.removeEventListener('click', this.handleOutsideClick);
  },
  beforeDestroy() {
    // 组件销毁前移除事件监听器
    document.removeEventListener('click', this.handleOutsideClick);
  },
  methods: {
    handleOutsideClick(e) {
      // 检查点击的元素是否是菜单或触发菜单的按钮
      if (!this.$el.contains(e.target)) {
        this.show = false; // 如果不是,则关闭菜单
      }
    },
    changeTheme(theme) {
      this.$emit('update:active', theme)
      this.show = false;
    }
  },
}
</script>
<style lang="scss" scoped>
.changeSkins {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: column;
  align-content: flex-start;
  position: relative;
  height: 40px;
  width: 100%;
  z-index: 100;

  .changeSkin {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: row;
    align-content: flex-start;
    cursor: pointer;
    height: 40px;
    width: 100%;


    span {
      margin-left: 12px;
      font-size: 14px;
      font-family: MicrosoftYaHei;
      font-weight: 400;
      color: #CEEEFE;
    }

    img {
      margin-right: 12px;
    }
  }

  .dropdown-menu {
    opacity: 1;
    top: 40px;
    width: 100%;
    background: rgba(1, 23, 63, 0.66);
    border: 1px solid #02639D;
    position: absolute;
    cursor: pointer;

    .dropdownMenuItem {
      height: 40px;
      border-bottom: 1px solid rgba(0, 163, 218, 0.1);
      display: flex;
      justify-content: center;
      align-items: center;
      flex-wrap: nowrap;
      flex-direction: row;
      align-content: flex-start;
      font-size: 14px;
      font-family: MicrosoftYaHei;
      font-weight: 400;
      color: #CCECFF;
    }

    .dropdownMenuItem.highlight, .dropdownMenuItem:hover {
      color: rgba(164, 222, 255, 1);
    }
  }
}

.fade-enter-active, .fade-leave-active {
  transition: transform 0.3s ease-in-out;
}

.fade-enter, .fade-leave-to {
  transform: translateY(-100%);
}

.changeSkinIcon {
  width: 12px;
  height: 7px;
  transition: transform 0.3s ease-in-out;
}
</style>


更新日志

2024年01月20日

添加点击空白区域收回菜单
增加placeholder添加默认显示内容

喜欢