[自定义 Vue 组件] 小尾巴下拉菜单组件(2.0) TailDropDown

文章归档:https://www.yuque.com/u27599042/coding_star/kcoem6dgyn8drglb

[自定义 Vue 组件] 下拉菜单(1.0) DropDownMenu:https://www.yuque.com/u27599042/coding_star/llltv52tchmatwg4

组件效果示例

[自定义 Vue 组件] 小尾巴下拉菜单组件(2.0) TailDropDown_第1张图片

组件所依赖的常量

在 src 目录下,创建 constant 目录,在其中新建 tail_drop_down_constant.js 文件,在其中声明组件所依赖的常量

/**
 * 与小尾巴下拉菜单组件相关的常量
 * @type {*} 与小尾巴下拉菜单组件相关的常量
 */

/**
 * 小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式
 * @type {string} 小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式
 */
// 左对齐
export const DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_LEFT = 'left'
// 居中对其
export const DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_CENTER = 'center'
// 右对齐
export const DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_RIGHT = 'right'

/**
 * 小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式所对应的样式类名
 * @type {string} 小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式所对应的样式类名
 */
// 左对齐
export const DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_LEFT = 'tail-drop-down-menu-box-v-align-left'
// 居中对其
export const DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_CENTER = 'tail-drop-down-menu-box-v-align-center'
// 右对齐
export const DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_RIGHT = 'tail-drop-down-menu-box-v-align-right'
// 所有下拉菜单与下拉链接之间的垂直对其方式所对应的样式类名组成的数组
export const dropDownMenuVerticalAlignClasses = [
    DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_LEFT,
    DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_CENTER,
    DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_RIGHT
]

组件所依赖的 CSS 变量

在 src 目录下,创建 styles 目录,在其中创建 tailComponentsThemeStyles 目录,在 tailComponentsThemeStyles 目录中新建 light.css 与 dark.css 文件,在其中声明组件所依赖的和主题样式相关的 CSS 变量

/*
 * 和小尾巴组件相关的亮色主题样式 CSS 变量
 */
:root[class*='light'] {
    /*
     * 小尾巴下拉菜单组件样式变量
     */
    /* 小尾巴下拉菜单组件背景颜色 */
    --tail-drop-down-bgc: #efefef00;
    /* 小尾巴下拉菜单组件菜单项背景颜色 */
    --tail-drop-down-menu-item-bgc: #efefef99;
    /* 小尾巴下拉菜单组件字体颜色 */
    --tail-drop-down-font-color: #333333;
    /* 小尾巴下拉菜单组件鼠标悬浮背景颜色 */
    --tail-drop-down-hover-bgc: #ccf4ed;
    /* 小尾巴下拉菜单组件鼠标悬浮字体颜色 */
    --tail-drop-down-hover-font-color: #1b88e3;
}
/*
 * 和小尾巴组件相关的暗色主题样式 CSS 变量
 */
:root[class*='dark'] {
    /*
     * 小尾巴下拉菜单组件样式变量
     */
    /* 小尾巴下拉菜单组件背景颜色 */
    --tail-drop-down-bgc: #454545;
    /* 小尾巴下拉菜单组件菜单项背景颜色 */
    --tail-drop-down-menu-item-bgc: #454545;
    /* 小尾巴下拉菜单组件字体颜色 */
    --tail-drop-down-font-color: #efefef;
    /* 小尾巴下拉菜单组件鼠标悬浮背景颜色 */
    --tail-drop-down-hover-bgc: #565555;
    /* 小尾巴下拉菜单组件鼠标悬浮字体颜色 */
    --tail-drop-down-hover-font-color: #00C9A7;
}

在 index.html 文件中的 html 元素上添加 light 或 dark 类名

<html lang="zh-CN" class="light">

在 main.js 文件中引入组件所依赖的和主题样式相关的 CSS 变量

vue 项目中配置 src 目录别名:https://www.yuque.com/u27599042/coding_star/ogu2bhefy1fvahfv

