1. 程式人生 > >用js的eval函數模擬Web API中的onclick事件

用js的eval函數模擬Web API中的onclick事件

腳本 ply function img listen target list getattr 部分

在檢查組內小夥伴提交的tabToggler插件的js代碼時,發現了onclick的如下用法:

                el.onclick = function(){
                    //按鈕樣式切換
                    for(var i=0;i<obj.btns.length;i++){
                        obj.btns[i].classList.remove("current");
                    }
                    this.classList.add("current");
                    
//內容顯示切換 for(var j = 0;j<obj.divs.length;j++){ obj.divs[j].style.display = ‘none‘; } obj.divs[this.index].style.display = ‘block‘; console.log(this.index); }

顯然這個this指向事件源對象—eventTarget,最近一直在鉆研閉包和this的我,看到這裏覺得非常的怪,為什麽這裏的this可以指向eventTarget呢,而且在書寫在html標簽裏的事件處理函數也可以在非閉包作用域下直接訪問this(指向target),如下代碼:

<div id="tab1" myonclick = "console.log(this.id);console.log(this)">Tab1</div>

打印結果:

技術分享圖片

這到底怎麽實現的?按照需求一步一步分析就可以了,其實onclick的事件處理函數包括了兩部分:

Part 1: 來自html標簽內的onclick屬性內的js代碼;

Part 2: 來自己js腳本裏的onclick方法

需求如下:

Part 1 裏的onclick字符串可以被click事件執行,而且this作用域是eventTarget

問題:js裏有什麽機制能執行字符串形式的js代碼?如何讓代碼作用域指向eventTarget?

答案:eval,且eval執行本身就有作用域的概念,讓代碼的作用域指向eventTarget就行了。

Part 2 裏的onclick方法被click事件執行內部邏輯,而且this作用域是eventTarget;

綜上,我們可以用eval和指定作用域的辦法來擴展一個myonclick時間了,具體實現如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="tab1" myonclick = "console.log(this.id);console.log(this)">Tab1</div>
        <div id="tab2">Tab2</div>
    </body>
    <script>
    //擴展HTMLDivElement原型
    HTMLElement.prototype.clickHandle = function(){
        //1.檢查dom標簽裏有myonclick屬性
        var _evalClickStr = this.getAttribute( "myonclick" );
        //2.檢查dom有無指定myonclick方法
        if( !!this.myonclick  && typeof this.myonclick === "function" ){
            var _clickHandle = this.myonclick;
        }
        var nativeEventBind = this.addEventListener || this.attachEvent;
        if( !!nativeEventBind ){
            nativeEventBind( ‘click‘,(function( e ){
                //執行eavl代碼串
                eval( _evalClickStr );
                //執行myonclick事件處理函數
                _clickHandle.apply( this,e );
            }).bind(this) );
        }
        else return;
    }
    
    var tab1 = document.getElementById( "tab1" );
    tab1.myonclick = function(){
        console.log( this.id );
    };
    tab1.clickHandle();
    
    </script>
</html>

核心設計要點:擴展了HTMLElement.prototype對象,在clickHandle方法裏,指定了兩部分onclick代碼的執行上下文為HTMLElement元素本身。

用js的eval函數模擬Web API中的onclick事件