Skip to content

Instantly share code, notes, and snippets.

@simonid
Last active March 7, 2018 14:05
Show Gist options
  • Save simonid/50071ae7792dd4fd2cab348de8ce61ff to your computer and use it in GitHub Desktop.
Save simonid/50071ae7792dd4fd2cab348de8ce61ff to your computer and use it in GitHub Desktop.
jQuery笔记

jQuery随笔

jQuery事件处理

jQuery事件通过封装JavaScript事件来实现,比如.click()就是onclick的封装

和事件绑定、触发相关的api:

  • 绑定事件:bind、on、one、live、delegate...
  • 触发事件:trigger()...
  • 解绑事件:unbind、off、die、undelegate

冒泡和默认行为

默认情况下,事件会冒泡,即同样的事件沿着DOM数由下至上逐级触发。
阻止冒泡的方式是event.stopPropagation()

与冒泡行为类似的是默认行为,比如点击了一个<a>或者<button>这类标签时,会发生默认行为,假如要阻止,可以使用event.preventDefault()

在实际使用中,我们可以通过在事件处理函数末尾添加return false来阻止上述两种行为,所以它做了3件事:

  • stopPropagation()
  • preventDefault()
  • 立即结束当前函数并返回

绑定事件

在原生js中,绑定事件可以在DOM元素上设置类似onxx的属性,然后在script标签对内设置对应的处理函数

<div onclick="test()"></div>
<script>
    function test(){
        alert("test");
    }
</script>

但是这种方法不方便,所以引入了更多方法

bind

格式:
bind(type,[data],fn)

$('.box').bind('click',function(event){})
当然也可以绑定多个事件:
$('.box').bind('click mousemove',function(event){})
还可以通过json格式在一个bind方法中绑定多个事件函数

var handler = {
    click : function(){},
    mousemove : function(){}
};
$('.box').bind(handler);

注意:事件处理函数内部的this,正常情况下是指向当前DOM元素

前面的格式中有一个data的可选参数,它可以是任意类型,可以通过它传入数据

var dat = { name : 'dat'};
$('.box').bind('click',dat,function(event){
    alert(event.data.name);  //dat
});

事件处理函数中,event.data就是bind传入的data数据
如果该data参数传入的是布尔值,那么它可以设置是否允许默认行为和冒泡行为(false表示阻止)

bind()方法只会给当前文档中已经存在的匹配元素添加事件处理函数,如果后续动态添加元素,添加元素并不会绑定该事件处理函数,如希望绑定事件对后续添加的元素生效,可使用on()、delegate()等事件函数著作权归作者所有。

解绑通过: $(.box).unbind('click');实现

one

one()方法和bind()方法的用法一样,不过前者是用来绑定至多执行一次的事件处理函数著作权归作者所有。

on

格式:
on(type,[selector],[data],fn)

on()方法也是用来为指定元素的一个或多个事件绑定事件处理函数。著作权归作者所有。
bind()方法只会为页面已存在的元素绑定事件处理函数,可是on()不同,它不仅支持直接在目标元素上绑定事件,还支持在目标元素的父辈元素上委托绑定

解绑用off()方法

delegate

将事件处理函数动态绑定到指定的根元素上,由于事件冒泡特性,它被用来处理指定的子元素上的事件。

格式:
$(selector).delegate(childSelector,event,[data],function)

特点:

  • 能自带绑定动态添加的元素。如果事件处理函数绑定在父节点上,新增加的子节点元素事件也会冒泡到父节点
  • 性能优于bind(毕竟bind可能绑定多个事件处理函数)
<div id="root">
  <a>A</a>
  <a>B</a>
</div>
<script>
$('#root').delegate('a', 'click', function(){
    alert("click a");
});
</script>

事件触发trigger

和前面的事件绑定函数不同,trigger用来触发事件
比如:

<div class="box">123</div>

<button>模拟点击</button>


$('.box').on('click',function(){

  alert(1);

});

