iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >手写实现vue2下拉菜单dropdown组件实例
  • 862
分享到

手写实现vue2下拉菜单dropdown组件实例

2024-04-02 19:04:59 862人浏览 薄情痞子
摘要

目录概述最终效果(动图没显示出来,请稍定会儿,可以先看后面)实现原理具体实现目录结构emitter.jsMyDropdown.VueMyDropdownMenu.vueMy

概述

一般后台项目结合分页组件用到这个dropdown组件,用来做显示分页条数,其他用到这个组件的地方倒不是很多,其实现思路和select组件有那么些相似,现记录下这个组件的实现。

最终效果(动图没显示出来,请稍定会儿,可以先看后面)

实现原理

这个组件和select组件记起相似,可以参考我之前的文章【手写vue2select下拉组件】,要做这个组件,需要注意以下几点:

组件分为两部分:

  • 供我们点击的文字,按钮,超链接等等(当成插槽供用户提供)
  • 下拉菜单项(支持边框,禁用等)

使用该组件应当提供的事件应该是点击item项,然后将对应的item的对应value暴露出来,供用户使用。

组件菜单项的显示隐藏需要过渡动画。

默认菜单项方向向下,当下方可视区的高度不足以容纳下拉菜单的高度的时候,自动让菜单方向向上。

具体实现

目录结构

emitter.js

这个在之前的组件实现过程中介绍过这个文件,主要是为了解决跨多层级父子组件之前数据通信的,本质上实现原理为发布订阅模式。


// 广播通知事件
function _broadcast(componentName, eventName, params) {
  // 遍历当前组件的子组件
  this.$children.forEach(function (child) {
    // 取出componentName,组件options上面可以自己配置
    var name = child.$options.componentName;
    // 如果找到了需要通知的组件名,触发组件上面的$eimit方法,触发自定义事件
    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      // 没找到,递归往下找
      _broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
const emiiter = {
  methods: {
    // 派发事件(通知父组件)
    dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;
      // 循环往上层父组件,知道知道组件名和需要触发的组件名相同即可,然后触发对应组件的事件
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;
        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    // 广播事件(通知子组件)
    broadcast(componentName, eventName, params) {
      _broadcast.call(this, componentName, eventName, params);
    },
  },
};
export default emiiter;

MyDropdown.vue

主要暴露给用户使用的组件

<template>
  <div
    class="my-dropdown"
    @click.stop="trigger == 'click' ? (showMenu = !showMenu) : ''"
    @mouseenter="trigger == 'hover' ? (showMenu = true) : ''"
    @mouseleave="trigger == 'hover' ? (showMenu = false) : ''"
    ref="myDropDdown"
  >
    <div class="tip-text" ref="tipText">
      <slot></slot>
    </div>
    <slot name="list"></slot>
  </div>
</template>
<script>
import emitter from "./emitter";
export default {
  name: "MyDropdown",
  componentName: "MyDropdown",
  mixins: [emitter],
  props: {
    // 触发显示方式
    trigger: {
      type: String,
      default: "click",
    },
    // 下来菜单的出现位置(上方,下方)
    placement: {
      type: String,
      default: "bottom",
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ["bottom", "top"].includes(value);
      },
    },
  },
  data() {
    return {
    //控制菜单是否显示
      showMenu: false,
    };
  },
  mounted() {
      //初始化自定义事件
    this.initEvent();
  },
  methods: {
    // 初始化
    initEvent() {
    //订阅当item点击的时候,发布on-click事件,告知外部
      this.$on("item-click", (params) => {
        this.$emit("on-click", params);
        this.showMenu = false;
      });
      //空白点击要隐藏菜单,需要执行的函数需要绑定this指向
      this.handleEmptyDomElementClickBindThis =
        this.handleEmptyDomElementClick.bind(this);
      window.addEventListener("click", this.handleEmptyDomElementClickBindThis);
    },
    // 处理空白区域点击,隐藏菜单列表
    handleEmptyDomElementClick(e) {
      if (!Array.from(this.$refs.myDropDdown.childnodes).includes(e.target)) {
        this.showMenu = false;
      }
    },
  },
  beforeDestroy() {
    // 移除window上面的事件
    window.removeEventListener(this.handleEmptyDomElementClickBindThis);
  },
  watch: {
  //变化的时候,通知子组件隐藏菜单列表
    showMenu() {
      this.broadcast("MyDropdownMenu", "set-menu-status", this.showMenu);
    },
  },
};
</script>
<style lang="less">
.my-dropdown {
  position: relative;
}
</style>

MyDropdownMenu.vue

主要暴露给用户使用的组件,菜单列表组件

<template>
<!-- 涉及到高度,位移,过渡使用js钩子函数的方式比较好处理些 -->
  <transition
    @before-enter="beforeEnter"
    @enter="enter"
    @leave="leave"
    v-bind:CSS="false"
  >
    <div class="my-dropdown-menu" v-if="showMeune" ref="myDroupdownMenu">
      <slot></slot>
    </div>
  </transition>
</template>
<script>
import emitter from "./emitter";
export default {
  name: "MyDropdownMenu",
  componentName: "MyDropdownMenu",
  mixins: [emitter],
  data() {
    return {
      showMeune: false,
      timer: null,
    };
  },
  mounted() {
    this.$on("set-menu-status", (status) => {
      this.showMeune = status;
    });
  },
  methods: {
  //进入前,初始化需要过渡的属性
    beforeEnter: function (el) {
      // 初始化
      el.style.opacity = 0;
      el.style.transfORM = "scaleY(0)";
      el.style.transformOrigin = "top center";
    },
  //dom进入
    enter: function (el, done) {
    //获取文档可视区高度
      const htmlClientHeight = document.documentElement.clientHeight;
      //菜单列表相对于父元素的top偏移量
      const offsetTop = el.offsetTop;
      const scrollHeight = el.scrollHeight;
      //获取当前元素和可视区的一些长度(top,left,bottom等)
      const { bottom } = el.getBoundinGClientRect();
      // 说明底部高度不够显示菜单了,这时候我们需要调整菜单朝上面显示
      if (htmlClientHeight - bottom < scrollHeight) {
        el.style.transformOrigin = "bottom center";
        el.style.top = -(scrollHeight + 20) + "px";
      } else {
      //查看是否placement属性,是的话我们主动处理
        if (this.$parent.placement == "top") {
          el.style.transformOrigin = "bottom center";
          el.style.top = -(scrollHeight + 20) + "px";
        } else {
          el.style.top = offsetTop + "px";
        }
      }
      el.style.transform = "scaleY(1)";
      el.style.opacity = 1;
    //根据官网事例,必须在enter和leave里面调用done函数,不然过渡动画不生效(切记)
      done();
    },
    //dom元素离开 
    leave: function (el, done) {
      el.style.transform = "scaleY(0)";
      el.style.opacity = 0;
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
      //根据官网事例,必须在enter和leave里面调用done函数,不然过渡动画不生效(切记)
        done();
      }, 250);
    },
  },
};
</script>
<style lang="less">
.my-dropdown-menu {
  min-width: 100px;
  max-height: 200px;
  overflow: auto;
  margin: 5px 0;
  padding: 5px 0;
  background-color: #fff;
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 1px 6px rgb(0 0 0 / 20%);
  z-index: 900;
  transform-origin: top center;
  position: absolute;
  transition: transform 0.25s ease, opacity 0.25s ease;
}
</style>

