• 下拉框click事件与搜索框blur事件的爱恨纠葛


    还原车祸现场

    功能类似于百度搜索,搜索框输入内容,下拉框显示候选项,点击候选项就选择候选项,然后下拉框隐藏,点击外面就直接隐藏下拉框,于是我写了以下代码

    //参会单位联想
    $('input[name="company_name"]').bind('input propertychange', function() {
        var _this = this;
        clearTimeout(this.timer);
        this.timer = setTimeout(function(){
            $.ajax({
                url:domin+'/api/company/index',
                data:{
                    k:_this.value
                },
                dataType:'jsonp',
                success:function(res){
                    if(res.status.code==0){
                        if(res.data.length<=0) return false;
                        var str = "";
                        res.data.forEach(function(e,i){
                            str += '<dd data-value="'+e.id+'" data-type="'+e.role_code+'" class="">'+e.name+'</dd>';
                        })
                        $('#company_list').html(str);
                        $(_this).parent().addClass('layui-form-selected');
                    }else {
                        form.val("beforehand", {
                            "company-type": "",
                        });
                    }
                }
            })
        }, 1000);
        $('#company_list').on('click','dd',function(){
            _this.value = this.innerHTML;
            postData.company_id = $(this).data('value');
            form.val("beforehand", {
                "company-type": company_type[$(this).data('type')]?company_type[$(this).data('type')]:"普通",
            });
            $(_this).parent().removeClass('layui-form-selected');
            $(this).parent().html('');
            isSelect = false;
        })
    });
    $('input[name="company_name"]').blur(function(ev){
      $('input[name="company_name"]').parent().removeClass('layui-form-selected');
    })

    先去请求数据,然后渲染列表,然后监听候选项点击,最后blur的时候隐藏下拉框,觉得自己写的很完美,于是便兴冲冲的去测试,但是一测试我发现了大问题,在我点击列表项也就是 dd 的时候,下拉框直接隐藏了,候选项的内容也没有被填到input里面去。我便很费解,于是便去找度娘玩耍,众说纷纭,我在很多胡扯的评论中终于找到了。总结如下,看看完整的步骤

    1. 点击 dd ,此时先触发 mousedown 
    2.  input 的 blur 触发
    3. 下拉框消失
    4. 此时鼠标抬起并不是在下拉框上
    5.  dd 的 click 并没有触发

    解决方案

    1. 监听的documentmouseup而不是inputblur事件,这样先触发ddmouseup,此时数据就已经取到,然后冒泡到document,移除下拉框(类似于百度搜索)
    2. 监听ddmousedown,这也会先取值,然后input再失焦(体验不太好,用户按下就会触发,不允许纠结,比如我按下第一个的时候,突然想选择第二个)
    3. dd还是,input还是blur,全局定义一个isSelect变量,监听dlmousedown 触发以后修改isSelect = true ,这样在blur时,先判断isSelect 就好了。(代码如下)
    var isSelect = false;
    // some code
        $('#company_list').on('click','dd',function(){
        _this.value = this.innerHTML;
        postData.company_id = $(this).data('value');
        form.val("beforehand", {
          "company-type": company_type[$(this).data('type')]?company_type[$(this).data('type')]:"普通",
        });
        $(_this).parent().removeClass('layui-form-selected');
        $(this).parent().html('');
        isSelect = false; //++
      })
    // some code
    // 以下为新增
    $('#company_list').mousedown(function(){   // 下拉框mousedown时,保存下拉框为真   isSelect = true;   // 注册定时器 0毫秒以后触发,在定时器触发之前 ,input 的失焦事件触发此时isSelect为真   setTimeout(function(){     // 此时input的失焦已经触发了     isSelect = false;     $('input[name="company_name"]').focus()   },0) }) $('input[name="company_name"]').blur(function(ev){   if(!isSelect){//++     $('input[name="company_name"]').parent().removeClass('layui-form-selected');   }//++ })

     虽然 setTimeout 是0毫秒的延迟,但是他在下一次的事件队列中,所以会先执行 input 的 blur 事件,再执行 setTimeout 。

    有关事件循环 EventLoop 的知识,大家可以自行百度,理解了这个,虽然不会让你写代码变厉害,但是对理解js是有很大的作用的。不过想彻底理解,需要理解宏任务 task 与微任务 Microtasks ,以及 Promise 。

    下次可能会写一下关于 EventLoop 的东西。

  • 相关阅读:
    PATA 1071 Speech Patterns.
    PATA 1027 Colors In Mars
    PATB 1038. 统计同成绩学生(20)
    1036. 跟奥巴马一起编程(15)
    PATA 1036. Boys vs Girls (25)
    PATA 1006. Sign In and Sign Out (25)
    读取web工程目录之外的图片并显示
    DOS命令
    java连接oracle集群
    servlet
  • 原文地址:https://www.cnblogs.com/maopixin/p/10043449.html
Copyright © 2020-2023  润新知