$('button').on('click',function(){

  $('.box').trigger('click');

});
  • trigger(eventType) 触发绑定在jQuery对象内匹配元素的特定事件类型(由eventType决定)上的事件处理函数。
  • trigger(Event) 触发绑定在jQuery对象内匹配元素的特定事件(由Event事件决定)上的事件处理函数。
  • triggerHandler(eventType) 触发绑定在jQuery对象内第一个匹配元素上的事件处理函数,既不冒泡,也不实施事件的默认行为。

document对象事件方法

load(function)  即load事件,在页面中的子元素及资源文件载入完成时触发

ready(function)  在页面中的元素已经处理完成,DOM就绪时触发

unload(function)  即unload事件,当用户离开当前页面时触发

浏览器事件方法

error(function)  即error事件,在载入外部资源文件出错时触发(如载入图片出错)

resize(function) 即resize事件,当浏览器窗口大小发生变化时触发

scroll(function) 即scroll事件,当用户拖动滚动条时触发

鼠标事件方法

click(function)  即click事件,在用户点击鼠标按钮时触发

dblclick(function)  即dblclick事件,在用户双击鼠标按钮时触发

focusin(function)  即focusin事件,在元素得到焦点时触发

focusout(function) 即focusout事件,在元素失去焦点时触发

hover(function)、hover(function,function)  即hover事件,在鼠标进入或离开元素时触发,若指定两个参数,进入时会触发第一个函数,离开时会触发第二个函数,否则都会触发第一个。

mousedown(function)  即mousedown事件,当在某元素上按下鼠标时触发

mouseenter(function) 即mouseenter事件,当鼠标进入某元素显示区域时触发

mouseleave(function) 即mouseleave事件,当鼠标离开某元素显示区域时触发

mousemove(function)  即mousemove事件,当鼠标在某元素显示区域内移动时触发

mouseout(function)   即mouseout事件,当鼠标离开某元素显示区域时触发

mouseover(function)  即mouseover事件,当鼠标进入某元素显示区域时触发

mouseup(function)    即mouseup事件,当按下后释放鼠标按钮时触发

mouseenter()与mouseover()、mouseleave() 与mouseup()的区别?

mouseenter()和mouseover()作用一样,但前者不支持冒泡,后者支持。

mouseleave()和mouseup()作用一样,但前者不支持冒泡,后者支持。

表单事件方法

blur(function)  即blur事件,在元素失去焦点时触发

change(function)  即change事件,在元素的值发生变化时触发

focus(function)  即focus事件,在元素获得焦点时触发

select(function)  即select事件,在用户选中某个可选框时触发

submit(function)  即submit事件,当用户提交表单时触发

键盘事件方法

keydown(function)  即keydown事件,当用户按下一个键后触发

keypress(function)  即keypress事件,当用户按下一个键并释放后触发

keyup(function)  即keyup事件,当用户释放一个键时触发

keypress事件会在按下键盘按键时触发。它与keydown事件类似,但keypress着重的是按下该键输入了哪个字符(只有能够打印字符的键才会触发keypress),keydown着重的是按下了哪个键(按下任何键都可触发keydown)。对于诸如Ctrl、Alt、Shift、Delete、Esc等修饰性和非打印键,请监听keydown事件。著作权归作者所有。

jQuery Event对象的属性和方法

currentTarget   返回正在处理(响应)该事件的元素

data   返回绑定事件时传递的data对象

isDefaultPrevented()   若已经调用过preventDefault()方法,返回true

isImmediatePropagationStopped()  若已经调用过stopImmediatePropation()方法,返回true

originalEvent   返回未经jQuery处理的原始DOM Event对象

pageX、pageY   返回相对于页面左上角的鼠标位置

preventDefault()  用来阻止当前事件的默认行为

relatedTarget  仅对鼠标事件有效,返回该鼠标事件有关的元素

result   返回处理该事件的最后一个事件处理函数的返回值

stopImmediatePropagation()  立即阻止调用当前事件的其他事件处理函数

stopPropagation()  阻止事件冒泡

target  返回触发事件的元素

timeStamp  返回事件发生的时间

type  返回事件类型

which  在键盘和鼠标事件中,返回用户按下的键或鼠标按钮

