摘要:上一篇文章介紹了這個(gè)工具庫(kù)中的第二個(gè)依賴,這個(gè)工具庫(kù)主要完成了一個(gè)簡(jiǎn)易的事件訂閱發(fā)布器。節(jié)點(diǎn)事件綁定判斷一個(gè)元素是否是節(jié)點(diǎn),是通過(guò)構(gòu)造函數(shù)和屬性來(lái)判斷的。
上一篇文章介紹了clipboard.js這個(gè)工具庫(kù)中的第二個(gè)依賴tiny-emitter,這個(gè)工具庫(kù)主要完成了一個(gè)簡(jiǎn)易的事件訂閱發(fā)布器。這次介紹一下clipboard.js源碼中的最后一個(gè)依賴的輕型工具庫(kù)good-listener,這個(gè)工具庫(kù)主要用來(lái)對(duì)dom的事件綁定進(jìn)行一層封裝,支持事件委托delegate,和jquery的寫(xiě)法非常類似,源碼簡(jiǎn)潔且清晰易懂,對(duì)理解事件綁定模型和原理非常有幫助。
快速用法const listen = require("good-listener")
good-listener支持常見(jiàn)的三種方式來(lái)綁定事件
node節(jié)點(diǎn)事件綁定
var logo = document.getElementById("logo"); listen(logo, "click", function(e) { console.log(e); });
nodeList多個(gè)節(jié)點(diǎn)遍歷事件綁定
var anchors = document.querySelectorAll("a"); listen(anchors, "click", function(e) { console.log(e); });
字符串形式的委托事件綁定(默認(rèn)委托的對(duì)象document.body)
listen(".btn", "click", function(e) { console.log(e); });代碼實(shí)現(xiàn)
good-listener的實(shí)現(xiàn)大致如下
function listen(target, type, callback) { if (is.node(target)) { return listenNode(target, type, callback); } else if (is.nodeList(target)) { return listenNodeList(target, type, callback); } else if (is.string(target)) { return listenSelector(target, type, callback); } else { throw new TypeError(`argument must be a String, HTMLElement, HTMLCollection, or NodeList`); } }
對(duì)于node和nodeList節(jié)點(diǎn)的實(shí)現(xiàn)比較簡(jiǎn)單,一筆帶過(guò),這里主要分析一下delegate委托的實(shí)現(xiàn)。
node節(jié)點(diǎn)事件綁定判斷一個(gè)元素是否是node節(jié)點(diǎn),是通過(guò)構(gòu)造函數(shù)constructor和nodeType屬性來(lái)判斷的。
value !== undefined && value instanceof HTMLElement && value.nodeType === 1;
listenNode實(shí)現(xiàn),返回了一個(gè)對(duì)象,為事件綁定擴(kuò)展了一個(gè)取消綁定的方法destroy
function listenNode(node, type, callback) { node.addEventListener(type, callback); return { destroy: function() { node.removeEventListener(type, callback); } } }nodeList多個(gè)節(jié)點(diǎn)遍歷事件綁定
判斷一個(gè)元素是否是nodeList節(jié)點(diǎn),是通過(guò)構(gòu)造函數(shù)constructor和length屬性來(lái)判斷的。且需要保證類數(shù)組中的元素都是有效的dom節(jié)點(diǎn)
var type = Object.prototype.toString.call(value) value !== undefined && (type === "[object NodeList]" || type === "[object HTMLCollection]") && ("length" in value) && (value.length === 0 || exports.node(value[0]))
listenNodeList實(shí)現(xiàn), 遍歷一下類數(shù)組,一次執(zhí)行事件綁定即可
function listenNodeList(nodeList, type, callback) { Array.prototype.forEach.call(nodeList, function(node) { node.addEventListener(type, callback); }); return { destroy: function() { Array.prototype.forEach.call(nodeList, function(node) { node.removeEventListener(type, callback); }); } } }事件委托的實(shí)現(xiàn)
簡(jiǎn)單回顧一下事件委托,比如有以下場(chǎng)景
1
2
3
4
需要把p標(biāo)簽的點(diǎn)擊事件委托到父元素div上面,jquery中的寫(xiě)法是
$(".wrapper").on("click", ".delegate", function(e) {...})
如果我們自己去實(shí)現(xiàn),是不能單純的去判斷點(diǎn)擊的target是不是包含delegate,因?yàn)辄c(diǎn)擊的元素有可能是子元素span,所以子元素可以通過(guò)冒泡找到delegate,那么委托也是應(yīng)該可以觸發(fā)的。
再介紹一個(gè)方法,下面要用到,Element的原型上有一個(gè)matches方法,接受一個(gè)selector字符串,如果element元素被指定的字符串選擇,那么返回true.
1.首先來(lái)模擬這個(gè)冒泡的過(guò)程
// document節(jié)點(diǎn) const DOCUMENT_NODE_TYPE = 9 function closet (element, selector) { while(element && element.nodeType !== DOCUMENT_NODE_TYPE) { if (typeof element.matches === "function" && element.matches(selector)) { return element } element = element.parentNode } }
這個(gè)函數(shù)就是判斷點(diǎn)擊的元素是否能夠向上冒泡(不斷的獲取父元素)匹配到指定的委托元素。
結(jié)合上面例子就是span能否向上找到delegate
2.使用代理模式為事件的回調(diào)函數(shù)封裝一層判斷邏輯,當(dāng)符合委托邏輯的時(shí)候,才去執(zhí)行回調(diào)函數(shù)
并且為event對(duì)象添加一個(gè)屬性delegateTarget,這樣在event中可以拿到對(duì)應(yīng)的三個(gè)對(duì)象
this和e.currentTarget 是被委托的元素
e.delegateTarget 是委托元素
e.target 是點(diǎn)擊元素
function listener(element, selector, type, callback) { return function(e) { e.delegateTarget = closest(e.target, selector); if (e.delegateTarget) { callback.call(element, e); } } }
3.delegate內(nèi)部封裝
let _delegate = (element, selector, type, callback, useCapture) => { // 將element和selector封裝一層 let listenerFn = listener.apply(this, arguments) element.addEventListener(type, listenerFn, useCapture) return { destroy () { element.removeListener(type, listenerFn, useCapture) } } }
4.delegate
分為兩種情況,被委托可以是一個(gè)dom元素,也可以是css選擇器字符串,如下所示
delegate(document.body, ".btn", "click", function(e) { console.log(e.delegateTarget); }, false);
delegate(".container", ".btn", "click", function(e) { console.log(e.delegateTarget); }, false);
分別處理即可
let delegate = (elements, selector, type, callback, useCapture) => { if (typeof elements.addEventListener === "function") { return _delegate.apply(null, arguments) } if (typeof elements === "string") { elements = document.querySelectorAll(elements) } return Array.prototype.map.call(elements, function (element) { return _delegate(element, selector, type, callback, useCapture) }) }結(jié)語(yǔ)
本次介紹的good-listener這個(gè)工具庫(kù)的用法和源碼分析,介紹了node,nodeList的事件綁定封裝的實(shí)現(xiàn),尤其探求了一下委托的實(shí)現(xiàn)方法,用不多的代碼實(shí)現(xiàn)了兼容性很好的delegate,至此clipboard.js的依賴都介紹完了,下一篇文章會(huì)整合代碼,將完整的clipboard.js實(shí)現(xiàn)展現(xiàn)出來(lái)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/93188.html
摘要:下面對(duì)它的實(shí)現(xiàn)一一分析。可以使用獲取選中的內(nèi)容也可以使用獲取一個(gè)用戶選擇的范圍。在這里完成了對(duì)用戶選中內(nèi)容的一些操作,而且在不是表單無(wú)法觸發(fā)事件的時(shí)候,也可以在指定區(qū)域監(jiān)聽(tīng)事件來(lái)實(shí)時(shí)獲取選中的內(nèi)容完成復(fù)制等功能。 項(xiàng)目中用到了選中復(fù)制功能 showImg(https://segmentfault.com/img/bVY7dH?w=400&h=78); 就是點(diǎn)擊按鈕,復(fù)制左側(cè)的內(nèi)容到剪切...
摘要:用于在同一主模塊下的不同子模塊以及不同主模塊之間的通信,支持動(dòng)態(tài)綁定作用域。如果用過(guò)的父子組件事件通信以及,對(duì)事件管理器應(yīng)該不會(huì)陌生的。而且支持指定作用域,可以遠(yuǎn)程調(diào)用任意模塊的函數(shù)。 上一篇文章介紹了clipboard.js這個(gè)工具庫(kù)中的第一個(gè)依賴select這個(gè)工具庫(kù)主要完成了對(duì)任意DOM元素的復(fù)制到粘貼板的功能。這次介紹一下clipboard.js源碼中的第二個(gè)依賴的輕型工具庫(kù)t...
摘要:需求開(kāi)發(fā)過(guò)程中遇到的需求需要復(fù)制請(qǐng)求過(guò)來(lái)的一段密令類似支付寶淘寶口令到剪切板。網(wǎng)上搜了下,是個(gè)相對(duì)比較靠譜的第三方。感謝大佬的評(píng)論意見(jiàn)使用該方法,會(huì)在下次更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的。 需求 開(kāi)發(fā)過(guò)程中遇到的需求需要復(fù)制 請(qǐng)求過(guò)來(lái)的一段密令(類似支付寶淘寶口令)到剪切板。 pc端的文本復(fù)制到剪切板 如果是在pc端的話,可以直接使用原生js進(jìn)...
摘要:需求開(kāi)發(fā)過(guò)程中遇到的需求需要復(fù)制請(qǐng)求過(guò)來(lái)的一段密令類似支付寶淘寶口令到剪切板。網(wǎng)上搜了下,是個(gè)相對(duì)比較靠譜的第三方。感謝大佬的評(píng)論意見(jiàn)使用該方法,會(huì)在下次更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的。 需求 開(kāi)發(fā)過(guò)程中遇到的需求需要復(fù)制 請(qǐng)求過(guò)來(lái)的一段密令(類似支付寶淘寶口令)到剪切板。 pc端的文本復(fù)制到剪切板 如果是在pc端的話,可以直接使用原生js進(jìn)...
閱讀 2687·2021-11-23 09:51
閱讀 2590·2021-09-30 09:48
閱讀 1219·2021-09-10 10:51
閱讀 2313·2021-08-12 13:22
閱讀 3661·2021-08-11 10:24
閱讀 2271·2019-08-30 15:55
閱讀 778·2019-08-30 14:05
閱讀 3281·2019-08-30 13:03