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

news/2024/7/10 0:36:26 标签: vue.js, javascript, 前端, 前端框架, vue, 组件, web
webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

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

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

组件效果示例

image.png

组件所依赖的常量

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

javascript">/**
 * 与小尾巴下拉菜单组件相关的常量
 * @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

javascript">import '@/styles/tailComponentsThemeStyles/light.css'
import '@/styles/tailComponentsThemeStyles/dark.css'

配置 sass 预处理

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

组件源码

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

<!--
TailDropDown 小尾巴下拉菜单组件
-->
<script setup>javascript">
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<Readonly<ExtractPropTypes<{}>>>}
 */
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<UnwrapRef<boolean>>}
 */
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小尾巴下拉菜单组件是否收缩显示,收缩显示只显示下拉链接文本图标Booleanfalse
textLink小尾巴下拉菜单组件下拉链接文本String‘小尾巴下拉菜单下拉文本链接’
textLinkClickHandler小尾巴下拉菜单组件下拉链接文本点击事件处理函数Function() => {}
textLinkHeight小尾巴下拉菜单组件下拉链接文本高度String‘2rem’
enableImageLink是否启用下拉链接图片替换下拉链接文本Booleanfalse
imageLinkUrl小尾巴下拉菜单组件下拉链接图片图片地址String‘’
imageSize小尾巴下拉菜单组件下拉链接图片图片大小,图片默认圆形居中String‘2rem’
imageLinkClickHandler小尾巴下拉菜单组件下拉链接图片点击事件处理函数Function() => {}
menuDistanceWithLink小尾巴下拉菜单组件下拉菜单与下拉链接之间的距离String‘0.5rem’
menuVerticalAlign小尾巴下拉菜单组件下拉菜单与下拉链接之间的垂直对其方式,默认左对齐StringDROP_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下拉菜单,该插槽会替换默认的下拉菜单项

http://www.niftyadmin.cn/n/5150886.html

相关文章

这5个老年人技巧,让你的微信操作起来更方便

目录 一、便捷登录验证 二、快速开启关怀模式 三、语音与消息撤回 四、快速打开名片二维码 五、语音收藏 六、总结 今天小编给大家分享5个老年人技巧&#xff0c;一起来看看吧&#xff01;说不定也能让你的微信操作起来更方便呢&#xff01; 一、便捷登录验证 在微信中&a…

Java web(六):FilterListenerAJAX

文章目录 一、Filter1.1 基本介绍1.2 过滤器的执行流程1.3 拦截路径配置1.4 过滤器链1.5 案例 二、Listener三、AJAX3.1 快速入门3.2 Axios异步框架 四、 JSON4.1 JSON基础语法4.2 Fastjson 五、 案例JSONAxiosServlet Java web的三大组件&#xff1a;Servlet、Filter、Listene…

Java 8 新特性 Stream 的使用场景(不定期更新)

方便在写代码的过程中直接使用&#xff0c;好记性不如好文章&#xff0c;直接 CV 改了直接用。提高 办&#xff08;摸&#xff09;公&#xff08;鱼&#xff09;效&#xff08;时&#xff09;率&#xff08;间&#xff09;&#xff0c; 不然就直接问 GPT 也不是说不行。 只符合…

操作系统学习笔记(学习中)

计算机系统概述 1.操作系统概念 管理系统软/硬件资源&#xff0c;为程序提供服务 2.发展与分类 3.操作系统的运行环境 运行机制 指令&#xff1a;&#xff08;二进制机器指令&#xff09;&#xff0c;CPU能识别&#xff0c;执行的最基本命令 应用程序&#xff1a;程序员写…

K7系列FPGA进行FLASH读写1——CCLK控制(STARTUPE2原语)

最近的工作涉及对 FPGA 进行远程更新&#xff0c;也就是通过远程通信接口将 .bin 文件送到 FPGA&#xff0c;然后写入 FLASH&#xff0c;这样当 FPGA 重新上电后就可以执行更新后的程序了。因此第一步工作就是进行 FLASH 的读写控制。 然而如果尝试配置 FLASH 管脚时&#xff0…

存储器(详解)

概念 存储器&#xff08;Memory&#xff09;是计算机系统中用于存储和检索数据的硬件设备或组件。它在计算机中扮演着重要的角色&#xff0c;允许计算机暂时或永久地存储程序、数据和中间结果。 存储器是许多存储单元的集合&#xff0c;按单元号顺序排列。每个单元由若干二进制…

全自动洗衣机什么牌子好?内衣洗衣机品牌排行榜前四名

随着内衣洗衣机的流行&#xff0c;很多小伙伴在纠结该不该入手一款内衣洗衣机&#xff0c;专门来洗一些贴身衣物&#xff0c;答案是非常有必要的&#xff0c;因为我们现在市面上的大型洗衣机只能做清洁&#xff0c;无法对我们的贴身衣物进行一个高强度的清洁&#xff0c;而小小…

【数据结构】败者树的建树与比较过程

文章目录 前置知识归并段 建树过程比较过程疑问为什么比较次数减少了&#xff1f;如果某个归并段的元素一直获胜&#xff0c;没有元素了怎么办&#xff1f;处理方法 1处理方法 2 前置知识 归并段 外部排序算法通常用于处理大规模数据&#xff0c;其中数据量远超过计算机内存的…