参考:
JQuery学习笔记整理:事件处理

jQuery事件绑定函数on和bind的区别

on和off方法是jQuery1.7+版本增加的,也推荐使用on方法

格式:
bind(type,[data],fn)
on(type,[selector],[data],fn)

二者区别在于是否含selector这个参数,假如on方法不设置selector,那么和bind是没有区别的。

根据JavaScript的事件冒泡特性,假如父元素上注册一个事件处理函数,当子元素上发生该事件时,父元素上的事件处理函数也会一并触发

on()函数的参数selector就是为了在事件冒泡的时候,让父元素能够过滤掉子元素上发生的事件。如果使用了bind,那么就没有这个能力,子元素上发生的事件一定会触发父元素事件。

比如:

<div id="parent">  
    <input type="button" value="a" id="a"/>  
    <input type="button" value="b" id="b"/>  
</div>  

$("#parent").on("click","#a",function(){  
    alert($(this).attr("id"));  
}); 

$("#parent").on("click","#a",function(){  
    alert($(this).attr("id"));  
});  
 

我们在父元素上绑定了事件处理函数,当点击子元素的任意一个按钮,都会执行事件处理函数。但是假如我们想要只点击某一个的时候才触发事件处理,那么应该使用on

jQuery中的data方法

一般来说,在js操作DOM的时候经常会向DOM临时增加一些参数,用作保存一些状态,或是从后端获取参数值等

在html标签上添加自定义属性就必须访问DOM,性能上并不好。如果是使用jQuery,可以尝试使用$element.data()方法获取html标签上的data-*自定义参数

<div id="awesome-json" data-awesome='{"game":"on"}'></div>

var gameStatus= jQuery("#awesome-json").data('awesome').game;
console.log(gameStatus);

当然,data方法不仅可以获取属性值,也可以用来设置属性值

<html>
<head>
<script type="text/javascript" src="/jquery/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
  $("#btn1").click(function(){
    $("div").data("greeting", "Hello World");
  });
  $("#btn2").click(function(){
    alert($("div").data("greeting"));
  });
});
</script>
</head>
<body>
<button id="btn1">把数据添加到 div 元素</button><br />
<button id="btn2">获取已添加到 div 元素的数据</button>
<div></div>
</body>
</html>

在jQuery插件中经常会看到类似下面的代码片段:

$.fn[pluginName] = function (options) {
        return this.each(function () {
            if (!$.data(this, 'test_' + pluginName)) {
                $.data(this, 'test_' + pluginName,
                new Plugin(this, options));
            }
        });
    }

这点很重要,因为我们在每个应用的元素上存储了对plugin实例的引用,通过data方法设置属性,允许我们检查一个元素是否已经应用了一个插件,或者需要实例化。

jQuery文档的教程一般格式如下:

$.fn[pluginName] = function ( options ) {
    return this.each(function () {
        if (typeof options === "string") {
            var args = Array.prototype.slice.call(arguments, 1), plugin = $.data(this, 'plugin_' + pluginName);
            plugin[options].apply(plugin, args);
        } else if (!$.data(this, 'plugin_' + pluginName)) {
            $.data(this, 'plugin_' + pluginName, new Plugin( this, options ));
        }
    });
};

参考:
How would I add a method to this jQuery plugin pattern?
Things I learnt creating a jQuery Plugin (Part I)
一个基本的jQuery插件demo

jQuery中的this和$(this)

this指的是html元素对象,可以调用html对象所拥有的属性
$(this)指的是jQuery对象,会继承jQuery的方法

本质上,二者是JavaScript和jQuery对象之间的转换

一般来说,有
this == $(this)[0]

补充另外一个例子说明:

<a href="http://segmentfault.com/q/1010000000125418" target="_blank" data-id="1010000000125418">jQuery</a>

$('a').click(function(){
        this.innerHTM==$(this).html()=='jQuery';//三者是一样的.
        this.getAttribute('href')==this.href==$(this).attr('href')//三者是一样的;
        this.getAttribute('target')==this.target==$(this).attr('target')//三者是一样的;
        this.getAttribute('data-id')==$(this).attr('data-id')//二者是一样的;
    });

