[js高手之路]設計模式系列課程-委托模式實戰微博發佈功能

来源:http://www.cnblogs.com/ghostwu/archive/2017/09/03/7471471.html
-Advertisement-
Play Games

在實際開發中,經常需要為Dom元素綁定事件,如果頁面上有4個li元素,點擊對應的li,彈出對應的li內容,怎麼做呢?是不是很簡單? 大多數人的做法都是:獲取元素,綁定事件 如果頁面上有1w個元素, 甚至10w個元素呢? 繼續使用上述方式,會有很大的性能問題,這個時候,有人可能要問,實際中的項目 哪有 ...


在實際開發中,經常需要為Dom元素綁定事件,如果頁面上有4個li元素,點擊對應的li,彈出對應的li內容,怎麼做呢?是不是很簡單?

大多數人的做法都是:獲取元素,綁定事件

 1     <ul>
 2         <li>跟著ghostwu學習javascript設計模式的應用1</li>
 3         <li>跟著ghostwu學習javascript設計模式的應用2</li>
 4         <li>跟著ghostwu學習javascript設計模式的應用3</li>
 5         <li>跟著ghostwu學習javascript設計模式的應用4</li>
 6     </ul>
 7     <script>
 8         var aLi = document.querySelectorAll( "li" );
 9         aLi.forEach(( ele, ind ) => {
10             ele.addEventListener( "click", ()=> {
11                alert( ele.innerHTML ); 
12             } );
13         });
14     </script>

如果頁面上有1w個元素, 甚至10w個元素呢?

繼續使用上述方式,會有很大的性能問題,這個時候,有人可能要問,實際中的項目 哪有1w個,10w個元素的。一般的項目可能沒有,但是社交類的網站,如微博,其他的如大批量文件上傳等能功能,都是需要動態創建dom元素,而且數量巨大,並且創建出來的dom元素,一般都需要綁定事件和相應的特效。一般情況下,用普通的綁定事件方式是不能給動態創建的dom元素綁定到事件的,所以這裡就產生了兩個問題:

1,當頁面元素很多的時候,如果給這些元素綁定上事件?

2,當動態創建dom時,如果給動態創建的dom綁定上事件和相應的特效?

這就是本文需要討論的模式-委托模式

採用事件委托可以順利解決上面2個問題

那麼,什麼是事件委托呢?

給元素的父元素綁定事件,利用冒泡原理,當子元素觸發事件的時候,會去觸發父元素的事件,然後把相應的業務邏輯放在父元素的事件中去處理。通俗點講就是,子元素不做事件綁定,把綁定事件的操作委托給父元素,這就叫做事件委托, 委托有一個特性,他能夠在事件觸發中,識別到具體是由哪個子元素觸發的,這個就是事件對象的target屬性

 1     <ul>
 2         <li>跟著ghostwu學習javascript設計模式的應用1</li>
 3         <li>跟著ghostwu學習javascript設計模式的應用2</li>
 4         <li>跟著ghostwu學習javascript設計模式的應用3</li>
 5         <li>跟著ghostwu學習javascript設計模式的應用4</li>
 6     </ul>
 7     <script>
 8         var oUl = document.querySelector("ul");
 9         oUl.addEventListener( "click", ( ev )=>{
10             var oEvent = ev || event;
11             target = oEvent.target || oEvent.srcElement;
12             alert( target.innerHTML );
13         });
14     </script>

當我們點擊li的時候,就能通過事件對象oEvent.target識別到觸發事件的li元素, srcElement是相容ie的寫法。

在沒有事件委托之間,我們通過javascript做一個hover的功能,一般這麼做.

 1     <ul>
 2         <li>跟著ghostwu學習設計模式</li>
 3         <li>跟著ghostwu學習設計模式</li>
 4         <li>跟著ghostwu學習設計模式</li>
 5         <li>跟著ghostwu學習設計模式</li>
 6         <li>跟著ghostwu學習設計模式</li>
 7     </ul>
 8     <script>
 9         var aLi = document.getElementsByTagName( "li" );
10         for( var i = 0, len = aLi.length; i < len; i++ ){
11             aLi[i].onmouseover = function(){
12                 this.style.backgroundColor = 'red';
13             }
14             aLi[i].onmouseout = function(){
15                 this.style.backgroundColor = '';
16             }
17         }
18     </script>

