2 个回答

首先可以将菜单封装成一个组件,然后在组件中实现相关逻辑,以减少模板代码。


要实现点击菜单外空白区域关闭菜单的功能,在uni-app开发中的实现大致可以分为 只兼容web端兼容所有端 两种方式。

  1. 由于web端可以直接访问 document,所以可以直接监听 documentclick 事件,然后判断当前点击的 target 是否包含在菜单范围中,如果不在的话就关闭菜单,示例如下:
export default {
  name: "DemoDropdown",
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    innerVisible: {
      get() {
        return this.visible;
      },
      set(value) {
        this.$emit("update:visible", value);
      }
    }
  },
  watch: {
    innerVisible: {
      handler(visible) {
        // 菜单弹出后开始监听document的click事件,关闭后移除监听
        if (visible) {
          this.createDocumentClickListener();
        } else {
          this.removeDocumentClickListener();
        }
      },
      immediate: true
    }
  },
  beforeDestroy() {
    this.removeDocumentClickListener();
  },
  methods: {
    createDocumentClickListener() {
      setTimeout(() => {
        document.documentElement.addEventListener("click", this.documentClickHandler);
      }, 100);
    },
    removeDocumentClickListener() {
      document.documentElement.removeEventListener("click", this.documentClickHandler);
    },
    documentClickHandler(event) {
      // 点击元素不包含在菜单范围中 -> 关闭菜单
      if (!this.$el.contains(event.target)) {
        this.innerVisible = false;
      }
    }
  }
};
  1. 由于部分端不能直接访问 document(或者是没有 document 的概念,例如小程序端、App端等),我们可以手动在菜单下方添加一个透明的全屏蒙层,当点击蒙层时执行关闭菜单的操作,示例如下:
<template>
  <view class="demo-dropdown">
    <view class="demo-dropdown__modal" @tap="innerVisible = false"></view>

    <view class="demo-dropdown__inner">
      <!-- 菜单内容 -->
    </view>
  </view>
</template>
.demo-dropdown__modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 10;
}

.demo-dropdown__inner {
  position: relative;
  // ...其他样式
  z-index: 12;
}

借鉴 vueUse 里面 onClickOutside 的实现就好了,就是不知道打包成App之后还能不能用,小程序应该没啥问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题