主頁 > 企業開發 > jQuery 原始碼分析(十六) 事件系統模塊 底層方法 詳解

jQuery 原始碼分析(十六) 事件系統模塊 底層方法 詳解

2020-09-14 10:54:48 企業開發

jQuery事件系統并沒有將事件監聽函式直接系結到DOM元素上,而是基于資料快取模塊來管理監聽函式的,事件模塊代碼有點多,我把它分為了三個部分:分底層方法、實體方法和便捷方法、ready事件來講,好理解一點,

jQuery的事件分為普通事件和代理事件:

  • 普通事件  ;當我們再div上定義一個click事件,此時如果點擊div或按鈕都會觸發該普通事件,這是由于冒泡的緣故
  • 代理事件  ;當我們在div上定義一個代理事件,且selector設定為button時,我們點擊div將不會觸發該事件,只有點擊了這個按鈕才會觸發這個代理事件

事件系統模塊的底層方法如下:

  • $.event.add(elem,types,handler,data,selector)  ;系結一個或多個型別的事件監聽函式,引數如下:
    • elem        ;操作的元素
    • types        ;系結的事件型別,多個事件型別之間用空格隔開,
    • handler    ;待系結的事件監聽函式,也可以是一個自定義的監聽物件,
    • data        ;自定義資料,
    • selector    ;選擇器運算式字串,用于系結代理事件,    ;
  • $.event.remove(elem, types, handler, selector, mappedTypes)  ;移除DOM元素上系結的一個或多個型別的事件監聽函式,引數同$.event.add(),如果只傳入一個elem元素則移除該元素上的所有事件,
  • $.event.trigger(type,data,elem,onlyHandlers)    ;手動觸發事件,執行系結的事件監聽函式和默認行為,并且會模擬冒泡程序,引數如下:
    • type            ;事件字串
    • data                 ;傳遞給回應函式的資料
    • elem            ;觸發該事件的DOM物件
    • onlyHandlers    ;是否只觸發elem元素對應的事件監聽函式,而不冒泡

常用的就是以上三個吧,其它還有$.event.global(記錄系結過的事件)、$.event.removeEvent(用于洗掉事件)等

先舉栗子前先先簡單說一下jQuery里的事件的分類,jQuery的事件分為普通事件和代理事件:

  • 普通事件  ;直接系結在這個元素的某個事件型別上,當在該元素上觸發了這個事件時,則執行該事件
  • 代理事件  ;當事件直接發生在代理元素上時,監聽函式不會執行,只有當事件從后代元素冒泡到代理元素上時,才會用引數selector匹配冒泡路上的后代元素,然后用匹配成功的后代元素作為背景關系去執行監聽函式,

這樣說可能理解不了,舉個栗子,我們定義兩個DOM元素先

這里我們定義了一個div,內部含有一個子節點button,渲染如下:

舉個栗子:

writer by:大沙漠 QQ:22969969

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    <style>div{width: 200px;padding-top:50px;height: 150px;background: #ced;}div button{margin:0 auto;display: block;}</style>
</head>
<body>
    <div>        
        <button id="button">按鈕1</button>    
    </div>
    <script>
        let div = document.getElementsByTagName('div')[0],
            btn = document.getElementsByTagName('button')[0];

        $.event.add(div,'click',()=>console.log('div普通單擊事件'));                //給div系結一個click事件
        $.event.add(div,'click',()=>console.log('d1代理事件'),null,'button');    //給div系結一個代理事件,監聽物件為button
    </script>
</body>
</html>

渲染如下:

 我們給div系結了一個普通事件(型別為click),還有一個代理事件(代理的元素是button),當我們點擊div元素時將觸發普通事件,如下:

代理事件并沒有被觸發,當我們點擊按鈕1時將會同時觸發普通事件和代理事件:

這里的代理事件是在jQuery內部實作的,而普通事件是因為原生的冒泡的事件流所產生的,

 

原始碼分析


jQuery內部的事件系結也是通過原生的addEventListener或attachEvent來實作的,不過jQuery對這個程序做了優化,它不只是僅僅的呼叫該API實作系結,用jQuery系結事件時,在同一個DOM元素上的系結的任何事件,其實最后系結的都是同一個函式,該函式只有幾行diamagnetic,最后又會呼叫jQuery.event.dispatch去進行事件的分發,并執行事件監聽函式,

上面說了事件系統模塊是基于資料快取模塊來管理監聽函式的,我們通過jQuery系結的事件都保存到了$. cache里對應的DOM元素的資料快取物件上(有疑問的可以看下資料快取模塊,前面介紹過了),比如上面的栗子,我們列印一下$.cache可以看到系結的資訊:

每個DOM元素在內部資料快取對上有兩個屬性是和事件有關的:

  • events  ;屬性是一個物件,其中存盤了該DOM元素的所有事件,該物件的下的每個元素的元素名是事件型別,值是一個陣列,是封裝了監聽函式的handleObject集合
  • handle  ;DOM元素的主監聽函式,負責分發事件和執行監聽函式,對于一個DOM元素,jQuery事件系統只會為之分配一個主監聽函式,所有型別的事件都被系結到這個主監聽函式

 好了,現在來說一下原始碼實作,$.event.add的原始碼實作如下:

jQuery.event = {
    add: function( elem, types, handler, data, selector ) {        //系結一個或多個型別的事件監聽函式

        var elemData, eventHandle, events,
            t, tns, type, namespaces, handleObj,
            handleObjIn, quick, handlers, special;

        // Don't attach events to noData or text/comment nodes (allow plain objects tho)
        if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = https://www.cnblogs.com/greatdesert/p/jQuery._data( elem )) ) {        //排除文本節點(瀏覽器不會在文本節點上觸發事件)、注釋節點(沒有意義)、引數不完整的情況
            return;
        }

        // Caller can pass in an object of custom data in lieu of the handler
        if ( handler.handler ) {                                    //如果引數handle是自定義監聽物件,其中的屬性價會被設定到后面所創建的新監聽物件上,函式cloneCopyEvent(src,dest)將呼叫該方法
            handleObjIn = handler;
            handler = handleObjIn.handler;
        }

        // Make sure that the handler has a unique ID, used to find/remove it later
        if ( !handler.guid ) {                                        //如果函式handler沒有guid
            handler.guid = jQuery.guid++;                                //則為它分配一個唯一標識guid,在移除監聽函式時,將通過這個唯一標識來匹配監聽函式,
        }

        // Init the element's event structure and main handler, if this is the first
        events = elemData.events;                                    //嘗試取出事件快取物件
        if ( !events ) {                                            //如果不存在,表示從未在當前元素上(通過jQuery事件方法)系結過事件,
            elemData.events = events = {};                                //則把它初始化為一個空物件,events物件保存了存放當前元素關聯的所有監聽函式,
        }    
        eventHandle = elemData.handle;                                //嘗試取出主監聽函式handle(event)
        if ( !eventHandle ) {
            elemData.handle = eventHandle = function( e ) {            //如果不存在,表示從未在當前元素上(jQuery事件方法)系結過事件,則初始化一個主監聽函式,并把它存盤到事件快取物件的handle屬性上,這是事件觸發時真正執行的函式
                // Discard the second event of a jQuery.event.trigger() and
                // when an event is called after a page has unloaded
                return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
                    jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
                    undefined;
            };
            // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
            eventHandle.elem = elem;
        }

        // Handle multiple events separated by a space
        // jQuery(...).bind("mouseover mouseout", fn);
        types = jQuery.trim( hoverHack(types) ).split( " " );        //先呼叫hoverHack()函式修正hover.namespace型別的事件,再呼叫split把types用空格進行分隔,轉換為一個陣列
        for ( t = 0; t < types.length; t++ ) {                        //遍歷需要系結的每個事件型別,逐個系結事件

            tns = rtypenamespace.exec( types[t] ) || [];                //正則rtypenamespace用于決議事件型別和命名空間,執行后tns[1]是事件型別,tns[2]是一個或多個命名空間,用.分隔
            type = tns[1];                                                //type就是事件型別
            namespaces = ( tns[2] || "" ).split( "." ).sort();

            // If event changes its type, use the special event handlers for the changed type
            special = jQuery.event.special[ type ] || {};

            // If selector defined, determine special event api type, otherwise given type
            type = ( selector ? special.delegateType : special.bindType ) || type;

            // Update special based on newly reset type
            special = jQuery.event.special[ type ] || {};

            // handleObj is passed to all event handlers
            handleObj = jQuery.extend({                                    //把監聽函式封裝為監聽物件,用來支持事件模擬、自定義事件資料等,
                type: type,                                                    //實際使用的事件型別,不包含命名空間,可能被修改過
                origType: tns[1],                                            //原始事件型別,不包含命名空件,未經過修正
                data: data,                                                    //排序后的命名空間,如果傳入的事件型別是'click.a.c.b',那么namespace就是a.b.c
                handler: handler,                                            //傳入的監聽函式
                guid: handler.guid,                                            //分配給監聽函式的唯一標識guid
                selector: selector,                                            //自定義的事件資料
                quick: quickParse( selector ),                                //入的事件代理選擇器運算式,當代理事件被觸發時,用該屬性過濾代理元素的后代元素,
                namespace: namespaces.join(".")
            }, handleObjIn );

            // Init the event handler queue if we're the first
            handlers = events[ type ];                                    //嘗試取出事件型別type對應的監聽物件陣列handlers,其中存放了已系結的監聽物件,
            if ( !handlers ) {                                            //如果type事件型別的陣列不存在,則進行系結操作
                handlers = events[ type ] = [];                                //把監聽物件陣列的handlers初始化為一個空陣列,
                handlers.delegateCount = 0;                                    //初始化handlers.delegateCount為0,表示代理事件的個數為0 

                // Only use addEventListener/attachEvent if the special events handler returns false
                if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {    //系結主監聽函式 優先呼叫修正物件的修正方法setup()
                    // Bind the global event handler to the element
                    if ( elem.addEventListener ) {                            //如果瀏覽器支持addEventListener()方法
                        elem.addEventListener( type, eventHandle, false );        //呼叫原生方法addEventListener()系結主監聽函式,以冒泡流的方式,

                    } else if ( elem.attachEvent ) {                        //如果沒有addEventListener()
                        elem.attachEvent( "on" + type, eventHandle );            //則呼叫attachEvent()方法系結主監聽函式,IE8及更早的瀏覽器只支持冒泡
                    }
                }
            }

            if ( special.add ) {                                        //如果修正物件有修正方法add()
                special.add.call( elem, handleObj );                        //則先呼叫修正方法add()系結監聽函式

                if ( !handleObj.handler.guid ) {
                    handleObj.handler.guid = handler.guid;
                }
            }

            // Add to the element's handler list, delegates in front
            if ( selector ) {                                            //如果傳入了selector引數,則系結的是代理事件
                handlers.splice( handlers.delegateCount++, 0, handleObj );    //把代理監聽物件插入屬性handlers.delegateCount所指定的位置,每次插入代理監聽物件后,監聽物件陣列的屬性handlers.delegateCount自動加1,以指示下一個代理監聽物件的插入位置,
            } else {                                                     //未傳入selector引數情況下,則是普通的事件系結
                handlers.push( handleObj );                                    //把監聽物件插入末尾
            }

            // Keep track of which events have ever been used, for event optimization
            jQuery.event.global[ type ] = true;                            //記錄系結過的事件型別
        }

        // Nullify elem to prevent memory leaks in IE
        elem = null;                                                    //解除引數elem對DOM元素的參考,以避免記憶體泄漏(IE)
    },
    /**/
}

 $.event.add會通過addEventListener或attachEvent去系結事件,當事件被觸發時就會執行我們系結的事件,也就是上面的elemData.handle函式,該函式會執行jQuery.event.dispatch函式,jQuery.event.dispatch就是用于分發事件的,如下:

 