如果li元素很多,就會產生性能問題,而採用委托模式,我們可以這麼做

 1     <ul>
 2         <li>跟著ghostwu學習設計模式1</li>
 3         <li>跟著ghostwu學習設計模式2</li>
 4         <li>跟著ghostwu學習設計模式3</li>
 5     </ul>
 6     <script>
 7         var aLi = document.getElementsByTagName("li");
 8         var oUl = document.getElementsByTagName( "ul" )[0];
 9         oUl.onmouseover = function( ev ){
10             var oEvent = ev || event;
11             var target = oEvent.target || oEvent.srcElement;
12             if ( target.tagName.toLowerCase() == 'li' ) {
13                 target.style.backgroundColor = 'red';
14             }
15         }
16         oUl.onmouseout = function( ev ){
17             var oEvent = ev || event;
18             var target = oEvent.target || oEvent.srcElement;
19             if ( target.tagName.toLowerCase() == 'li' ) {
20                 target.style.backgroundColor = '';
21             }
22         }
23     </script>

通過事件委托,把元素綁定到父元素,大大提高性能

至此,我們解決了第一個問題:當頁面元素很多的時候,如果給這些元素綁定上事件

對於新創建的dom元素,普通綁定事件的方式,是不能綁定到這些dom元素的

 1      <input type="button" value="創建">
 2    <ul>
 3        <li>ghostwu1</li>
 4        <li>ghostwu2</li>
 5    </ul>
 6     <script>
 7         var oBtn = document.getElementsByTagName( "input" )[0];
 8         var oUl = document.getElementsByTagName( "ul" )[0];
 9         var aLi = document.getElementsByTagName( "li" );
10         oBtn.onclick = function(){
11             var oLi = document.createElement( "li" );
12             oLi.innerHTML = 'ghostwu';
13             oUl.appendChild( oLi );
14         }
15         for( var i = 0, len = aLi.length; i < len; i++ ){
16             aLi[i].onmouseover = function(){
17                 this.style.backgroundColor = 'red';
18             }
19             aLi[i].onmouseout = function(){
20                 this.style.backgroundColor = '';
21             }
22         }
23 
24     </script>

新創建的li元素,是不能綁定到onmouseover和onmouseout事件的,我們採用委托模式之後,可以這麼做

 1     <input type="button" value="創建">
 2     <ul>
 3         <li>ghostwu1</li>
 4         <li>ghostwu2</li>
 5     </ul>
 6     <script>
 7         var oBtn = document.getElementsByTagName("input")[0];
 8         var oUl = document.getElementsByTagName("ul")[0];
 9         var aLi = document.getElementsByTagName("li");
10         oBtn.onclick = function () {
11             var oLi = document.createElement("li");
12             oLi.innerHTML = 'ghostwu';
13             oUl.appendChild(oLi);
14         }
15         oUl.onmouseover = function( ev ){
16             var oEvent = ev || event;
17             var target = oEvent.target || oEvent.srcElement;
18             if ( target.tagName.toLowerCase() == 'li' ) {
19                 target.style.backgroundColor = 'red';
20             }
21         }
22         oUl.onmouseout = function( ev ){
23             var oEvent = ev || event;
24             var target = oEvent.target || oEvent.srcElement;
25             if ( target.tagName.toLowerCase() == 'li' ) {
26                 target.style.backgroundColor = '';
27             }
28         }
29     </script>

至此,我們解決了第二個問題:當動態創建dom時,如果給動態創建的dom綁定上事件和相應的特效

最後,我們結合委托模式,來實戰一個微博發佈的功能,微博發佈之後,給動態創建的dom元素添加手風琴摺疊功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link href="https://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-offset-3 col-md-6">
                <form class="form-horizontal">
                    <div class="form-group">
                        <input id="title" type="text" class="form-control" placeholder="請輸入標題">
                    </div>
                    <div class="form-group">
                        <textarea name="" id="txt" cols="30" rows="5" class="form-control"></textarea>
                    </div>
                    <div class="form-group">
                        <input type="button" value="發佈" class="btn btn-primary" id="btn-publish">
                    </div>
                </form>
            </div>
            <div class="col-md-offset-3 col-md-6" id="content">
            </div>
        </div>
    </div>