参考:
segmentfault 问:jQuery里$(this)和this的区别在哪?

jQuery宽高的理解

首先区分window和document的区别

window.location === document.location

与window相关的宽高

window.innerWidth、window.innerHeight、window.outerWidth、window.outerHeight

window.outerHeight的高度就是整个浏览器的高,window.innerHeight的高度是网页页面的高,也就是浏览器高减去浏览器工具栏的高度

window.innerHeight和window.outerHeight

window.innerWidth和window.outerWidth的宽度相等,都是浏览器宽

window.innerWidth和window.outerWidth

window.innerWidth和window.outerWidth

注意:innerHeight和outerHeight是有兼容性的,IE9以下不支持

window.screen

该属性包含了用户屏幕的信息

大致可以分为下列:

window.screen.height、window.screen.width、window.screen.availHeight、window.screen.availWidth、window.screenTop、window.screenLeft

window.screenTop;//浏览器窗口距离屏幕顶部的高度

window.screenLeft;//浏览器窗口距离屏幕左侧的宽度


window.screen//包含了屏幕的信息

window.screen.height;//屏幕的高度
window.screen.width;//屏幕的宽度
window.screen.availHeight;//屏幕可利用的高度,比如windows系统的任务栏高度去除以后就是了
window.screen.availWidth;//屏幕可利用的宽度

window.screen.height和window.screen.availHeight
-


与document相关的宽高

document下与client相关的宽高

document.body.clientWidth、document.body.clientHeight

该属性指的是元素可视区域宽高,即padding+content

  • 如果没用滚动条,即为元素设定的高度和宽度
  • 如果出现滚动条,滚动条会遮盖元素的宽高,那么该属性就是其本身宽高减去滚动条的宽高

小结:

  • 假如无padding无滚动 clientWidth=style.width

* 假如有padding无滚动 clientWidth=style.width+style.padding*2
* 假如有padding有滚动,且滚动是显示的 clientWidth=style.width+style.padding*2-滚动轴宽度

client位置属性

document.body.clientLeft、document.body.clientTop

这两个元素返回的是元素周围边框的厚度,如果不指定一个边框或者不定位该元素,它的值就是0

这一堆属性用来读取元素的border的宽高

clientTop = border-top的border-width
clientLeft = border-left的border-width


document下offset相关宽高介绍

offsetWidth和offsetHeight

这一对属性指的是元素的border+padding+content的宽高

该属性和其内部的元素是否超出元素大小无关,只和本来设定的border以及width和height有关

offsetLeft和offsetTop

offsetParent

  • 如果当前元素的父级元素没有进行CSS定位(position为absolute或relative),offsetParent为body
  • 如果当前元素的父级元素中有CSS定位(position为absolute或relative),offsetParent取最近的那个父级元素

offset*属性在不同浏览器中有不同的表现

在IE6/7中
offsetLeft = (offsetParent的padding-left) + (当前元素的margin-left)
在IE8/9/10及chrome中
offsetLeft = (offsetParent的margin-left) + (offsetParent的border宽度) + (offsetParent的padding-left) + (当前元素的margin-left)
在Firefox中
offsetLeft = (offsetParent的margin-left) + (当前元素的margin-left) + (offsetParent的padding-left)

offset位置属性

document下scroll相关宽高

scrollWidth和scrollHeight

document.body的scrollWidth和scrollHeight与div下的是有区别的

document.body下的

  • 一、当给定宽高小于浏览器窗口时 scrollWidth通常是浏览器窗口的宽度
    scrollHeight通常是浏览器窗口高度

  • 二、当给定宽高大于浏览器窗口,且内容小于给定宽高 scrollWidth给定的高度 + 其所有的padding、margin和border
    scrollHeight给定的高度 + 其所有的padding、margin和border

  • 三、当给定宽高大于浏览器窗口,且内容大于给定宽高 scrollWidth内容高度 + 其所有的padding、margin和border
    scrollHeight内容高度 + 其所有的padding、margin和border

div下的

