<noframes id="bhrfl"><address id="bhrfl"></address>

    <address id="bhrfl"></address>

    <noframes id="bhrfl"><address id="bhrfl"><th id="bhrfl"></th></address>

    <form id="bhrfl"><th id="bhrfl"><progress id="bhrfl"></progress></th></form>

    <em id="bhrfl"><span id="bhrfl"></span></em>

    全部
    常見問題
    產品動態
    精選推薦

    使用事件代理提升 Web 應用性能

    管理 管理 編輯 刪除

    前言

    在構建現代 Web 應用時,我們經常需要處理大量數據,并將其渲染為列表或表格,對每個數據項綁定一個事件處理程序是常見的做法。但隨著數據量的增長,這種做法將會導致嚴重的性能問題;本文旨在介紹事件代理這一解決方案,幫助開發者優化 Web 應用性能,提升用戶體驗。

    常見場景

    在構建現代 Web 應用時,我們會使用各種現代 Web 框架來簡化我們的工作。以 Vue 為例,渲染一個列表的代碼大致如下:

    <template>
        <ul>
            <li v-for="item of someList" :key="item.id" @click="handleItemClick">{{ item.name }}</li>
        </ul>
    </template>
    
    <script setup lang="ts">
    const someList = [
        ...
    ];
    
    const handleItemClick = (e: Event) => {
        ...
    }
    
    </script>   

    someList 中存在多少條數據,頁面中便會存在多少個事件監聽處理程序。當 someList 數據量巨大時,大量的事件監聽器會占用大量內存,并導致嚴重的性能問題。此時我們可以通過事件代理,將事件處理代理給父元素。事件代理利用了事件冒泡的機制,使得只需在父元素上綁定一個事件監聽器,即可處理所有子元素的事件,從而大大減少事件監聽器的數量,代碼如下:

    <template>
        <ul @click="handleListClick">
            <li v-for="item of someList" :key="item.id" :data-id="item.id">{{ item.name }}</li>
        </ul>
    </template>
    
    <script setup lang="ts">
    const someList = [
        ...
    ];
    
    const handleListClick= (e: Event) => {
        const { id } = e.target.dataset;
        if (id !== undefined) {
            ...
        }
    }
    
    </script>   


    通過將子元素需要的數據綁定在 dataset 屬性中,我們可以方便的在事件代理中獲取這些數據,解決了參數傳遞的問題。然而實際開發中,列表項遠比示例中要復雜得多,可能會包含多個圖標、按鈕或其他子元素。

    此時我們就需要一種方法來區分不同的按鈕;同樣我們可以使用 dataset 屬性,為不同的按鈕設置不同的 dataset 屬性值,然后在事件處理程序中通過 event.target.dataset 來判斷哪個按鈕觸發了事件,代碼如下;

    b7d52202501221038236709.png

    <template>
        <ul @click="handleListClick">
            <li v-for="item of someList" :key="item.id">
                <p>文案</p>
                <button :data-id="item.id" data-event="event1">button1</button>
                <button :data-id="item.id" data-event="event2">button2</button>
            </li>
        </ul>
    </template>
    
    <script setup lang="ts">
    
    const someList = [
        ...
    ];
    
    const handleListClick= (e: Event) => {
        const { id, event } = e.target.dataset;
        if (id === undefined || event === undefined) return;
        if (event === "event1") {
            ...
        } else if (event === "event2") {
            ...
        }
    }
    
    </script>   


    有時,列表子項內包含多個無需任何事件處理程序的子元素,而數據綁定在列表子項的 dataset 屬性上。此時,如果點擊子元素, e.target 指向的是子元素,而非列表元素,無法直接獲取 dataset。 e.target.closest(selector) 方法可以向上查找匹配選擇器的最近祖先元素,從而解決這個問題,代碼如下:

    <template>
        <ul @click="handleListClick">
            <li v-for="item of someList" :key="item.id" :data-uid="item.uid">
                <p>文案</p>
                <img src="../avatar.png" />
            </li>
        </ul>
    </template>
    
    <script setup lang="ts">
    
    const someList = [
        ...
    ];
    
    const handleListClick= (e: Event) => {
        let { uid } = e.target.dataset;
        if (uid === undefined) {
            const listItem = e.target.closest("li")
            if (!listItem) return;
            uid = listItem.dataset.uid;
        }
        
        ....
    }
    
    </script>  

    結語

    需要注意的是,事件代理并非適用于所有場景,開發者需要針對具體情況進行實際權衡。在需要處理大量相似元素的事件時,事件代理無疑是一種優秀的解決方案。本文的代碼示例中以 Vue 框架為示例,但核心思想應用在 React 或其他框架上也同樣使用,希望本文能夠幫助開發者更好的使用事件代理,在實際開發中做出更穩妥的選擇。

    請登錄后查看

    plz 最后編輯于2025-01-22 11:11:24

    快捷回復
    回復
    回復
    回復({{post_count}}) {{!is_user ? '我的回復' :'全部回復'}}
    排序 默認正序 回復倒序 點贊倒序

    {{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level }}

    作者 管理員 企業

    {{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
    {{item.is_suggest == 1? '取消推薦': '推薦'}}
    沙發 板凳 地板 {{item.floor}}#
    {{item.user_info.title || '暫無簡介'}}
    附件

    {{itemf.name}}

    {{item.created_at}}  {{item.ip_address}}
    {{item.like_count}}
    {{item.showReply ? '取消回復' : '回復'}}
    刪除
    回復
    回復

    {{itemc.user_info.nickname}}

    {{itemc.user_name}}

    回復 {{itemc.comment_user_info.nickname}}

    附件

    {{itemf.name}}

    {{itemc.created_at}}
    {{itemc.like_count}}
    {{itemc.showReply ? '取消回復' : '回復'}}
    刪除
    回復
    回復
    查看更多
    2782
    {{like_count}}
    {{collect_count}}
    添加回復 ({{post_count}})

    相關推薦

    快速安全登錄

    使用微信掃碼登錄
    {{item.label}} 加精
    {{item.label}} {{item.label}} 板塊推薦 常見問題 產品動態 精選推薦 首頁頭條 首頁動態 首頁推薦
    取 消 確 定
    回復
    回復
    問題:
    問題自動獲取的帖子內容,不準確時需要手動修改. [獲取答案]
    答案:
    提交
    bug 需求 取 消 確 定

    微信登錄/注冊

    切換手機號登錄

    {{ bind_phone ? '綁定手機' : '手機登錄'}}

    {{codeText}}
    切換微信登錄/注冊
    暫不綁定
    亚洲欧美字幕
    CRMEB客服

    CRMEB咨詢熱線 咨詢熱線

    400-8888-794

    微信掃碼咨詢

    CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
    返回頂部 返回頂部
    CRMEB客服