主要是区别于原生js的异同点。
one.
你可以一直用原生的js来处理事件,但是你一定要记住jquery处理事件的最重要的一些特殊点:
1.同一个dom节点添加不同的事件,不会被覆盖。这是jquery重构事件的出发点。
2.由于上述第一点,一个dom节点对应多个事件,需要被管理。因此,与“on”对应的存在“off”。原生的js中没有同一个节点管理不同事件的需求,不存在"off"之类的,也没这个需求,比如不存在oDiv.offclick=function(){}..
3.组合拳(自定义新的事件)。他有两个不同的方向,一个方向是定义一个压根在现实世界里不存在的事件,常常与trigger联合起来使用自动触发,再给事件进行命名的时候随意性较大;另外一个方向是多个人协同工作的时候,不同的人给同一个DOM添加各自不同的事件,管理混乱的情况下尤其是在测试谁的代码问题的时候,使用称之为“事件命名空间”的技术(由于上述第一点的存在故而产生这种需求),它的在给事件进行命名的时候,都是在已有的现实中存在(如点击click,移入mouseover,移出mouseout)的,他的事件命名的格式形如:dom.on("click.lx",fn) &&dom.on("click.zly",fn) [分别代表代号为“lx”“zly”两个不同的人的命名空间]。无论是哪种的方向,都只能采用dom.on(eventName,fn)的形式而不能采用dom.click(fn)的形式,都常常与trigger联合起来使用。
// 起作用的是“bb()”“"原生js的onmouseover"”.aa被bb覆盖。
// 原生的js中同一类型的事件会被覆盖,不同类型的事件会保留:
oDiv=document.getElementsByTagName("div")[0]
oDiv.onclick=aa;
oDiv.onclick=bb;
oDiv.onmouseover=function(){
alert("原生js的onmouseover")
}
// 居然不认可$("div")[0]
$("div")[0].click(aa) //失效?!最好不要用这种半原生的半jq的!
$("div").click(function() {
alert("第一种方式:dom.click(fn)")
})
$("div:eq(0)").on("click", function() {
alert("第二种方式dom.on(eventName,fn)")
})
$("div").eq(0).click(aa);
$("div").click(bb);
$("div").mouseover(function() {
alert("jquery的mouseover")
})
// 连些模式,移入点击都会触发aa()
$("div").on("click mouseover", aa)
// 需要被管理,因此出现off("eventName",fn)
$("div").off("mouseover", aa) //禁止$("div").mouseover(aa)的效果
$("div").off("mouseover") // 所有的“mouseover”事件都被禁止
$("div").off("mouseover click", aa) //禁止$("div").click(aa)和$("div").mouseover(aa)
two
事件冒泡 vs 阻止默认事件
jquery把两者都简化成“return false”了(write less ,do more)。
"return false"解决所有问题,尤其代码的记忆问题(ev.stopPropagation/ev.preventDefault单词很难记啊!)
// 靠近20行的代码,阻止默认事件/阻止冒泡事件。
oDiv_f=document.getElementsByTagName("div")[0];
oDiv_son=document.getElementsByTagName("div")[1];
oDiv_f.onclick=father;
//冒泡
oDiv_son.onclick=son;
// 阻止冒泡,将son包含在另外一个新的函数中,ev为所有的事件函数都默认带有。
oDiv_son.onclick=function(ev){
son();
ev.stopPropagation(true);
};
oA=document.getElementsByTagName("a")[0];
oA.onclick=function(ev){
alert("本来跳转到“爱美句”的结果不跳转了")
ev.preventDefault(true);
}
oForm=document.getElementsByTagName("form")[0];
oForm.onclick=function(ev){
alert("本来跳转到“爱xuexi”的结果不跳转了")
ev.preventDefault(true);
}
// "return false"解决所有问题,尤其代码的记忆问题
// (ev.stopPropagation/ev.preventDefault单词很难记啊!)
// 不到10行的代码,“write less do more!”
$(".father").click(father);
$(".son").click(function(){
alert(" “retrun false”阻止冒泡事件");
return false;
});
$("a").click(function(ev){
// 阻止a的默认跳转
return false;
})
$("form").click(function(ev){
// 阻止表单action的默认跳转
return false;
})
three.
在jquery中,都是通过on/off/trigger来控制dom的事件的开/关/自动运行的,因此,他们的代码的格式也及其的相似,可以统一的表达为:
DOM.on/off/trigger("eventName",fn)。fn在off/trigger可以省略。
trigger vs triggerHanddler:
trigger 不阻止冒泡不阻止默认事件。triggerHandller阻止冒泡阻止默认事件(可以想见源代码类似于上述two中的"return false"有无的区别)。但是对于特殊的标签"a",$("a").trigger("click")在jquery的源代码中做过了处理,无论是trigger还是triggerHandller都是不会跳转页面的【目的是为了防止篡改页面?安全考虑?】。如果确实有这个需要则需要手动修改html页面,将a标签中的内容包裹在span中,比如<a><span>a标签中的HTM内容</span></a>(也就是说,你要是想不通过点击自动跳转页面,光有修改js的权限还是不够的,你还得有修改html的权限,防止恶意篡改)。
four.
1.自定义现实中不存在的操作事件。
function father(){alert("father()")}
function son(){alert("son()")}
// myclickisnotreal mymouseisnone都是在现实中不存在的操作
$(".father").on("myclickisnotreal",father);
$(".son").on("mymouseisnone",son);
// 不起作用,父节点不能使用子节点的自定义事件,不相干的节点不能调用该节点的自定义事件
// $(".father").trigger("mymouseisnone")
// $("span").trigger("mymouseisnone")
// 都起作用,即对于子节点而言,父节点/子节点自身带有的自定义事件都可以被.trigger()
$(".son").trigger("myclickisnotreal")
$(".son").trigger("mymouseisnone")
2.自定义现实中存在的操作事件,在存在的操作事件后加".人物名缩写/人物名"以示区别。比如dom.on("click.lx",fn) &&dom.on("click.zly",fn) [分别代表代号为“lx”“zly”两个不同的人的命名空间]。
$(".father").on("click",function(){
alert("我是你们爸爸!")
})
$(".son").on("click.lx",function(){
alert("没门牙的响哥")
return false
})
// 冒泡现象在这里(事件命名空间)神奇的不起作用了!
$(".son").on("click.zly",function(){
alert("伪娘燎原")
})
// 常常用于检测谁的代码出错了啊?!便于管理.
$(".son").trigger("click.zly")
总结如下:
1.无论是自定义事件还是自定义的“事件命名空间”,冒泡现象起作用与否主要看事件的名称是否完全一致。
2.无论是自定义事件还是自定义的“事件命名空间”,两者都是与trigger有着广泛的联系!
five.
“ 事件委托”是“事件捕获”的具体的应用。顶级的父类的事件通过“事件捕获”一级一级的传递给子类DOM节点,当子类节点暂时不存在或者不方便点击或者不方便获取 的时候,通过“事件委托”把当前节点所应该处理的“事件委托”给父类或者便于获取/点击的节点。尤其要注意原生js在jquery在这个领域上的比较!
一段原生的js的代码:
<script>
// 点击子节点div1,div2以及之后新增的div3全部转化成点击父节点。
window.onload = function(){
let div = document.getElementById('div');
div.addEventListener('click',function(e){
// 原生的js中是用 e.target 来标注鼠标点到的某一个具体的DOM节点元素上的。
// 而jquery中非常复杂的委托(delegate)事件需要用在这里不露痕迹的
// 似乎不费劲的显示了出来:
//(jq)需要被委托的节点.delegate(寻求委托的DOM节点,"eventName(click,mouseouver...)",fn)
//(原生js) 需要被委托的节点.addEventListener(eventName,fn(e){e.target})
console.log(e.target)
})
let div3 = document.createElement('div');
div3.setAttribute('class','div3')
div3.innerHTML = 'div3';
div.appendChild(div3)
}
</script>
<body>
<div id="div">
<div class="div1">div1</div>
<div class="div2">div2</div>
</div>
</body>
jquery:
$("ul").delegate("li","click",function(ev){
console.log(ev.target);
// 区别于原生的js,这里的this代表的是“li”,而非“谁的函数this就是谁”的"ul".
// 注:jquey在"this"重新定向的问题上显然是经过加工和再处理了。
console.log(this.innerHTML)
// 这里的this只是一个dom对象还不是一个jquery对象,还需要将其包装成jquery对象,$(this)
console.log($(this).html())
})
一半原生js一半jquery处理的委托:
$("ul").click(function(ev){
console.log(ev.target);
console.log(ev.target.innerHTML);
console.log($(ev.target).html());
})
总结:
1.原生的js在处理“事件委托”的时候,是直接把子节点的点击换成父节点的点击,并没有刻意的使用类似于jquery“.delegate()”之类的函数。
(jquery格式:)需要被委托的节点.delegate(寻求委托的子节点,"eventName",fn)
(原生js:) 需要被委托的节点.addEventListener(eventName,fn(e){e.target})
2.$(function(){})或者window.οnlοad=fn来说,加载的只是已经写好的固定的H5页面,对于新增的节点,是无法操作的。新增的节点只有2个操作:添加,移除。对应于父节点.append(子节点) / 子节点.remove()。因此在需要操作这类特殊的新增加的节点的时候,需要考虑用“事件委托”/“事件捕获”:
//注册页面的时候弹出窗口。$mask(“蒙版”) 和 $(".login")【登陆时候弹出的窗口】都是新增加的节点。
//这类特殊的节点只有append()和remove()可以使用
$mask.remove();
//语法上没有错误,所以下面的代码不会有任何的效果,但是也不会报错。$(".login")未通过$(fn)加载进
//来,要牢记这一点,避免这种情况,因为不报错很难查找。目前技术暂时只能放弃这种使用,以后有更好的
//技术能直接使用也说不准。
$(".login").attr("display","none")
six(复习)
div.addEventListener('click',fn,false/true),关于addEventListener的使用范围:
1.dom.addEventListener("eventName",fn,ture/false) 增加的同一个类型的事件不会被覆盖,是原生js自带的事件的加强版。
2.dom.addEventListener("eventName",fn,ture/false),第三个参数“true/false”可以不写,不写的时候默认为“false”.当写“true”的时候表示阻止冒泡事件但是对于a标签form标签的默认事件无能为力。
3.当dom节点是window的时候,window.addEventListener("load",fn)----回到开篇介绍jquery性能的时候讲到过这一点。用这种方式不会被覆盖,她的价值等于$(function(){})
seven
在jquery源代码中,mouseenter/mouseleave作为进阶版本的mouseover/mouseout 事件,通过在父节点的所有的子节点中遍历增加“return false”,而避免了子节点捕获/获取父节点的事件。因此,这种格式更合适实际的生产需要。要补充说明的是,上述情况只适用于子类的“面积”完全在父类的掌控中的时候。当子类的设置的面积大于父类的时候,在父类的掌控中的面积避免了“事件冒泡”;但是多余的突出面积依然存在事件捕获/事件冒泡,点击突出面积依然会有父类事件的弹出!
另外要注意的是hover是mouseenter/mouseleave的改写,也是通过增加“return false”避免事件冒泡。
$(".father").mouseenter(function(){
console.log("father mouseenter")
})
$(".father").mouseleave(function(){
console.log("father mouseleave")
})
$(".son").mouseenter(function(){
console.log("son mouseenter")
})
$(".son").mouseleave(function(){
console.log("son mouseleave")
})
$(".father").hover(function(){
// 这里是移入后的函数
console.log("hover 移入")
},function(){
// 这里是移出后的函数
console.log("hover 移出")
})
$(".son").hover(function(){
console.log("hover的两个函数相同的时候可以省略成一个!呵呵!")
})