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 相关文章推荐
javascript实现的listview效果
Apr 28 Javascript
jquery选择符快速提取web表单数据示例
Mar 27 Javascript
原生js实现的贪吃蛇网页版游戏完整实例
May 18 Javascript
JQuery中DOM实现事件移除的方法
Jun 13 Javascript
浅谈jQuery中setInterval()方法
Jul 07 Javascript
Bootstrap的基本应用要点浅析
Dec 19 Javascript
基于Vue过渡状态实例讲解
Sep 14 Javascript
详解angular2.x创建项目入门指令
Oct 11 Javascript
代码实例ajax实现点击加载更多数据图片
Oct 12 Javascript
Vue 使用beforeEach实现登录状态检查功能
Oct 31 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
Nov 01 jQuery
用jQuery实现抽奖程序
Apr 12 jQuery
微信小程序 行的删除和增加操作实现详解
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(1) php开发环境配置
2010/02/15 PHP
PHP备份数据库生成SQL文件并下载的函数代码
2012/02/05 PHP
php调用MySQL存储过程的方法集合(推荐)
2013/07/03 PHP
PHP实现的统计数据功能详解
2016/12/06 PHP
统一接口:为FireFox添加IE的方法和属性的js代码
2007/03/25 Javascript
JavaScript的document对象和window对象详解
2010/12/30 Javascript
javascript继承之为什么要继承
2012/11/10 Javascript
toggle()隐藏问题的解决方法
2014/02/17 Javascript
js加减乘除丢失精度问题解决方法
2014/05/16 Javascript
JavaScript中常见的字符串操作函数及用法汇总
2015/05/04 Javascript
jQuery 获取遍历获取table中每一个tr中的第一个td的方法
2016/10/05 Javascript
工作中常用的js、jquery自定义扩展函数代码片段汇总
2016/12/22 Javascript
JQuery实现定时刷新功能代码
2017/05/09 jQuery
单行 JS 实现移动端金钱格式的输入规则
2017/05/22 Javascript
微信小程序多张图片上传功能
2017/06/07 Javascript
VUE实现表单元素双向绑定(总结)
2017/08/08 Javascript
Node.js引入UIBootstrap的方法示例
2018/05/11 Javascript
vue多页面项目中路由使用history模式的方法
2019/09/23 Javascript
python实现的文件夹清理程序分享
2014/11/22 Python
详解python中asyncio模块
2018/03/03 Python
python编写暴力破解zip文档程序的实例讲解
2018/04/24 Python
利用Python如何制作好玩的GIF动图详解
2018/07/11 Python
python 切换root 执行命令的方法
2019/01/19 Python
Python里字典的基本用法(包括嵌套字典)
2019/02/27 Python
OpenCV模板匹配matchTemplate的实现
2019/10/18 Python
Python实现动态给类和对象添加属性和方法操作示例
2020/02/29 Python
Python语法垃圾回收机制原理解析
2020/03/25 Python
通过代码简单了解django model序列化作用
2020/11/12 Python
澳大利亚在线床零售商:Bedworks
2020/09/01 全球购物
家长给老师的道歉信
2014/01/13 职场文书
自行车广告词大全
2014/03/21 职场文书
企业安全标语
2014/06/07 职场文书
乡镇创先争优活动总结
2014/08/28 职场文书
单位租房协议书范本
2014/12/04 职场文书
新郎婚礼答谢词
2015/01/04 职场文书
Python基础之赋值,浅拷贝,深拷贝的区别
2021/04/30 Python