</body>
<script>
    var oBtnPublish = document.getElementById("btn-publish");
    var aTpl = [
        '<div class="panel panel-success">',
           '<div class="panel-heading">',
                '<h4 class="panel-title">',
                   '<a href="javascript:;">',
                    '[title]',
                    '</a>',
                '</h4>',
            '</div>',
            '<div class="panel-body">',
                '[content]',
            '</div>',
        '</div>'
    ];
    var oContent = document.getElementById( "content" ),
        str = aTpl.join( "" ),
        title = '', content = '', panelParent = null;
    oBtnPublish.onclick = function(){
        str = aTpl.join( "" );
        title = document.getElementById( "title" ).value;
        txt = document.getElementById( "txt" ).value;
        str = str.replace( /\[title\]/, title );
        str = str.replace( /\[content\]/, txt );
        oContent.innerHTML += str;
    }
    oContent.onclick = function( ev ){
        var oEvent = ev || event;
        var target = oEvent.target || oEvent.srcElement;
        if ( target.tagName.toLowerCase() == 'a' ) {
            panelParent = target.parentNode.parentNode.parentNode;
            if ( panelParent.children[1].style.display == "block" ||  panelParent.children[1].style.display == '' ) {
                panelParent.children[1].style.display = 'none';
            } else {
                panelParent.children[1].style.display = 'block';
            }
        }
    }
</script>
</html>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在一個項目還是單體架構的時候,所有的js,css,image都會在一個web網站上,看起來並沒有什麼問題,比如下麵這樣: 但是當web網站流量起來的時候,這個單體架構必須要進行橫向擴展,而在原來的架構中靜態資源這羊毛是出在單體架構這頭羊身上,所以橫向多少 個單體,就有多少個靜態資源文件夾,比如下麵這 ...
  • 組合模式主要應對的是當一個具體實現一個介面的類中,含有更多的該介面的實例的樹形介面,當執行此介面的方法時怎樣賦予其中的相同介面的方法實現 1.介面 2.實現介面的類 1)單一的類 2.具有樹形實現介面的類 3.應用 ...
  • 迭代器模式簡單的說就是將含有相同類型的"集合"但不同"集合"類型的兩類甚至更多類融合在一起進行遍歷 . 1.含有的相同類型(這裡以菜單為例) 2.將兩種不同方式,統一繼承Iterator介面 3.存儲“集合”的不同方式(其實可以統一繼承一個含有createIterator方法的介面) 1) 數組的存 ...
  • 目錄 一個特例 在正式開始之前,我們先來說一個特例。 在構造函數中,this上的值會在創建實例的時候被綁定到新創建的實例上。不適用於下麵的判斷方法,所以特此說明。 開始判斷 下麵是一個典型例子,我們的分析從這裡開始。 法則一:對象方法中的this指向對象本身(箭頭函數形式的除外) 法則二:多層嵌套函 ...
  • javascript(JS)的組成? DOM 文檔對象模型 BOM 瀏覽器對象模型 ECMAScript javascript(JS)在頁面中處理了什麼事情? 特效交互 數據交互 邏輯操作 常見特效的原理 通過js修改元素的css樣式,來操作元素的變化 js可以寫在哪 寫在寫標簽內部,行間事件(不允 ...
  • ###理解對象 ECMA-262把對象定義為:“無序屬性的集合,其屬性可以包含基本值、對象或者函數。”嚴格來講,這就相當於說對象是一組沒有特定順序的值。對象的每個屬性或方法都有一個名字,而每個名字都映射到一個值。 我們可以把ECMAScript的對象想象成散列表:無非就是一組名值對,其中的值可以是數 ...
  • 概述 對於企業級後臺產品來說,Table 應該是使用最頻繁的組件了,它通常比 Form 和 Chart 的使用還頻繁。對於這麼一個常用的組件,我們決定要把它從 RSuite 中單獨出來開發,並且要具有一定的通用性,適應很多場景。 首先看一下,Table 完成的效果。 預覽地址: https://rs ...
  • 粗體判斷js中的數據類型有一下幾種方法:typeof、instanceof、 constructor、 prototype、 $.type()/jquery.type(),接下來主要比較一下這幾種方法的異同。 先舉幾個例子: var a = "iamstring.";var b = 222;var ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...