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 遍历对象中的子对象
Jul 03 Javascript
vue2笔记 — vue-router路由懒加载的实现
Mar 03 Javascript
jquery实现tab键进行选择后enter键触发click行为
Mar 29 jQuery
Node.js+Express+MySql实现用户登录注册功能
Jul 10 Javascript
在Js页面通过POST传递参数跳转到新页面详解
Aug 25 Javascript
基于Vue框架vux组件库实现上拉刷新功能
Nov 28 Javascript
详解vue 数组和对象渲染问题
Sep 21 Javascript
vue-cli+axios实现文件上传下载功能(下载接收后台返回文件流)
May 10 Javascript
layer弹出层取消遮罩的方法
Sep 25 Javascript
浅谈Vue 函数式组件的使用技巧
Jun 16 Javascript
关于vue的列表图片选中打钩操作
Sep 09 Javascript
react+antd 递归实现树状目录操作
Nov 02 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
4月1日重磅发布!《星际争霸II》6.0.0版本更新
2020/04/09 星际争霸
PHP语法速查表
2007/01/02 PHP
收集的DedeCMS一些使用经验
2007/03/17 PHP
PHP删除HTMl标签的三种解决方法
2013/06/30 PHP
使用php自动备份数据库表的实现方法
2017/07/28 PHP
PHP基于phpqrcode类生成二维码的方法详解
2018/03/14 PHP
jQuery 联动日历实现代码
2012/05/31 Javascript
jquery实现简单易懂的图片展示小例子
2013/11/21 Javascript
js 判断控件获得焦点的示例代码
2014/03/04 Javascript
JavaScript动态改变表格单元格内容的方法
2015/03/30 Javascript
浅谈js中的in-for循环
2016/06/28 Javascript
jQuery的三种bind/One/Live/On事件绑定使用方法
2017/02/23 Javascript
nodejs Assert中equal(),strictEqual(),deepEqual(),strictDeepEqual()比较
2017/09/18 NodeJs
在React 组件中使用Echarts的示例代码
2017/11/08 Javascript
vue中node_modules中第三方模块的修改使用详解
2019/05/31 Javascript
python 图片验证码代码分享
2012/07/04 Python
python求众数问题实例
2014/09/26 Python
如何在python字符串中输入纯粹的{}
2018/08/22 Python
python 实现读取一个excel多个sheet表并合并的方法
2019/02/12 Python
python字典嵌套字典的情况下找到某个key的value详解
2019/07/10 Python
在Django model中设置多个字段联合唯一约束的实例
2019/07/17 Python
selenium+python配置chrome浏览器的选项的实现
2020/03/18 Python
python 异步async库的使用说明
2020/05/04 Python
浅谈优化Django ORM中的性能问题
2020/07/09 Python
C#基础面试题
2016/10/17 面试题
保安员岗位职责
2013/11/17 职场文书
开办加工厂创业计划书
2014/01/03 职场文书
中学生社会实践活动总结
2014/07/03 职场文书
原料仓仓管员岗位职责
2014/07/08 职场文书
学生会竞选演讲稿怎么写
2014/08/26 职场文书
见习报告的格式
2014/10/31 职场文书
司考复习计划
2015/01/19 职场文书
归途列车观后感
2015/06/17 职场文书
师范生见习自我总结
2015/06/23 职场文书
幼儿园教师读书笔记
2015/06/29 职场文书
优化经济发展环境工作总结
2015/08/11 职场文书