jQuery.event = {
    dispatch: function( event ) {        //分發事件,執行事件監聽函式

        // Make a writable jQuery.Event from the native event object
        event = jQuery.event.fix( event || window.event );                //呼叫jQuery.event.fix(event)把原生事件物件封裝為jQuery事件物件,

        var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),        //取出this元素當前事件型別對應的函式串列,
            delegateCount = handlers.delegateCount,                                            //代理監聽物件個事
            args = [].slice.call( arguments, 0 ),                                            //把引數arguments轉換為真正的陣列
            run_all = !event.exclusive && !event.namespace,
            handlerQueue = [],
            i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;

        // Use the fix-ed jQuery.Event rather than the (read-only) native event
        args[0] = event;                                                                    //將event保存為args[0],監聽函式執行時這是作為第一個引數傳入的
        event.delegateTarget = this;                                                        //當前的DOM物件,等于event.currentTarget屬性的值

        // Determine handlers that should run if there are delegated events
        // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
        if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {    //如果當前物件系結了代理事件,且目標物件target沒有禁用  !(event.button && event.type === "click")的意思是:是滑鼠單擊時

            // Pregenerate a single jQuery object for reuse with .is()
            jqcur = jQuery(this);                                                                            //用當前元素構造一個jQuery物件,以便在后面的代碼中復用它的方法.is(selector)
            jqcur.context = this.ownerDocument || this;                                                        //背景關系

            for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {                            //從事件目標開始,再依次到父節點,一直到當前目標為止,遍歷從觸發事件的元素到代理元素這條路徑上的所有后代元素,
                selMatch = {};                                                                                    //重置selMatch為空物件
                matches = [];                                                                                    //重置matches為空陣列
                jqcur[0] = cur;                                                                                    //將jqcur系結到每一個后代元素
                for ( i = 0; i < delegateCount; i++ ) {                                                            //遍歷所有的代理監聽物件陣列,
                    handleObj = handlers[ i ];                                                                        //某個代理監聽物件,
                    sel = handleObj.selector;                                                                        //當前代理監聽物件的selector屬性    

                    if ( selMatch[ sel ] === undefined ) {                                                            //如果系結的事件對應的選擇器在selMatch中不存在,則進行檢查,看是否符合要求
                        selMatch[ sel ] = (
                            handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
                        );
                    }
                    if ( selMatch[ sel ] ) {                                                                        //當后代元素與代理監聽物件的選擇器運算式匹配時
                        matches.push( handleObj );                                                                    //把代理監聽物件放入陣列matches中,
                    }
                }
                if ( matches.length ) {
                    handlerQueue.push({ elem: cur, matches: matches });                                            //最后把某個后代元素匹配的所有代理監聽物件代理放到陣列handlerQueue里,
                }
            }
        }

        // Add the remaining (directly-bound) handlers
        if ( handlers.length > delegateCount ) {                                                //如果監聽物件陣列handlers的長度大于代理監聽物件的位置計數器delegateCount,則表示為當前元素系結了普通事件
            handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });            //把這些監聽物件也放入待執行佇列handlerQueue中
        }

        // Run delegates first; they may want to stop propagation beneath us
        for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {            //執行陣列handlerQueue中的所有函式,遍歷待執行佇列handlerQueue,如果某個元素的監聽函式呼叫了方法stopPropagation()則終止for回圈
            matched = handlerQueue[ i ];                                                            //matched是陣列handlerQueue中的一個物件
            event.currentTarget = matched.elem;                                                        //把當前正在執行監聽函式的元素賦值給事件屬性event.currentTarget,這樣在事件處理函式內,this等于系結的代理函式

            for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {    //遍歷元素定對應的監聽物件陣列,并執行監聽物件中的監聽函式
                handleObj = matched.matches[ j ];                                                            //handleObj是一個具體的監聽物件handleObj

                // Triggered event must either 1) be non-exclusive and have no namespace, or
                // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
                if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {

                    event.data = handleObj.data;                                                        //把監聽物件的屬性handleObj.data賦值給jQuery事件物件
                    event.handleObj = handleObj;                                                        //把監聽物件賦值給jQuery事件物件event.handleObj上,這樣監聽函式就可以通過該屬性訪問監聽物件上的諸多屬性

                    ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )    //優先呼叫修正物件的修正方法special.handle(),
                            .apply( matched.elem, args );

                    if ( ret !== undefined ) {                                                            //如果函式有回傳值
                        event.result = ret;
                        if ( ret === false ) {                                                            //如果監聽物件的回傳值是false
                            event.preventDefault();                                                            //呼叫preventDefault()方法阻止默認行為
                            event.stopPropagation();                                                           //stopPropagation()方法停止事件傳播
                        }
                    }
                }
            }
        }

        return event.result;
    },
    /**/
}

jQuery.event.fix()會把原生事件修正為jQuery事件物件并回傳,修正不兼容屬性,就是自定義一個物件,保存該事件的資訊,比如:型別、創建的時間、原生事件物件等,有興趣的可以除錯一下,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/34137.html

標籤:jQuery

上一篇:layUI

下一篇:$.ajaxSetup()與$.ajax()區別

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more