2

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


本文采用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>

Shyla
1.5k 声望148 粉丝

FE programmer