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 相关文章推荐
html读出文本文件内容
Jan 22 Javascript
jQuery函数的第二个参数获取指定上下文中的DOM元素
May 19 Javascript
使用jquery解析XML示例代码
Sep 05 Javascript
js实现div层缓慢收缩与展开的方法
May 11 Javascript
JavaScript中setMonth()方法的使用详解
Jun 11 Javascript
node模块机制与异步处理详解
Mar 13 Javascript
js中获取时间new Date()的全面介绍
Jun 20 Javascript
jQuery实现下拉菜单动态添加数据点击滑出收起其他功能
Jun 14 jQuery
vue ssr 实现方式(学习笔记)
Jan 18 Javascript
Vue实现商品分类菜单数量提示功能
Jul 26 Javascript
js遍历详解(forEach, map, for, for...in, for...of)
Aug 28 Javascript
javascript设计模式 ? 状态模式原理与用法实例分析
Apr 22 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
用Apache反向代理设置对外的WWW和文件服务器
2006/10/09 PHP
php checkbox 取值详细说明
2010/08/19 PHP
在PHP中使用curl_init函数的说明
2010/11/02 PHP
php自定义类fsocket模拟post或get请求的方法
2015/07/31 PHP
PHP实现将MySQL重复ID二维数组重组为三维数组的方法
2016/08/01 PHP
解决php扩展安装不生效问题
2019/10/25 PHP
PHP 面向对象程序设计之类属性与类常量实现方法分析
2020/04/13 PHP
通过继承IHttpHandle实现JS插件的组织与管理
2010/07/13 Javascript
21个JavaScript事件(Events)属性汇总
2014/12/02 Javascript
JavaScript实现的一个计算数字步数的算法分享
2014/12/06 Javascript
浅谈JavaScript中的String对象常用方法
2015/02/25 Javascript
灵活的理解JavaScript中的this指向
2016/02/25 Javascript
JavaScript检测原始值、引用值、属性
2016/06/20 Javascript
js与jquery正则验证电子邮箱、手机号、邮政编码的方法
2016/07/04 Javascript
Node.js中防止错误导致的进程阻塞的方法
2016/08/11 Javascript
深入理解bootstrap框架之第二章整体架构
2016/10/09 Javascript
微信小程序-消息提示框实例
2016/11/24 Javascript
JS和canvas实现俄罗斯方块
2017/03/14 Javascript
实例详解display:none与visible:hidden的区别
2017/03/30 Javascript
详解plotly.js 绘图库入门使用教程
2018/02/23 Javascript
js Element Traversal规范中的元素遍历方法
2018/04/19 Javascript
基于Angular 8和Bootstrap 4实现动态主题切换的示例代码
2020/02/11 Javascript
python3写爬取B站视频弹幕功能
2017/12/22 Python
Django中间件基础用法详解
2019/07/18 Python
django框架模板语言使用方法详解
2019/07/18 Python
django认证系统实现自定义权限管理的方法
2019/08/28 Python
Pytorch之Variable的用法
2019/12/31 Python
CSS3只让背景图片旋转180度的实现示例
2021/03/09 HTML / CSS
英国健身专家:WIT Fitness
2021/02/09 全球购物
薪酬专员岗位职责
2014/02/18 职场文书
库房保管员岗位职责
2014/04/07 职场文书
热爱祖国演讲稿
2014/05/04 职场文书
群众路线教育实践活动的心得体会
2014/09/03 职场文书
手机销售员岗位职责
2015/04/11 职场文书
导游词之永泰公主墓
2019/12/04 职场文书
python用tkinter开发的扫雷游戏
2021/06/01 Python