MyDropdownItem.vue

主要暴露给用户使用的组件,菜单列表项组件,组件内容很简单,主要就是展示item数据和绑定点击事件。

<template>
  <div
    :class="[
      'my-dropdownItem',
      divided ? 'my-dropdownItem-divided' : '',
      disabled ? 'my-dropdownItem-disabled' : '',
    ]"
    @click.stop="handleItemClick"
  >
    <slot></slot>
  </div>
</template>
<script>
import emitter from "./emitter";
export default {
  name: "MyDropdownItem",
  componentName: "MyDropdownItem",
  mixins: [emitter],
  props: {
    divided: {
      type: Boolean,
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    name: {
      type: String,
      default: "",
    },
  },
  data() {
    return {};
  },
  methods: {
    handleItemClick() {
      if (this.disabled) return;
      // item项点击通知dropdown组件派发到外部的自定义事件
      this.dispatch("MyDropdown", "item-click", this.name);
    },
  },
};
</script>
<style lang="less">
.my-dropdownItem {
  margin: 0;
  line-height: normal;
  padding: 7px 16px;
  clear: both;
  color: #515a6e;
  font-size: 14px !important;
  white-space: nowrap;
  list-style: none;
  cursor: pointer;
  transition: background 0.2s ease-in-out;
  &:hover {
    background: #f3f3f3;
  }
}
.my-dropdownItem-divided {
  border-bottom: 1px solid #eee;
}
.my-dropdownItem-disabled {
  color: #cacdd2;
  cursor: not-allowed;
  &:hover {
    background: #fff;
  }
}
</style>

总结

类似组件库中的这种经常出现跨多层级组件通信,需要特殊处理,一般emitter.js文件里面的封装我们在开发中一般是用不到的,我们写组件经常也就父子组件之间,很少会跨祖孙级别,但是在组件库中,这种关系就很多,因此需要单独利用发布订阅来处理,这种模式用到实际项目里面也是很管用的。

以上就是手写实现vue2下拉菜单dropdown组件实例的详细内容,更多关于vue 下拉菜单dropdown的资料请关注编程网其它相关文章!

--结束END--

本文标题: 手写实现vue2下拉菜单dropdown组件实例

本文链接: https://www.lsjlt.com/news/165905.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 手写实现vue2下拉菜单dropdown组件实例
    目录概述最终效果(动图没显示出来,请稍定会儿,可以先看后面)实现原理具体实现目录结构emitter.jsMyDropdown.vueMyDropdownMenu.vueMy...
    99+
    2024-04-02
  • flutter实现下拉菜单组件——基于PopupMenuButton
    问题背景 客户端日常开发和学习过程,下拉菜单是一个很常见的组件,本文主要介绍flutter中实现下拉菜单组件的一个方案,基于PopupMenuButton来进行实现。 问题分析 PopupMenuButton PopupM...
    99+
    2023-10-22
    flutter android ios
  • Jquery实现下拉菜单案例
    本文实例为大家分享了Jquery实现下拉菜单的具体代码,供大家参考,具体内容如下 需要实现的结构如下图: 关于布局: 布局采用ul里面包含4个li,li里面包含a标签(微博)以及u...
    99+
    2024-04-02
  • js实现下拉菜单栏
    下面是一个基本的JavaScript实现下拉菜单栏的示例:HTML代码:```html菜单选项1选项2选项3```JavaScrip...
    99+
    2023-09-15
    JS
  • Vue2递归组件如何实现树形菜单
    小编给大家分享一下Vue2递归组件如何实现树形菜单,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!效果如下图,点击后打开二级菜单,...
    99+
    2024-04-02
  • vue实现下拉菜单效果
    本文实例为大家分享了vue实现下拉菜单效果的具体代码,供大家参考,具体内容如下 下拉菜单主要运用了hover显示与隐藏以及定位的问题 效果图: 可能出现的问题 定位后菜单的div无...
    99+
    2024-04-02
  • Bootstrap3如何实现下拉菜单
    这篇文章主要介绍了Bootstrap3如何实现下拉菜单,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。使用方法通过data属性<div&...
    99+
    2024-04-02
  • css如何实现下拉菜单
    这篇文章主要为大家展示了“css如何实现下拉菜单”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“css如何实现下拉菜单”这篇文章吧。   HTML代码:   ...
    99+
    2024-04-02
  • html如何实现下拉菜单
    小编给大家分享一下html如何实现下拉菜单,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!   元素来包裹这些元素,并使用 CS...
    99+
    2024-04-02
  • 如何使用JS组件Bootstrap实现下拉菜单效果
    这篇“如何使用JS组件Bootstrap实现下拉菜单效果”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何使用JS组件Boo...
    99+
    2023-07-04
  • css怎样实现下拉菜单
    这篇文章将为大家详细讲解有关css怎样实现下拉菜单,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。   <!DOCTYPEhtml>   <html&...
    99+
    2024-04-02
  • 原生js实现下拉菜单
    下拉菜单在实际生活中也挺常见的,它实现的js代码与tab选卡,手风琴几乎一样,在此不过多赘述。 我仿照苏宁易购官网写了一个下拉菜单,实现代码如下: <!DOCTYPE ht...
    99+
    2024-04-02
  • css怎么实现下拉菜单
    这篇文章主要介绍css怎么实现下拉菜单,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!css的全称是什么css的全称是Cascading Style Sheets(层叠样式表),它是一种用来表现HTML或XML等文件样...
    99+
    2023-06-14
  • bootstrap组件之按钮式下拉菜单的实现方法
    小编给大家分享一下bootstrap组件之按钮式下拉菜单的实现方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、单按钮下拉菜...
    99+
    2024-04-02
  • javascript实现简单下拉菜单效果
    本文实例为大家分享了 javascript实现简单下拉菜单的具体代码,供大家参考,具体内容如下 效果: 思路:比较复杂的是样式的编写,首先是ul里面含有3个li,每个li...
    99+
    2022-11-13
    js 下拉菜单
  • jquery实现简单下拉菜单效果
    本文用简单的几行jquery代码实现简单的下拉菜单效果,供大家参考,具体内容如下 看效果 html <ul>     <li>       主题市场    ...
    99+
    2024-04-02
  • 使用jquery 简单实现下拉菜单
    可以通过以下方式使用 jQuery 实现简单的下拉菜单:首先,需要在 HTML 文件中引入 jQuery 库和一个 CSS 文件来定...
    99+
    2023-08-17
    jQuery
  • 用CSS实现水平下拉菜单
    这篇文章主要介绍“用CSS实现水平下拉菜单”,在日常操作中,相信很多人在用CSS实现水平下拉菜单问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”用CSS实现水平下拉菜单”的疑惑...
    99+
    2024-04-02
  • vue3.0实现下拉菜单的封装
    vue3.0出来已经有段时间的了,也与必要开始研究它了! 先看下我们要实现的效果 很常见的展开显示菜单项的内容,在vue3.0里面怎么开发,这里样式我们用的是bootstrap的默...
    99+
    2024-04-02
  • Bootstrap3中下拉菜单事件的实现方法
    这篇文章给大家分享的是有关Bootstrap3中下拉菜单事件的实现方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。下拉菜单的事件Bootstrap为下拉菜单插件提供了 4 个事件,通过监听这些事件,可以对特定操...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作