import '@/styles/tailComponentsThemeStyles/light.css'
import '@/styles/tailComponentsThemeStyles/dark.css'

配置 sass 预处理

https://www.yuque.com/u27599042/coding_star/ua8sgyngldtaa2re

组件源码

在 src/components 目录下,创建 TailDropDown.vue 文件,在其中编写组件


<script setup>
import {ref, computed} from 'vue'
import {
  DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_CENTER,
  DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_LEFT,
  DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_RIGHT,
  DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_CENTER,
  DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_LEFT,
  DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_RIGHT
} from "@/constant/tail_drop_down_constant.js";

/**
 * 接收父组件传递的参数
 * @type {Prettify>>}
 */
const props = defineProps({
  // 小尾巴下拉菜单组件是否收缩显示,收缩显示只显示下拉文本链接图标
  isShrinkDisplay: {type: Boolean, default: false},
  // 小尾巴下拉菜单组件下拉文本链接
  textLink: {type: String, default: '小尾巴下拉菜单下拉文本链接'},
  // 小尾巴下拉菜单组件下拉文本链接点击事件处理函数
  textLinkClickHandler: {
    type: Function, default: () => {
    }
  },
  // 小尾巴下拉菜单组件下拉文本链接高度
  textLinkHeight: {type: String, default: '2rem'},
  // 是否启用下拉图片链接替换下拉文本链接
  enableImageLink: {type: Boolean, default: false},
  // 小尾巴下拉菜单组件下拉图片链接图片地址
  imageLinkUrl: {type: String, default: ''},
  // 小尾巴下拉菜单组件下拉图片链接图片大小,图片默认圆形居中
  imageSize: {type: String, default: '2rem'},
  // 小尾巴下拉菜单组件下拉图片链接点击事件处理函数
  imageLinkClickHandler: {
    type: Function, default: () => {
    }
  },
  // 小尾巴下拉菜单组件下拉菜单与下拉链接之间的距离
  menuDistanceWithLink: {type: String, default: '0.5rem'},
  // 小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式,默认左对齐
  menuVerticalAlign: {type: String, default: DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_LEFT},
  // 小尾巴下拉菜单组件下拉菜单项,由 {menuItemText: '', menuItemClickHandler: ()=>{}} 组成的数组
  menuItems: {type: Array, default: []},
  // 小尾巴下拉菜单组件下拉菜单项高度
  menuItemHeight: {type: String, default: '2rem'},
})

/**
 * 小尾巴下拉菜单组件下拉文本链接样式
 * @type {{height: *}}
 */
const textLinkStyle = {
  height: props?.textLinkHeight
}

/**
 * 小尾巴下拉菜单组件下拉图片链接样式
 * @type {{width: *, height: *}}
 */
const imageLinkStyle = {
  height: props?.imageSize,
  width: props?.imageSize,
}

/**
 * 小尾巴下拉菜单组件下拉菜单项样式
 * @type {{height: *}}
 */
const menuItemStyle = {
  height: props?.menuItemHeight
}

/**
 * 控制下拉菜单是否显示
 * @type {Ref>}
 */
const dropDownMenuIsShow = ref(false)

/**
 * 小尾巴下拉菜单组件下拉菜单样式
 * @type {{paddingTop: {default: string, type: String | StringConstructor}}}
 */
const menuStyle = {
  paddingTop: props?.menuDistanceWithLink
}

/**
 * 动态控制下拉菜单与下拉链接之间的垂直对其方式
 */
// 下拉菜单的 class 类名
const dropDownMenuClassName = computed(() => {
  // 判断指定的下拉菜单与下拉链接之间的垂直对其方式
  switch (props?.menuVerticalAlign) {
    case DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_LEFT:
      return DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_LEFT
    case DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_CENTER:
      return DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_CENTER
    case DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_RIGHT:
      return DROP_DOWN_MENU_VERTICAL_ALIGN_CLASS_RIGHT
  }
})

script>

