zoukankan      html  css  js  c++  java
  • click事件细节

    这是前一个月被反馈的问题,当时没有时间研究,今天稍有时间研究汇总下

    一个小问题

    click事件是鼠标点击某个元素的时候触发的吗?
    这么问还不够细……
    是鼠标点下触发的吗?
    是鼠标松开时触发的?
    还是鼠标一次按下+松开再触发。

    这个问题很好回答,相信很多人有这样一种检验:一些二逼的产品经理把一些点击的交互放在非常不寻常的位置,这导致我们经常点击到错误的区域——好的,我们细化这个过程:

    -->我们需要执行某个无脑操作,鼠标在我们直觉认为的地方左键按下(并没有松开)
    -->然后大脑忽然参与了,“二逼,这个地方点击并不能达到你的期望,并且会跳到一个操作时间很长的页面,以公司这破网速,你再回到此页面需要250秒!”
    -->然后我们的右手(此处忽略左撇子的感受!)拖动鼠标到一个无关的地方,释放按下的左键,“好险,又避开了产品经理的陷阱!”

    一次连贯的click事件就被我们摧毁了。

    和别的事件结合会发生什么事

    就像我们打断鼠标的点击事件一样,在同一元素上触发click事件和一些别的事件,会造成意外的情况。

    因为click包含mousedown和mouseup,那么我们就要特别注意那些mousedown时触发的事件:mousedown,focus,focusin。

    假如这些mousedown时就会触发的事件是把鼠标移到别的位置,例如弹出一个遮挡层——鼠标与原来的元素之间的联系就断开了,就算鼠标的坐标没有发生变化,但是此时再松开鼠标——还有卵用!你只是在遮挡上来了一发mouseup!

    细节之处

    模拟select元素遇到的问题

    方案一

    我时常看到一些人嫌select元素不好用,要自己模拟一个select。

    代码会这样写

    /**
     * 模拟一个下拉列表
     */
    function DropdownList(){
    	var container = $("<div class='select'></div>");
    	var curitem = $("<input readonly='readonly' class='curitem'>");
    	var list = $("<ul style='display:none'><li>选项1</li><li>选项2</li></ul>");
    
    	//事件
    	curitem
    	.focus(function(){
    		list.css({
    			"display":"block"
    		})
    	})
    	.blur(function(){
    		list.css({
    			"display":"none"
    		})
    	})
    	list.find("li").click(function(e){
    		var value = $(e.target).html();
    		curitem.val(value);
    	})
    
    	container.append(curitem);
    	container.append(list);
    
    	return container;
    }
    

    他们使用一个input来呈现已选中的项的值,用一个ul存放下拉列表的值,通过input的焦点事件来显隐ul。给li元素绑定click事件来选中。
    然而:click事件并没有什么卵用!

    因为我们click一个li的时候,放慢动作:

    -->mousedown到了li上 --> input 失去焦点,blur了 --> ul隐藏了 -->此时™释放了mouseup

    你的click被沉默了!

    解决办法:只要把选择事件从click换成 mousedown即可。

    方案二

    一些同学在上面一步就垮掉了,愤怒地说道:“尼玛的,傻逼设计的js,傻逼设计的dom,本屌的思路如此行云流水,竟然会出现此路不通!”

    他们会执行方案二:

    /**
     * 模拟一个下拉列表
     * 使用一个div和ul
     */
    function DropdownList2(){
    	var container = $("<div class='select'></div>");
    	//这里不再用input元素,而是一个div元素,他们不再依赖focus和blur机制
    	var curitem = $("<div class='curitem'></div>");
    	curitem.css({
    		"border":"1px solid #ddd",
    		"height":"30px",
    		"width":"100px"
    	})
    	var list = $("<ul style='display:none'><li>选项1</li><li>选项2</li></ul>");
    
    	//事件
    	curitem
    	.click(function(){
    		list.css({
    			"display":"block"
    		})
    	})
    	
    	list.find("li").click(function(e){
    		var value = $(e.target).html();
    		curitem.html(value);
    		list.css({
    			"display":"none"
    		})
    	})
    
    	container.append(curitem);
    	container.append(list);
    	return container;
    }
    
    

    然而坑爹的是,当ul显示出来之后,点击页面的其他地方,ul隐藏不了。于是……
    在body上绑定了一个click事件,click之后隐藏ul……

    有一些模拟化编程基础的同学是忍受不了这种事情的。

    我的解决方法是使用focuseout,它有一些兼容性问题我这里不讨论:

    focusout和blur的概念是一样的,但它是冒泡的。有人说,这里是个div元素没有focus和blur事件,你冒个卵子,我只能说too young too simple!

    需要背景知识的去看这篇文章,很棒的,说说focus /focusin /focusout /blur 事件

    我们直奔主题了:
    我们将上面的代码改造成如下

    /**
     * 模拟一个下拉列表
     * 使用一个div和ul
     */
    function DropdownList2(){
    	var container = $("<div class='select' tabindex='0'></div>");//这里使用一个tabindex是为了让div在非ie环境下具有fouseout事件
    	//这里不再用input元素,而是一个div元素,他们不再依赖focus和blur机制
    	var curitem = $("<div class='curitem'></div>");
    	curitem.css({
    		"border":"1px solid #ddd",
    		"height":"30px",
    		"width":"100px"
    	})
    	var list = $("<ul style='display:none;200px;border:1px solid #ddd;'><li>选项1</li><li>选项2</li></ul>");
    
    	//事件
    	curitem
    	.click(function(){
    		list.css({
    			"display":"block"
    		})
    	})
    	
    	list.find("li").click(function(e){
    		var value = $(e.target).html();
    		curitem.html(value);
    		list.css({
    			"display":"none"
    		})
    	})
    	container.focusout(function(e){
    		console.log("container focusout")
    		list.css({
    			"display":"none"
    		})
    	})
    
    	container.append(curitem);
    	container.append(list);
    	return container;
    }
    

    上面的代码在chrome,firfox下没有问题,但是在ie下是有问题的:li的click之后触发的首先是container的focusout事件,然后list直接被隐藏了,click又被沉默了!——因为ie下li和div天然就可触发focuseout事件,所以我们放下慢动作:

    ie中(别的浏览器我就不说了):

    -->首先你click了用来显示选中项的curitem,然后ul显示出来了——此时焦点在curitem上
    -->然后你选中了一项(mousedown):焦点到了ul中的此项上-->curitem上触发了focusout事件,冒泡到container上-->container.focusout隐藏了ul-->你在ul之外释放mouseup

    这个现象说明了一个元素的focusout事件包括冒泡上去的focusout事件,执行完了,才会执行这个元素上的click事件!

    想一想,为什么要这么设计?

    为什么一个先触发的事件,需要完成其整个冒泡之后,再触发后一个事件?


  • 相关阅读:
    C# 查找其他应用程序并打开、显示、隐藏、关闭的API
    微信公众平台开发2-access_token获取及应用(含源码)
    Winform下编译Dev控件时提示license.licx文件错误
    JS+MySQL获取 京东 省市区 地区
    MySQL性能调优与架构设计——第11章 常用存储引擎优化
    MySQL性能调优与架构设计——第10章 MySQL数据库Schema设计的性能优化
    MySQL性能调优与架构设计——第9章 MySQL数据库Schema设计的性能优化
    MySQL性能调优与架构设计——第1章 MySQL 基本介绍
    .NET基础 (21)ASP NET应用开发
    .NET基础 (20).NET中的数据库开发
  • 原文地址:https://www.cnblogs.com/magma/p/5061389.html
Copyright © 2011-2022 走看看