js 下拉菜单点击旁边收起实现(踩坑记)


Posted in Javascript onSeptember 29, 2019

背景:

最近在搞一个需求:搜索框,输入时显示联想词下拉列表,当点击联想词跳转到搜索页,如果点击其他部分收起联想的下拉列表。接到需求后第一反应用失焦(blur)去做收起操作避免body的监控,随后就踩坑里了,下面情景再现,一步一步来看这个问题的解决(里面的demo等会用vue实现)

带有bug的版本演示图

js 下拉菜单点击旁边收起实现(踩坑记)

备注:最后的搜索跳转我直接用console代替掉了,但是并没有执行

问题抛出

当我点击上面的联想词的时候它的onSearch并不能执行

demo代码展示

<template lang="html">
<div :class="[baseClass + '-wrap']">
 <input
  type="text"
  v-model="searchVal"
  :class="[baseClass + '-input']"
  ref="demo-search-input"
  placeholder="搜索"
  @focus="onFoucs"
  @blur="onBlur"
  @keyup.enter="onSearch"
  @input="getRecommendedList" />
 <span :class="[baseClass + '-btn']" @click="onSearch"></span>
 <div :class="[baseClass + '-recommended']" v-show="isShowRecommend && recommendList.length > 0">
  <div :class="[baseClass + '-triangle-border', baseClass + '-tb-border']"></div>
  <div :class="[baseClass + '-triangle-border', baseClass + '-tb-bg']"></div>
  <ul :class="[baseClass + '-list-wrap']">
   <li
    :class="[baseClass + '-list']"
    v-for="(item, index) in recommendList"
    :key="index"
    @click="onSearch(item)"
   >{{item}}</li>
  </ul>
 </div>
</div>
</template>
<script>
const mockData = ['123456', '12', '56873', '092341', '454666677']
export default {
 data () {
  return {
   baseClass: 'demo-search',
   searchVal: '',
   isShowRecommend: false,
   recommendList: []
  }
 },
 methods: {
  onFoucs () {
   this.isShowRecommend = true
  },
  onBlur () {
   this.isShowRecommend = false
   this.searchVal = ''
   this.recommendList = []
  },
  onSearch (val) {
   val = typeof val === 'string' ? val : this.searchVal
   if (val) {
    // 这里需要跳转搜索,我们用console来代替
    console.log(val)
    this.searchVal = ''
   } else {
    this.$refs['demo-search-input'].focus()
   }
  },
  getRecommendedList () {
   if (this.searchVal) {
    // 这里需要给后台发送请求来获取联想词,这里我们用mock数据匹配来展示
    setTimeout(() => {
     const reg = new RegExp(this.searchVal)
     const arr = []
     for (let i = 0; i < mockData.length; i++) {
      if (reg.test(mockData[i])) {
       arr.push(mockData[i])
      }
     }
     this.recommendList = arr
    }, 10)
   }
  }
 }
}
</script>

上面就是我们这个效果的代码了,根据逻辑来看我们在input上面绑定了blur事件来控制清空搜索和收起联想词下拉列表,同时给list绑定了click事件,我们的预期是点击list的时候console执行然后input失去焦点收起来,但是事实是它仅仅执行了blur,onSearch事件里面的console并未执行。

猜测原因做尝试

首先第一反应绝对是事件的触发顺序,所以我就想到了利器setTimeout来验证

onBlur () {
 setTimeout(() => {
  this.isShowRecommend = false
  this.searchVal = ''
  this.recommendList = []
 }, 500)
}

结果果然触发了,因为延迟了blur先执行了click。但是当我们点击其他区域的时候下拉窗口需要停顿一会再消失,这个很诡异,所以继续想办法调整。

分析:

  1. 现在确认是事件的优先级的问题了,blur要优先于click所以我们需要想办法替换掉click
  2. 我们知道click事件是由mousedown事件和mouseup事件组成,同时mousedown和mouseup触发必须在同一个像素点上才会触发click事件。即鼠标点击: mousedown -> mouseup -> click
  3. 所以我们来写一个demo看一下事件的执行顺序
methods: {
  onClick () {
   console.log('click')
  },
  onMousedown () {
   console.log('mousedown')
  },
  onMouseup () {
   console.log('mouseup')
  },
  onBlur () {
   console.log('blur')
  }
}

结果

 js 下拉菜单点击旁边收起实现(踩坑记)

最后把click替换成mousedown,完成了问题修复