<template>
  
  <div class="tail-drop-down">
    
    <div
        class="tail-drop-down-link"
        @mouseover="dropDownMenuIsShow = true"
        @mouseout="dropDownMenuIsShow = false"
    >
      
      <div
          class="tail-drop-down-text-link"
          v-if="!enableImageLink"
          :style="textLinkStyle"
          @click="textLinkClickHandler"
      >
        
        <span class="tail-drop-down-text-link-icon">
          <slot name="dropDownTextLinkIcon">slot>
        span>
        <span v-show="!isShrinkDisplay">{{ textLink }}span>
        
        <div
            v-show="menuItems.length > 0"
            class="tail-drop-down-link-icon"
            :class="dropDownMenuIsShow ? 'tail-drop-down-link-icon-rotate' : ''"
        >
          <slot name="dropDownLinkIcon">slot>
        div>
      div>
      
      <slot name="dropDownImageLink" v-if="enableImageLink">
        <div
            class="tail-drop-down-image-link"
            :style="imageLinkStyle"
            v-if="enableImageLink"
        >
          <img :src="imageLinkUrl" alt="小尾巴下拉菜单下拉图片链接">
        div>
      slot>
      
      <div
          class="tail-drop-down-menu-box"
          :class="dropDownMenuClassName"
          :style="menuStyle"
      >
        <div
            class="tail-drop-down-menu"
            v-show="dropDownMenuIsShow"
        >
          <slot name="dropDownMenu">
            <ul>
              
              <li
                  class="tail-drop-down-menu-item"
                  v-for="(menuItem, idx) in menuItems"
                  :key="idx"
                  :style="menuItemStyle"
                  @click="menuItem?.menuItemClickHandler"
              >
                <span>{{ menuItem?.menuItemText }}span>
              li>
            ul>
          slot>
        div>
      div>
    div>
  div>
template>

<style scoped lang="scss">
/*
 * 小尾巴下拉菜单组件
 */
