在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/HTML/ 使用jq框架,如何讓事件在捕獲階段執(zhí)行。

使用jq框架,如何讓事件在捕獲階段執(zhí)行。

比如在父元素A設(shè)置一個(gè)事件,在子元素B設(shè)置另一個(gè)事件。
點(diǎn)擊子元素的時(shí)候,我希望A的事件先觸發(fā)(就是按照捕獲階段執(zhí)行)
但是我看過源碼,jq綁定事件的addEventlistener只能冒泡執(zhí)行。
這令我不解,難道jq沒有給出解決方法嗎?
這種情況應(yīng)該有人遇到過才對,是怎么解決的呢?

$(box).on('click',function(e){console.log(0)}); //并不是最先觸發(fā)的
$(b1).on('click',function(e){console.log(1)});
$(box).on('click.blur','.b1',function(e){console.log(2)});
回答
編輯回答
卟乖

clipboard.png
本質(zhì)是這個(gè)。
既然jquery沒有捕獲的實(shí)現(xiàn),我們自己實(shí)現(xiàn)一個(gè)。代碼如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
    <!--換成你自己jquery的地址-->
    <script src="jquery-1.12.4.js"></script>
    <title>Document</title>
</head>
<body>
    <div id="xx" style="height:200px;background:green;">
        <div id="yy" style="position:relative;top:50px;height:100px;background:red;"></div>
    </div>
    <script>
        (function(debug){
            // 用WeakMap省的dom被移除了還持有引用無法gc
            const listeners = new WeakMap();
            // core
            const capture = (elem,type,callback,once=false) => {
                // 看看有沒有這個(gè)dom,避免重復(fù)注冊
                if(!listeners.has(elem)){
                    listeners.set(elem,new Map());
                    // https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener
                    elem.addEventListener(type,fnCenter,{
                        capture:true,
                        once,
                    });
                }
                const map = listeners.get(elem);
                // 看看有沒有這個(gè)type的事件被注冊
                if(map.has(type)){
                    map.get(type).push(callback);
                }else{
                    map.set(type,[callback]);
                }
            };
            
            // 所有注冊都用同一個(gè)函數(shù)引用,方便解除
            const fnCenter = function(event){
                // currentTarget和target的區(qū)別參見mdn
                const {currentTarget,type} = event;
                // currentTarget,type就是找到回調(diào)的兩把鑰匙
                if(listeners.has(currentTarget) && listeners.get(currentTarget).has(type)){
                    const callbacksArray = listeners.get(currentTarget).get(type);
                    // 循環(huán)執(zhí)行回調(diào)們
                    callbacksArray.forEach(callback=>callback(event));
                }else{
                    //找不到么應(yīng)該有問題,你可以選擇在此拋出錯(cuò)誤或者警告或者移除注冊
                }
            }
            
            // 卸載
            const remove = (elem,type) => {
                // 看看注沒注冊過,沒注冊過就退出
                if(!listeners.has(elem)){
                    return false;
                }
                // 沒寫type全移除,寫了type,只移除這個(gè)類型的
                if(!type){
                    listeners.delete(elem);
                }else{
                    const map = listeners.get(elem);
                    map.delete(type);
                }
                elem.removeEventListener(type,fnCenter);
            }
            
            // 注冊到j(luò)Query的原型上去
            // 監(jiān)聽捕獲
            $.fn.capture=function(type,callback){
                // this is a jQuery Object
                if(!this.length){
                    throw new Error("沒有有效的selector")
                }
                for(let i=0;i<this.length;i++){
                    const dom = this.get(i);
                    capture(dom,type,callback);
                }
            };
            // 僅監(jiān)聽一次捕獲
            $.fn.captureOnce=function(type,callback){
                // this is a jQuery Object
                if(!this.length){
                    throw new Error("沒有有效的selector")
                }
                for(let i=0;i<this.length;i++){
                    const dom = this.get(i);
                    capture(dom,type,callback,true);
                }
            };
            // 解除監(jiān)聽
            $.fn.removeCapture=function(type){
                // this is a jQuery Object
                if(!this.length){
                    throw new Error("沒有有效的selector")
                }
                for(let i=0;i<this.length;i++){
                    const dom = this.get(i);
                    remove(dom,type);
                }
            };
            
            if(debug){
                window.listeners = listeners;
            }
            
        })(true);
        
        // 實(shí)驗(yàn)
        $("#xx").capture("click",function(e){
            alert("父");
        });
        $("#yy").capture("click",function(e){
            alert("子");
        });
    </script> 
</body>
</html>

效果如下

clipboard.png

2017年10月17日 22:54
編輯回答
孤星

setTimeout

2017年12月8日 13:42
編輯回答
離夢

原來是我理解錯(cuò)了,多虧阿蛇提醒,查了資料,jquery自身并未提供在捕獲階段觸發(fā)事件處理函數(shù)的接口。原生的addEventListener可以實(shí)現(xiàn),非要和jq扯上關(guān)系,改造如下(用了阿蛇的html結(jié)構(gòu))

    <div id="xx" style="height:200px;background:green;">
        <div id="yy" style="position:relative;top:50px;height:100px;background:red;"></div>
    </div>
    <script>
        $('#yy')[0].addEventListener("click",function(){
            alert("子")
        },true);
        $('#xx')[0].addEventListener("click",function(){
            alert("父")
        },true);

    </script> 
2017年4月16日 14:57
編輯回答
短嘆

看來是jq本身沒有打算為事件控制捕獲順序了。
那么我試著假設(shè)要為jq框架的基礎(chǔ)上添加一個(gè)這樣的功能,修改原先的程序。
首先為綁定事件(event.add)增加一個(gè)可選參數(shù)capture,用于決定捕獲順序。
正常來說jq只會(huì)為一個(gè)元素綁定一個(gè)addEventListener。但為了能按照捕獲順序觸發(fā)函數(shù),接收到有capture的事件,需額外綁定一個(gè)capture為true的addEventListener。
為jq事件處理對象(handlers)加上capture屬性。
然后修改event.handlers方法,按照事件傳播階段(eventPhase)來判斷現(xiàn)在觸發(fā)的是捕獲還是冒泡觸發(fā)。如果是捕獲觸發(fā),在處理程序列表(handlerQueue)內(nèi)插入capture為true的handlers。然后就能按照正常流程執(zhí)行處理程序。
以上的修改能保留原先的構(gòu)造上增加捕獲觸發(fā)的功能,也能使用jq.off(解除綁定事件)。希望以后jq能增加這個(gè)功能吧。

2018年8月5日 13:19