当无滚动轴时:
scrollWidth = clientWidth = style.width + style.padding*2
当有滚动轴时:
scrollWidth = 实际内容宽度 + padding*2
scrollHeight = 实际内容高度 + padding*2

scrollLeft和scrollTop

这对属性是可读写的,指的是当元素中的内容超出其宽高时,元素被卷起的高度和宽度

scroll位置属性

3种height

从上图直观看来,仿佛clientHeightscrollHeight的值并不一样,然后再来对比下面的图,这是一个返回顶部按钮的demo,且鼠标已经滚动到底部: scrollHeight和clientHeight
结果,无论鼠标如何滚动,clientHeightscrollHeight的值一直相等。
造成这个现象的原因在于设置了body的样式属性height:5000px,所以clientHeight的高就是5000px
从这里可以看出,不可以简单地认为页面可视高度就是clientHeight,要注意有没有设置body的高

然后再看:
window.innerHeight和document.documentElement.clientHeight
window.innerHeightdocument.documentElement.clientHeight相等,这里就是没有设置body的height属性

不过这只是在没有底部滚动条的情况下,如果出现底部横向滚动条就另当别论了

具体说来,window.innerHeight包括整个DOM:内容、边框以及滚动条。

documentElement.clientHeight不包括整个文档的滚动条,但包括<html>元素的边框。
body.clientHeight不包括整个文档的滚动条,也不包括<html>元素的边框,也不包括<body>的边框和滚动条。

documentElement和body

二者是父子级别的关系,documentElement是html区域,body则是body区域

Event对象中的5种坐标

Event对象中的5种坐标

小结:

e.clientX
e.clientY  点击的地方距离可视窗口的距离

e.offsetX
e.offsetY   点击的地方距离父元素

e.screenX
e.screenY   点击的地方距离屏幕的距离

jQuery宽高

和jQuery直接相关的宽高的方法:

.width()    .height()
.innerWidth()   .innerHeight()
.outerWidth()   .outerHeight()

width()和height()

实际值是内容的宽高,不包含padding
以width()为例
对于window和document来说传值无效;对于普通元素来说,读写都是可以的,格式可以是width(value)width(function(){})

.width()和.css("width")的区别

最主要的区别:
width()返回结果无单位
css("width")的结果有单位

.innerWidth()和.innerHeight()

它们二者的读写和前面提到的width()height()一样,所以不建议在windowdocument环境下使用这两个方法

.outerWidth()和.outerHeight()

这两者可以传入一个布尔值,当传入内容是true,内容包括margin,否则不包含(默认)
除了这一点外,和innerWidth(),.innerHeight()情况一样

延伸-.scrollLeft()、.scrollTop()、.offset()、.position()

scrollLeft():相对于水平滚动条左边的距离。如果滚动条不能滚动,该值为0
scrollTop()类似

offset():相对于document的当前坐标值(相对于body左上角的left、top值)
position():相对于offsetParent的当前坐标(相对于offsetParent元素左上角left、top值)
jQuery

参考:
segmentfault-浏览器的各种位置值获取
视口的宽高与滚动高度

jQuery插件中经常有这种格式代码

;(function ( $, window, document, undefined ){
 //函数体内具体代码
 })(jQuery, window,document);

解释

1.最前面的分号是为了防止多个文件压缩合并后其他文件末尾没加分号而引起的错误

2.3个实参:
$是jQuery的简写,很多方法和库也有$,这里$接受jQuery对象,为了避免$变量冲突
window和document实参分别接收window、document对象,window、document对象都是再全局环境下的,而函数内window、document实际上是局部变量,不是全局的window、document对象。这样做可以提高性能,减少作用域链的查询时间
如果再函数体内需要多次调用window或document对象,这样把window或document对象当作参数传进。假如插件中不使用这两个对象,就没必要传递这两个参数了

3.还剩最后一个undefined形参,它在旧浏览器中是不支持的,直接使用会报错,为了考虑兼容,所以增加一个形参undefined

参考:
jquery插件中(function ( $, window, document, undefined )的作用
中文-What (function (window, undefined) {})(window);really means

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment