一个简单的效果,点击导航栏弹出菜单后,在菜单外点击触发失焦,自动关闭菜单


本文采用Vant组件
核心:通过触发菜单内的input聚焦失焦控制显示/隐藏

导航栏:

<van-nav-bar title="导航栏" left-arrow @click="handleRight">    <van-icon name="ellipsis" v-slot:right /></van-nav-bar>

菜单:

<div v-show="isShowMenu" class="nav-menu">    <ul>        <li v-for="item in menuList"             :key="item"            @click="handleMenu(item)">{{ item }}</li>    </ul>    <input ref="MenuInput" type="text" @blur="menuBlur" /></div>
.nav-menu{    position: fixed;    top: 40px;    right: 5px;    input{        position: absolute;        left: 0;        bottom: 0;        width: 0;        height: 0;        margin: 0;        border: none;        outline: 0;        opacity: 0;        -webkit-appearence: none;    }}

事件:

export default{    name: 'custom-nav',    data(){        return {            isShowMenu: false,// 控制菜单            menuList: ['操作1', '操作2'],// 菜单        }    },    methods: {        handleMenu(item){// 点击菜单项            console.log(item)        },        menuBlur(){// 输入框失焦 =》 隐藏菜单            this.isShowMenu = false        },        handleRight(){// 点击导航栏右侧            this.isShowMenu = !this.isShowMenu            // trigger焦点            this.$nextTick(() => {                if(this.$refs.MenuInput){                    this.$refs.MenuInput.focus()                }else{                    this.$refs.MenuInput.blur()                }            })        }    }}

问题:

  1. 菜单栏点击事件handleMenu与输入框失焦menuBlur冲突

    由于js是单线程,所以两者无法同时进行,加个延迟

    menuBlur(){    setTimeout(() => {        this.isShowMenu = false;    }, 100)}
  2. 输入框聚焦同时弹出键盘
    如果把input类型设置为hidden反而不能聚焦,所以加个只读属性readonly

    <input ref="MenuInput" readonly type="text" @blur="menuBlur" />
  3. 其他组件同时出发失焦事件
    在用ElementUI的日期选择器时,其自带的@blur会上浮,不知道算不算bug。
    此处带上事件修饰符可解决

    <el-date-picker @blur.native.capture="pickerBlur"></el-date-picker>