<li
 :class="[baseClass + '-list']"
 v-for="(item, index) in recommendList"
 :key="index"
 @mousedown="onSearch(item)"
>{{item}}</li>

最终效果展示

js 下拉菜单点击旁边收起实现(踩坑记)

好了今天的踩坑和填坑运动结束,以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用js简单实现了tree树菜单
Nov 20 Javascript
使用命令对象代替switch语句的写法示例
Feb 28 Javascript
JavaScript操作cookie类实例
Mar 31 Javascript
包含中国城市的javascript对象实例
Aug 03 Javascript
JavaScript兼容浏览器FF/IE技巧
Aug 14 Javascript
javascript数组去重常用方法实例分析
Apr 11 Javascript
jquery实现异步加载图片(懒加载图片一种方式)
Apr 24 jQuery
JS获取input[file]的值并显示在页面的实现方法
Mar 09 Javascript
vue 注册组件的使用详解
May 05 Javascript
vue项目中使用Svg的方法
Oct 24 Javascript
如何在JavaScript中优雅的提取循环内数据详解
Mar 04 Javascript
基于JS实现父组件的请求服务过程解析
Oct 14 Javascript
微信小程序 行的删除和增加操作实现详解
Sep 29 #Javascript
微信小程序 轮播图实现原理及优化详解
Sep 29 #Javascript
为nuxt项目写一个面包屑cli工具实现自动生成页面与面包屑配置
Sep 29 #Javascript
React-redux实现小案例(todolist)的过程
Sep 29 #Javascript
关于layui 实现点击按钮添加一行(方法渲染创建的table)
Sep 29 #Javascript
在Layui中实现开关按钮的效果实例
Sep 29 #Javascript
layui之数据表格--与后台交互获取数据的方法
Sep 29 #Javascript
You might like
如何使用PHP获取网络上文件
2006/10/09 PHP
基于PHP+jQuery+MySql实现红蓝(顶踩)投票代码
2015/08/25 PHP
详解WordPress中分类函数wp_list_categories的使用
2016/01/04 PHP
php自动加载代码实例详解
2021/02/26 PHP
在网页中控制wmplayer播放器
2006/07/01 Javascript
广告切换效果(缓动切换)
2009/05/27 Javascript
Jquery实现三层遍历删除功能代码
2013/04/23 Javascript
jQuery中Form相关知识汇总
2015/01/06 Javascript
jquery拖动层效果插件用法实例分析(附demo源码)
2016/04/28 Javascript
深入理解angularjs过滤器
2016/05/25 Javascript
Google 地图API Map()构造器详解
2016/08/06 Javascript
RequireJS 依赖关系的实例(推荐)
2017/01/21 Javascript
详解基于Vue+Koa的pm2配置
2017/10/24 Javascript
JS实现json对象数组按对象属性排序操作示例
2018/05/18 Javascript
LayerClose弹窗关闭刷新方法
2018/08/17 Javascript
JQuery实现简单的复选框树形结构图示例【附源码下载】
2019/07/16 jQuery
layer更改皮肤的实现方法
2019/09/11 Javascript
Javascript confirm多种使用方法解析
2020/09/25 Javascript
[06:38]DOTA2怒掀电竞风暴 2013Chinajoy
2013/07/27 DOTA
python模拟登陆,用session维持回话的实例
2018/12/27 Python
解决pycharm remote deployment 配置的问题
2019/06/27 Python
使用python把xmind转换成excel测试用例的实现代码
2020/10/12 Python
HTML5 Canvas概述
2009/08/26 HTML / CSS
美国新蛋IT数码商城:Newegg.com
2016/07/21 全球购物
草莓网英国官网:Strawberrynet UK
2017/02/12 全球购物
华为俄罗斯官方网上商城:购买Huawei手机和平板
2017/04/21 全球购物
YOOX台湾:意大利奢侈品电商
2018/10/13 全球购物
网上快餐厅创业计划书
2014/02/01 职场文书
小学教师办公室制度
2014/02/03 职场文书
贫困生助学金感谢信
2015/01/21 职场文书
2015毕业寄语大全
2015/02/26 职场文书
道歉信怎么写
2015/05/12 职场文书
Python入门之基础语法详解
2021/05/11 Python
使用springMVC所需要的pom配置
2021/09/15 Java/Android
Win11 引入 Windows 365 云操作系统,适应疫情期间混合办公模式:启动时直接登录、模
2022/04/06 数码科技
xhunter1.sys可以删除嘛? win11提示xhunter1.sys驱动不兼容解决办法
2022/09/23 数码科技