媒介
前端在近来几年着实火爆非常,vue、react、angular各路框架屡见不鲜,我们假如不晓得个双向数据绑定,不晓得啥是假造DOM,或许就被蔑视了。炽热的背地每每也是无尽的急躁,进修这些先进盛行的类库或许框架能够让我们走的更快,然则静下心来回归基础,把基石打稳固,却能够让我们走的更稳,更远。
近来一向在看zepto的源码,愿望经由过程进修它控制一些框架设想的技能,也将良久不再拾起的js基础从新复习稳固一遍。假如你对这个系列感兴趣,迎接点击下方地点watch
,随时关注动态。这篇文章重要想说一下zepto中事宜模块(event.js)的trigger
完成道理。
<!–more–>
event.js模块
zepto中由许多小的模块组合合成,基础的
zepto.js
模块,event.js
事宜处置惩罚模块,ajax.js
要求处置惩罚模块等等。个中event.js
事宜处置惩罚模块的中心完成了zepto中事宜绑定on
,移除off
另有手动触发trigger
等功用。我们简朴回忆下怎样运用zepto的这三大功用。
<ul class="list">
<li>1</li>
<li>2</li>
</ul>
let $list = $('.list')
let cb1 = function (e, name) {
console.log(1, name)
}
let cb2 = function (e, name) {
console.log(2, name)
}
$list.on('click', cb1)
$list.on('click', cb2)
// 移除事宜
// 我们能够指定移除click事宜的某个事宜处置惩罚顺序
$list.off('click', cb1)
// 也能够直接移除click事宜
$list.off('click')
// 手动触发事宜
$list.trigger('click', 'qianlongo')
哥们你逗我呢,jQuery,zepto多熟了,谁不会用这个啊!客观别急,我们本日主假如慢慢来看看它源码怎样完成的。
一步步看trigger怎样完成
直接上代码
$.fn.trigger = function (event, args) {
// 对传入的event举行处置惩罚,假如是字符串或许纯对象,获得一个本身建立的事宜对象
// 假如传入的已是个经由$.Event处置惩罚的对象,则放入compatible再次革新(实在就是增加了几个要领,和重写了几个要领)
event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
// args传递给事宜处置惩罚顺序的参数
event._args = args
return this.each(function () {
// handle focus(), blur() by calling them directly
if (event.type in focus && typeof this[event.type] == "function") this[event.type]()
// items in the collection might not be DOM elements
// 触发dom事宜
else if ('dispatchEvent' in this) this.dispatchEvent(event)
// 由于zepto对象内部的元素不一定是dom元素,此时直接触发还调函数
else $(this).triggerHandler(event, args)
})
}
直接贴出trigger函数的代码能够我们是懵逼的
$
是啥啊!!!
$.fn
是啥啊!!!
$.isPlainObject
又是啥啊!!!
$.Event
又是什么鬼?
似乎有一连串的题目等待着我们处理。
为了直接切入不容易明白,我们先来看看zepto中是怎样给基础的zepto.js
模块增加功用的
起首看看zepto.js模块
var Zepto = (function () {
// xxxx
var $ = function (selector, context) {
return zepto.init(selector, context)
}
return $
zepto.Z.prototype = Z.prototype = $.fn
// xxxx
})()
window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)
只管删除了一些不必要的代码,能够看到我们日常平凡运用的Zepto
实在就是其匿名函数自实行内部导出的一个函数。而$.fn
就是其原型
怎样给zepto.js模块增加功用
zepto.js
模块只要一些基础的功用,比方给dom增加事宜的功用就没有,怎样增加呢?
(function ($) {
// xxx
$.fn.on = function () {//xxxx}
$.fn.off = function () {//xxxx}
$.fn.trigger = function () {//xxxx}
$.Event = function () {//xxx}
// xxx
})(Zepto)
末了缩减掉其他的滋扰代码,能够看到所谓的给zepto.js
模块增加功用,基础上就是在其原型上增加新的要领或许直接在$函数上定一些静态要领。
好啦我们已处理了$
,$.fn
是啥的疑问了,如今归去最先一步步解读怎样完成手动触发事宜。
从新看trigger函数源码
$.fn.trigger = function (event, args) {
// 对传入的event举行处置惩罚,假如是字符串或许纯对象,获得一个本身建立的事宜对象
// 假如传入的已是个经由$.Event处置惩罚的对象,则放入compatible再次革新(实在就是增加了几个要领,和重写了几个要领)
event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
// args传递给事宜处置惩罚顺序的参数
event._args = args
// xxx
}
先把背面的一些代码给删除了,我们先明白这几句代码。个中非常重要的一个函数就是$.Event
,至于
isString
=> 推断是不是是字符串
isPlainObject
=> 推断是不是是存粹的对象(必需是对象,window对象除外,该对象的原型必需和Object的原型一致)
compatible
=> 实在就是对事宜对象event
做一些扩大,比方增加一些要领,重写一些要领之类的。
这几个要领临时能够不须要太多体贴.
我们重要看看$.Event
,这内里险些含有怎样手动触发一个dom事宜的大部分步骤和内容。
我们重要看看$.Event
,这内里险些含有怎样手动触发一个dom事宜的大部分步骤和内容。
我们重要看看$.Event
,这内里险些含有怎样手动触发一个dom事宜的大部分步骤和内容。
$.Event是个啥
建立并初始化一个指定的dom事宜对象, 假如给定了props,则将其扩大到事宜对象上
$.Event = function (type, props) {
// 当type是个对象时,比方{type: 'click', data: 'qianlongo'}
if (!isString(type)) props = type, type = props.type
// click,mousedown,mouseup mousemove对应MouseEvent
// 其他事宜对应为Events
// 并把bubbles设置为true,示意事宜冒泡,为false则不冒泡
var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
// 当props存在的时刻,对props举行轮回处置惩罚,将其属性扩大到event对象上
if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
// 初始化事宜对象,第一个为事宜范例,第二个为冒泡与否,第三个为是不是能够经由过程preventDefault来阻挠浏览器默许行动
event.initEvent(type, bubbles, true)
// 再对制造出来的时候对象处置惩罚一番并返回
return compatible(event)
}
解释已写的很清晰了,这个函数就是返回一个经由初始化了的事宜对象
到这里我们直接归结一下要手动触发一个dom事宜的基础步骤
手动触发一个dom事宜,须要3步,假如你对document.createEvent,不是很熟悉,能够点击检察。
建立一个事宜对象 document.createEvent(event)
初始化事宜对象 event.initEvent(type, bubbles, true)
分发事宜 dom.dispatchEvent(event)
到这里已完成了前面两步,还剩末了一步了,在来看trigger
剩下的代码
手动触发dom事宜末了一步
$.fn.trigger = function (event, args) {
// 对传入的event举行处置惩罚,假如是字符串或许纯对象,获得一个本身建立的事宜对象
// 假如传入的已是个经由$.Event处置惩罚的对象,则放入compatible再次革新(实在就是增加了几个要领,和重写了几个要领)
event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
// args传递给事宜处置惩罚顺序的参数
event._args = args
return this.each(function () {
// handle focus(), blur() by calling them directly
if (event.type in focus && typeof this[event.type] == "function") this[event.type]()
// items in the collection might not be DOM elements
// 触发dom事宜
else if ('dispatchEvent' in this) this.dispatchEvent(event)
// 由于zepto对象内部的元素不一定是dom元素,此时直接触发还调函数
else $(this).triggerHandler(event, args)
})
}
末了一步实在就是将当前选中的元素举行一次each遍历,然后推断要触发的事宜是不是是focus
或许blur
,假如是就直接实行。
再进一步,假如dispatchEvent
要领在当前的dom元素属性中存在,那末便将该事宜触发。(为何要这一步呢?由于我们晓得$()函数的运用体式格局有许多,有些体式格局获得的zepto对象是没有选中dom节点的)
末了另有一个else分支,这个分支处置惩罚走的不是手动触发事宜,而是直接触发注册事宜时增加的事宜处置惩罚顺序(由于这里涉及到zepto事宜模块中怎样治理元素与事宜队列的映照关联,篇幅会比较长,会在接下来的文章中说,这里不睁开申明)
手动diy一个
依据上面的形貌,手动触发DOM事宜,本来并没有那末奇异,完成三步,即可到达目的。我们本身来手动写一个示例
<ul class="list">
<li class="item1">1</li>
<li>2</li>
<li>3</li>
</ul>
let $list = document.querySelector('.list')
let $item1 = document.querySelector('.item1')
$list.addEventListener('click', function () {
console.log(this.innerHTML)
}, false)
$item1.addEventListener('click', function () {
console.log(this.innerHTML)
}, false)
// 1. 建立一个事宜对象 document.createEvent(event)
let event = document.createEvent('Event')
// 2. 初始化事宜对象 event.initEvent(type, bubbles, true)
event.initEvent('click', true, true)
// 3. 分发事宜 dom.dispatchEvent(event)
$item1.dispatchEvent(event)
这个时刻控制台打印出了
1
<li class="item1">1</li>
<li>2</li>
<li>3</li>
1是item1的事宜处置惩罚函数打印出来的。
背面的li那部分则是list打印出来的。
假如将initEvent的第二个参数设置为false,将不许可冒泡,则只会打印出1
末端
假如这部分对你有点点协助,点个star好不好呀! ???