(Vue)阻止冒泡事件之下拉菜单的实现

本文通过一个具体的Vue下拉菜单实例,详细解析了事件冒泡的概念及其解决方法。针对冒泡导致的菜单关闭失败问题,给出了使用`.stop`修饰符的解决方案。

这是本人作为程序媛的第一篇博客,如有出现纰漏的地方,请各位大佬不吝赐教!!!

1、(Vue)事件冒泡

所谓的事件冒泡,即事件由子元素传递给父元素的过程称之为事件的冒泡
如:在两个div中,外层div嵌套着一个子div,并相应的给父(div)与子(div)分别添加click事件。当触发子(div)的click事件时,父级的click事件也会相应的触发。这易导致页面展现效果出现错乱。
在此,我以下拉菜单的实例进行阐述所遇到的事件冒泡问题,以及该如何去进行解决事件的冒泡!
实现效果图:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.1(Vue)事件冒泡实例

在该实例中,父级div点击事件为:“showMenuListUl()”,子级中的点击事件为li中的"clickPayMethod(item.id)"。当点击菜单栏时进行下拉菜单的展示,当选中下拉菜单的子选项时,对下拉菜单进行相应的隐藏。但由于事件的冒泡,对下拉菜单的子选项进行完相应的选择之后,无法对下拉菜单进行相应的隐藏。

     <div class="selectBody" @click="showMenuListUl">
        <span><img :src="showMenuList[index].imgpath" alt="logo" /></span>
        <span><input type="button" v-model="inputtext" /></span>
        <span>
          <img v-show="showdown" src="@/assets/down.svg" alt="down">
          <img v-show="!showdown" src="@/assets/up.svg" alt="up">
        </span>
        <div class="selectBodyUl" v-show="showSelectBodyUl">
          <ul>
            <li v-for="item in showMenuList"
              :key="item.index"
              @click="clickPayMethod(item.id)"
              :class="item.id == selected ? 'selected' : ''">
              <span><img :src="item.imgpath"></span>
              <span>{{item.name}}</span>
            </li>
          </ul>
        </div>
      </div>

1.2(Vue)事件冒泡实例的解决

解决方案: 为子级的click事件添加“.stop”,如下代码所示,将li中的@click="clickPayMethod(item.id)"更改为@click.stop=“clickPayMethod(item.id)

<div class="selectBody" @click="showMenuListUl">
        <span><img :src="showMenuList[index].imgpath" alt="logo" /></span>
        <span><input type="button" v-model="inputtext" /></span>
        <span>
          <img v-show="showdown" src="@/assets/down.svg" alt="down">
          <img v-show="!showdown" src="@/assets/up.svg" alt="up">
        </span>
        <div class="selectBodyUl" v-show="showSelectBodyUl">
          <ul>
            <li v-for="item in showMenuList"
              :key="item.index"
              @click.stop="clickPayMethod(item.id)"
              :class="item.id == selected ? 'selected' : ''">
              <span><img :src="item.imgpath"></span>
              <span>{{item.name}}</span>
            </li>
          </ul>
        </div>
      </div>

2、(Vue)下拉菜单实现过程完整代码

<template>
  <div class="selectMenu">
    <div class="selectMenuContainer">
      <h1>Vue下拉菜单功能的实现</h1>
      <div class="selectBody" @click="showMenuListUl">
        <span><img :src="showMenuList[index].imgpath" alt="logo" /></span>
        <span><input type="button" v-model="inputtext" /></span>
        <span>
          <img v-show="showdown" src="@/assets/down.svg" alt="down">
          <img v-show="!showdown" src="@/assets/up.svg" alt="up">
        </span>
        <div class="selectBodyUl" v-show="showSelectBodyUl">
          <ul>
            <li v-for="item in showMenuList"
              :key="item.index"
              @click.stop="clickPayMethod(item.id)"
              :class="item.id == selected ? 'selected' : ''">
              <span><img :src="item.imgpath"></span>
              <span>{{item.name}}</span>
            </li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</template>

```html
<script>
export default {
  name: 'test',
  data () {
    return {
      inputtext: '',
      itemimg: '',
      index: 0,
      showdown: true,
      selected: 0,
      showSelectBodyUl: false,
      showMenuList: [{
        id: 0,
        name: '微信',
        imgpath: require('@/assets/wechat.svg')
      }, {
        id: 1,
        name: '银行卡',
        imgpath: require('@/assets/bank.svg')
      }, {
        id: 2,
        name: '支付宝',
        imgpath: require('@/assets/paypal.svg')
      }]
    }
  },
  methods: {
    clickPayMethod (id1) {
      this.index = id1
      this.inputtext = this.showMenuList[id1].name
      this.selected = id1
      this.showSelectBodyUl = false
      this.showdown = true
    },
    showMenuListUl () {
      this.showSelectBodyUl = !this.showSelectBodyUl
      this.showdown = false
    }
  },
  created() {
    this.inputtext = this.showMenuList[0].name
  }
}
</script>
<style lang="less" scoped>
  .selectMenu {
    margin: 0;
    padding: 0;
    .selectMenuContainer {
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      .selectBody {
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 5px;
        border: 1px solid oldlace;
        border-radius: 2px;
        box-shadow: 1px 1px 0px 1px #f3f3f3;
        position: relative;
        cursor: pointer;
        img {
          width: 24px;
          height: 24px;
          align-items: center;
        }
        input {
          border: none;
          background: none;
          width: 150px;
          outline: none;
          cursor: pointer;
        }
      }
      .selectBodyUl {
        width: 205px;
        margin-top: 10px;
        text-align: left;
        border: 1px solid oldlace;
        border-radius: 2px;
        box-shadow: 1px 1px 0px 1px #f3f3f3;
        position: absolute;
        right: 0;
        top: 35px;
        ul {
          list-style-type: none;
          display: flex;
          flex-direction: column;
          align-items: center;
          margin: 0;
          padding: 0;
          li {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 30px;
            &:not(:last-child) {
              margin-bottom: 5px;
            }
            span {
              display: flex;
              align-items: center;
            }
          }
          li:hover {
            background: cornsilk;
          }
          .selected {
            background: cornsilk;
          }
          img {
            width: 24px;
            height: 24px;
            margin-right: 5px;
          }
        }
      }
    }
  }
</style>
### Vue实现点击文字后在下方弹出可选菜单 为了实现Vue 应用中点击某个特定的文字后,在该文字的正下方显示一个可选项菜单,可以采用如下方法: #### 使用 `v-if` 或者 `v-show` 通过绑定布尔变量来控制子组件(即菜单)的可见性。当用户点击目标文本时,改变这个布尔值的状态。 ```html <template> <div class="container"> <!-- 主要展示区域 --> <p @click="toggleMenu">点击这里</p> <!-- 动态显示/隐藏的菜单部分 --> <ul v-if="isMenuVisible" style="position:absolute; margin-top:0px;"> <li>选项一</li> <li>选项二</li> <li>选项三</li> </ul> </div> </template> <script> export default { data() { return { isMenuVisible: false, }; }, methods: { toggleMenu(event) { this.isMenuVisible = !this.isMenuVisible; // 阻止冒泡传播到其他监听器上, 这样就不会意外关闭菜单. event.stopPropagation(); document.addEventListener('click', (e)=>{ if (!event.target.contains(e.target)) { this.closeMenu(); } }); }, closeMenu(){ this.isMenuVisible=false; document.removeEventListener('click'); } } }; </script> ``` 上述代码片段展示了如何利用 Vue 的条件渲染指令 (`v-if`) 来管理 DOM 元素的存在与否,并且处理了鼠标点击事件以切换菜单状态[^1]。 另外需要注意的是,为了让菜单能够准确地位于触发它的元素之下,可能还需要适当调整 CSS 样式中的定位属性以及 z-index 属性等设置。 对于更复杂的交互需求,比如带有动画效果或者其他样式定制化的要求,则建议考虑使用第三方库如 Element UI 或 Ant Design Vue 提供的相关组件来进行开发。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值