.tail-drop-down {
  color: var(--tail-drop-down-font-color);

  /*
   * 清除默认样式
   */
  div, ul, li, span {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /*
   * 小尾巴下拉菜单组件下拉链接
   */
  .tail-drop-down-link {
    position: relative;
    display: inline-block;
    cursor: pointer;
    // 文字不能被选中
    user-select: none;

    /*
     * 小尾巴下拉菜单组件下拉文本链接
     */
    .tail-drop-down-text-link {
      box-sizing: border-box;
      padding: 0.5rem;
      border-radius: 0.5rem;
      background-color: var(--tail-drop-down-bgc);
      transition: all 0.3s;
      display: flex;
      justify-content: center;
      align-items: center;
      // 文本不换行
      white-space: nowrap;

      &:hover {
        background-color: var(--tail-drop-down-hover-bgc);
        color: var(--tail-drop-down-hover-font-color);
      }

      /*
       * 小尾巴下拉菜单组件下拉链接图标
       */
      .tail-drop-down-link-icon {
        width: 100%;
        height: 100%;
        margin-left: 0.5rem;
        transition: all 0.3s;
        // 设置旋转中心点 x y
        transform-origin: 50% 50%;
        display: flex;
        justify-content: center;
        align-items: end;
      }

      /*
       * 小尾巴下拉菜单组件下拉链接图标旋转样式
       */
      .tail-drop-down-link-icon-rotate {
        transform: rotateZ(180deg);
        transition-delay: -0.1s;
      }
    }

    /*
     * 小尾巴下拉菜单组件下拉图片链接
     */
    .tail-drop-down-image-link {
      border-radius: 50%;
      background-color: var(--tail-drop-down-bgc);
      transition: all 0.5s;
      overflow: hidden;

      &:hover {
        transform: rotateZ(360deg);
      }

      img {
        width: 100%;
      }
    }

    /*
     * 小尾巴下拉菜单组件下拉菜单盒子
     */
    .tail-drop-down-menu-box {
      position: absolute;
      top: 100%;

      /*
       * 小尾巴下拉菜单组件下拉菜单
       */
      .tail-drop-down-menu {
        border-radius: 0.5rem;
        // 如果溢出隐藏会影响子菜单的显示
        // overflow: hidden;

        /*
         * 小尾巴下拉菜单组件下拉菜单项
         */
        .tail-drop-down-menu-item {
          z-index: 1;
          box-sizing: border-box;
          padding: 0.5rem;
          background-color: var(--tail-drop-down-menu-item-bgc);
          transition: all 0.3s;
          overflow: hidden;
          display: flex;
          justify-content: start;
          align-items: center;
          // 文本不换行
          white-space: nowrap;

          &:hover {
            background-color: var(--tail-drop-down-hover-bgc);
            color: var(--tail-drop-down-hover-font-color);
          }

          // 当前元素的父元素的第一个子元素
          &:first-child {
            border-top-right-radius: 0.5rem;
            border-top-left-radius: 0.5rem;
          }

          // 当前元素的父元素的最后一个子元素
          &:last-child {
            border-bottom-right-radius: 0.5rem;
            border-bottom-left-radius: 0.5rem;
          }
        }
      }
    }

    /*
     * 小尾巴下拉菜单组件下拉菜单盒子与下拉链接之间的垂直对其方式
     */
    // 左对齐
    .tail-drop-down-menu-box-v-align-left {
      left: 0;
    }

    // 居中对齐
    .tail-drop-down-menu-box-v-align-center {
      left: 50%;
      transform: translateX(-50%);
    }

    // 右对齐
    .tail-drop-down-menu-box-v-align-right {
      right: 0;
    }
  }
}
style>

组件使用说明

props 组件属性

属性 属性说明 属性值类型 属性默认值
isShrinkDisplay 小尾巴下拉菜单组件是否收缩显示,收缩显示只显示下拉链接文本图标 Boolean false
textLink 小尾巴下拉菜单组件下拉链接文本 String ‘小尾巴下拉菜单下拉文本链接’
textLinkClickHandler 小尾巴下拉菜单组件下拉链接文本点击事件处理函数 Function () => {}
textLinkHeight 小尾巴下拉菜单组件下拉链接文本高度 String ‘2rem’
enableImageLink 是否启用下拉链接图片替换下拉链接文本 Boolean false
imageLinkUrl 小尾巴下拉菜单组件下拉链接图片图片地址 String ‘’
imageSize 小尾巴下拉菜单组件下拉链接图片图片大小,图片默认圆形居中 String ‘2rem’
imageLinkClickHandler 小尾巴下拉菜单组件下拉链接图片点击事件处理函数 Function () => {}
menuDistanceWithLink 小尾巴下拉菜单组件下拉菜单与下拉链接之间的距离 String ‘0.5rem’
menuVerticalAlign 小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式,默认左对齐 String DROP_DOWN_MENU_VERTICAL_ALIGN_WAY_LEFT
取值参考:https://www.yuque.com/u27599042/coding_star/kcoem6dgyn8drglb#CYUne
menuItems 小尾巴下拉菜单组件下拉菜单项,由 {menuItemText: '', menuItemClickHandler: ()=>{}} 组成的数组 Array []
menuItemHeight 小尾巴下拉菜单组件下拉菜单项高度 String ‘2rem’

slot 插槽

插槽名称 插槽说明
dropDownTextLinkIcon 小尾巴下拉菜单组件下拉链接文本前的图标
dropDownLinkIcon 小尾巴下拉菜单组件下拉链接图标(下拉链接文本后的图标)
dropDownImageLink 小尾巴下拉菜单组件下拉链接图片,需要使 enableImageLink 组件属性为 true (使用此插槽元素替换下拉链接文本)
dropDownMenu 下拉菜单,该插槽会替换默认的下拉菜单项

你可能感兴趣的:(小尾巴的编程知识星球,vue.js,javascript,前端,前端框架,vue,组件,web)