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 相关文章推荐
EASYUI TREEGRID异步加载数据实现方法
Aug 22 Javascript
javascript 正则表达式相关应介绍
Nov 27 Javascript
jquery分页插件jpaginate在IE中不兼容问题
Apr 22 Javascript
Js实现网页键盘控制翻页的方法
Oct 30 Javascript
js实现文字在按钮上滚动的方法
Aug 20 Javascript
js+CSS实现模拟华丽的select控件下拉菜单效果
Sep 01 Javascript
详解JavaScript的流程控制语句
Nov 30 Javascript
jQuery向父辈遍历的简单方法
Sep 18 Javascript
canvas绘制多边形
Feb 24 Javascript
详解如何让InstantClick兼容MathJax、百度统计等
Sep 12 Javascript
IE8中jQuery.load()加载页面不显示的原因
Nov 15 jQuery
详解使用React.memo()来优化函数组件的性能
Mar 19 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 array_pop()数组函数将数组最后一个单元弹出(出栈)
2011/07/12 PHP
通过table标签,PHP输出EXCEL的实现方法
2013/07/24 PHP
Laravel5中contracts详解
2015/03/02 PHP
PHP动态柱状图实现方法
2015/03/30 PHP
在WordPress中使用wp-cron插件来设置定时任务
2015/12/10 PHP
PHP7新特性foreach 修改示例介绍
2016/08/26 PHP
Zend Framework基于Command命令行建立ZF项目的方法
2017/02/18 PHP
php7连接MySQL实现简易查询程序的方法
2020/10/13 PHP
IE中jscript/javascript的条件编译
2006/09/07 Javascript
ext 列表页面关于多行查询的办法
2010/03/25 Javascript
JQuery对表格进行操作的常用技巧总结
2014/04/23 Javascript
在JavaScript中处理时间之getHours()方法的使用
2015/06/10 Javascript
javascript html5实现表单验证
2016/03/01 Javascript
javascript replace()第二个参数为函数时的参数用法
2016/12/26 Javascript
利用Promise自定义一个GET请求的函数示例代码
2019/03/20 Javascript
node.js使用net模块创建服务器和客户端示例【基于TCP协议】
2020/02/14 Javascript
JS错误处理与调试操作实例分析
2020/04/13 Javascript
[03:28]2014DOTA2国际邀请赛 走近EG战队天才中单Arteezy
2014/07/12 DOTA
windows下python 3.6.4安装配置图文教程
2018/08/21 Python
python3通过selenium爬虫获取到dj商品的实例代码
2019/04/25 Python
python实现屏保程序(适用于背单词)
2019/07/30 Python
JDO的含义
2012/11/17 面试题
护理专业本科生自荐信
2013/10/01 职场文书
机械化及自动化毕业生的自我评价分享
2013/11/06 职场文书
单位单身证明范本
2014/01/11 职场文书
商务日语专业毕业生自荐信
2014/03/27 职场文书
干部竞争上岗演讲稿
2014/09/11 职场文书
2014年酒店工作总结范文
2014/11/17 职场文书
党支部意见范文
2015/06/02 职场文书
同学聚会祝酒词
2015/08/10 职场文书
Python 文本滚动播放器的实现代码
2021/04/25 Python
MySQL之PXC集群搭建的方法步骤
2021/05/25 MySQL
Pytorch中Softmax与LogSigmoid的对比分析
2021/06/05 Python
基于PyQT5制作一个桌面摸鱼工具
2022/02/15 Python
gojs实现蚂蚁线动画效果
2022/02/18 Javascript
vue实现列表垂直无缝滚动
2022/04/08 Vue.js