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 相关文章推荐
Jquery+ajax请求data显示在GridView上(asp.net)
Aug 27 Javascript
javascript宿主对象之window.navigator详解
Sep 07 Javascript
VueJS全面解析
Nov 10 Javascript
jQuery与js实现颜色渐变的方法
Dec 30 Javascript
js实现年月日表单三级联动
Apr 17 Javascript
详解react-webpack2-热模块替换[HMR]
Aug 03 Javascript
JS实现电商放大镜效果
Aug 24 Javascript
jquery实现企业定位式导航效果
Jan 01 jQuery
100行代码实现一个vue分页组功能
Nov 06 Javascript
关于vue-cli 3配置打包优化要点(推荐)
Apr 22 Javascript
浅谈nuxtjs校验登录中间件和混入(mixin)
Nov 06 Javascript
Vue开发中常见的套路和技巧总结
Nov 24 Vue.js
微信小程序 行的删除和增加操作实现详解
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
ajax+php打造进度条 readyState各状态
2010/03/20 PHP
php学习笔记 数组遍历实现代码
2011/06/09 PHP
php中实现字符串翻转的方法
2017/02/22 PHP
PHP APP微信提现接口代码
2018/09/30 PHP
PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
2020/02/16 PHP
理解Javascript_13_执行模型详解
2010/10/20 Javascript
通过一段代码简单说js中的this的使用
2013/07/23 Javascript
angular2使用简单介绍
2016/03/01 Javascript
bootstrap-datetimepicker实现只显示到日期的方法
2016/11/25 Javascript
js实现手机拍照上传功能
2017/01/17 Javascript
解决JavaScript layui 下拉框不显示的问题
2018/08/14 Javascript
详解Vue依赖收集引发的问题
2019/04/22 Javascript
微信小程序系列之自定义顶部导航功能
2019/05/21 Javascript
jquery实现直播视频弹幕效果
2020/02/25 jQuery
[02:38]2018年度DOTA2最佳劣单位选手-完美盛典
2018/12/17 DOTA
python目录与文件名操作例子
2016/08/28 Python
Python面向对象类的继承实例详解
2018/06/27 Python
分享vim python缩进等一些配置
2018/07/02 Python
python 格式化输出百分号的方法
2019/01/20 Python
python shutil文件操作工具使用实例分析
2019/12/25 Python
Python使用Tkinter实现转盘抽奖器的步骤详解
2020/01/06 Python
使用 PyTorch 实现 MLP 并在 MNIST 数据集上验证方式
2020/01/08 Python
OpenCV哈里斯(Harris)角点检测的实现
2020/01/15 Python
Django Xadmin多对多字段过滤实例
2020/04/07 Python
Python多线程正确用法实例解析
2020/05/30 Python
浅谈Python程序的错误:变量未定义
2020/06/02 Python
python 下载文件的多种方法汇总
2020/11/17 Python
秋季运动会通讯稿
2014/01/24 职场文书
留学推荐信写作指南
2014/01/25 职场文书
课堂教学改革实施方案
2014/03/17 职场文书
竞选学委演讲稿
2014/09/13 职场文书
2015年中个人总结范文
2015/03/10 职场文书
地雷战观后感
2015/06/09 职场文书
怎样评估创业计划书是否有可行性?
2019/08/07 职场文书
导游词之镇江西津古渡
2019/11/06 职场文书
vue+elementui 实现新增和修改共用一个弹框的完整代码
2021/06/08 Vue.js