整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          jQuery 添加和刪除HTML元素

          節我們學習如何使用 jQuery 中的方法來添加和刪除 HTML 元素。

          jQuery 中用于添加 HTML 元素的方法有如下幾種:

          方法

          描述

          append()

          在所選元素的末尾插入內容

          prepend()

          在選定元素的開頭插入內容

          after()

          在選定元素后插入內容

          before()

          在選定元素之前插入內容

          而用于刪除元素的方法有:

          方法

          描述

          remove()

          刪除被選元素容,包括子元素

          empty()

          刪除被選元素的所有子節點和內容

          append()方法

          append() 方法可以在指定元素的末尾插入內容。

          語法如下:

          $(selector).append(content,function(index,html))
          
          • content:規定要插入的內容,可以包含 HTML 元素、jQuery 對象、DOM 元素。
          • function(index,html):規定返回待插入內容的函數,index 為集合中元素的索引位置,html 為被選元素的當前 HTML

          示例:

          我們來看下面這個例子:

          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="utf-8">
          <title>jQuery_俠課島(9xkd.com)</title>
          <script src="jquery-3.5.1.min.js"></script>
          <script>
            $(function(){
              $("button").click(function(){
                $("p").append("俠課島");
              });
            });
          </script>
          </head>
          <body>
            <p>你好,我的名字叫做:</p>
            <button>點擊追加文本</button>
          </body>
          </html>
          

          點擊按鈕,在指定的 <p> 標簽末尾添加文本內容 “俠課島”,我們可以在瀏覽器中看一下演示結果:

          除了文本內容,我們還可以在元素中添加 HTML

          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="utf-8">
          <title>jQuery_俠課島(9xkd.com)</title>
          <script src="jquery-3.5.1.min.js"></script>
          <script>
            $(function(){
              $("button").click(function(){
                $("ul").append("<li>strawberry</li>");
              });
            });
          </script>
          </head>
          <body>
            <ul>
              <li>apple</li>
              <li>pear</li>
              <li>peach</li>
              <li>watermelon</li>
            </ul>
            <button>點擊追加文本</button>
          </body>
          </html>
          
          

          在瀏覽器中的演示結果:

          prepend()方法

          prepend() 方法其實和 append() 方法類似,語法也差不多。但是 prepend() 方法主要用于在被選元素的開頭插入指定內容。

          語法如下:

          $(selector).prepend(content,function(index,html))
          

          示例:

          我們將上述示例中的 append() 方法改成 prepend() 方法:

          $(function(){
              $("button").click(function(){
                $("ul").prepend("<li>strawberry</li>");
              });
          });
          

          然后看一下在瀏覽器中的演示結果:

          after()方法

          after() 方法用于在被選元素后插入指定的內容。看起來 after() 方法和 append() 方法的作用好像差不多,但是其實兩個方法還是有區別的。 append() 方法是在被選元素的結尾插入內容,插入的內容仍然在元素內部。而 after() 插入的內容會重新起一行,與被選擇的元素并沒有什么邏輯上的聯系。

          示例:

          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="utf-8">
          <title>jQuery_俠課島(9xkd.com)</title>
          <script src="jquery-3.5.1.min.js"></script>
          <script>
            $(function(){
              $("button").click(function(){
                $("p").after("<p>俠課島</p>");
              });
            });
          </script>
          </head>
          <body>
            <p>你好,我的名字叫做:</p>
            <button>點擊追加文本</button>
          </body>
          </html>
          

          在瀏覽器中的演示效果:

          before()方法

          before() 方法用于在被選元素之前插入指定的內容。它和 prepend() 方法的區別在于一個在被選元素內插入內容,一個在被選元素外。

          注意 before() 方法和 after() 方法都是在被選元素外插入內容。append()prepend() 方法都是在被選元素內插入內容。

          示例:

          例如將上述示例中的方法改為 before

          $(function(){
              $("button").click(function(){
                $("p").before("<p>俠課島</p>");
              });
          });
          

          在瀏覽器中的演示效果:

          remove()方法

          remove() 方法用于刪除被選元素及其子元素。該方法也會刪除被選元素的數據和事件。

          示例:

          例如下面這個例子:

          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="utf-8">
          <title>jQuery_俠課島(9xkd.com)</title>
          <script src="jquery-3.5.1.min.js"></script>
          <script>
            $(function(){
              $("button").click(function(){
                $("p").remove();
              });
            });
          </script>
          </head>
          <body>
            <p>你好,歡迎來到俠課島!</p>
            <button>點擊刪除</button>
          </body>
          </html>
          

          在瀏覽器中的演示效果:

          從上圖中可以看到,remove() 方法將指定的 p 元素連標簽帶元素全部刪除。

          empty()方法

          empty() 方法用于刪除被選元素的所有子節點和內容。該方法不會移除元素本身,或它的屬性。

          示例:

          我們講上述示例中的 remove() 方法改為empty() 方法,看看有什么不同:

          $(function(){
              $("button").click(function(){
                $("p").empty();
              });
          });
          

          在瀏覽器中的演示效果:

          可以看到 empty() 方法只會刪除指定元素中的內容,不會刪除元素本身,當然如果元素上有屬性,屬性也不會被刪除,大家可以自己試一下。

          源:https://www.cnblogs.com/VanFan/p/15685910.html

          一、犯錯經歷

          1.1 故事背景

          最近有個需求大致的背景類似:

          我已經通過一系列的操作拿到一批學生的考試成績數據,現在需要篩選成績大于 95 分的學生名單。

          善于寫 bug 的我,三下五除二完成了代碼的編寫:

          @Test
          public void shouldCompile() {
              for (int i = 0; i < studentDomains.size(); i++) {
                  if (studentDomains.get(i).getScore() < 95.0) {
                      studentDomains.remove(studentDomains.get(i));
                  }
              }
              System.out.println(studentDomains);
          }
          

          測試數據中四個學生,成功篩選出了兩個 95 分以上的學生,測試成功,打卡下班。

          [StudentDomain{id=1, name='李四', subject='科學', score=95.0, classNum='一班'}, StudentDomain{id=1, name='王六', subject='科學', score=100.0, classNum='一班'}]
          

          1.2 貌似,下不了班!

          從業 X 年的直覺告訴我,事情沒這么簡單。

          但是自測明明沒問題,難道寫法有問題?那我換個寫法(增強的 for 循環):

          @Test
          public void commonError() {
              for (StudentDomain student : studentDomains) {
                  if (student.getScore() < 95.0) {
                      studentDomains.remove(student);
                  }
              }
              System.out.println(studentDomains);
          }
          

          好家伙,這一試不得了,直接報錯:ConcurrentModificationException

          • 普通 for 循環“沒問題”,增強 for 循環有問題,難道是【增強 for 循環】的問題?

          1.3 普通 for 循環真沒問題嗎?

          為了判斷普通 for 循環是否有問題,我將原代碼加了執行次數的打印:

          @Test
          public void shouldCompile() {
              System.out.println("studentDomains.size():" + studentDomains.size());
              int index = 0;
              for (int i = 0; i < studentDomains.size(); i++) {
                  index ++;
                  if (studentDomains.get(i).getScore() < 95.0) {
                      studentDomains.remove(studentDomains.get(i));
                  }
              }
              System.out.println(studentDomains);
              System.out.println("執行次數:" + index);
          }
          

          這一加不得了,我的 studentDomains.size() 明明等于 4,怎么循環體內只執行了 2 次。

          更巧合的是:執行的兩次循環的數據,剛好都符合我的篩選條件,故會讓我錯以為【需求已完成】。

          二、問題剖析

          一個個分析,我們先看為什么普通 for 循環比我們預計的執行次數要少。

          2.1 普通 for 循環次數減少

          這個原因其實稍微有點兒開發經驗的人應該都知道:在循環中刪除元素后,List 的索引會自動變化,List.size() 獲取到的 List 長度也會實時更新,所以會造成漏掉被刪除元素后一個索引的元素。

          比如:循環到第 1 個元素時你把它刪了,那么第二次循環本應訪問第 2 個元素,但這時實際上訪問到的是原來 List 的第 3 個元素,因為第 1 個元素被刪除了,原來的第 3 個元素變成了現在的第 2 個元素,這就造成了元素的遺漏。

          2.2 增強 for 循環拋錯

          • 我們先看 JDK 源碼中 ArrayListremove() 源碼是怎么實現的:
          public boolean remove(Object o) {
              if (o == null) {
                  for (int index = 0; index < size; index++)
                      if (elementData[index] == null) {
                          fastRemove(index);
                          return true;
                      }
              } else {
                  for (int index = 0; index < size; index++)
                      if (o.equals(elementData[index])) {
                          fastRemove(index);
                          return true;
                      }
              }
              return false;
          }
          

          只要不為空,程序的執行路徑會走到 else 路徑下,最終調用 fastRemove() 方法:

          private void fastRemove(int index) {
              modCount++;
              int numMoved = size - index - 1;
              if (numMoved > 0)
                  System.arraycopy(elementData, index+1, elementData, index, numMoved);
              elementData[--size] = null;
          }
          

          fastRemove() 方法中,看到第 2 行【把 modCount 變量的值加 1】。

          • 增強 for 循環實際執行

          通過編譯代碼可以看到:增強 for 循環在實際執行時,其實使用的是Iterator,使用的核心方法是 hasnext()next()

          next() 方法調用了 checkForComodification()

          final void checkForComodification() {
          	if (modCount != expectedModCount)
                   throw new ConcurrentModificationException();
           	}
          

          看到 throw new ConcurrentModificationException() 那么就可以結案了:

          因為上面的 remove() 方法修改了 modCount 的值,所以這里肯定會拋出異常。

          三、正確方式

          既然知道了普通 for 循環和增強 for 循環都不能用的原因,那么我們先從這兩個地方入手。

          3.1 優化普通 for 循環

          我們知道使用普通 for 循環有問題的原因是因為數組坐標發生了變化,而我們仍使用原坐標進行操作。

          • 移除元素的同時,變更坐標。
          @Test
          public void forModifyIndex() {
              for (int i = 0; i < studentDomains.size(); i++) {
                  StudentDomain item = studentDomains.get(i);
                  if (item.getScore() < 95.0) {
                      studentDomains.remove(i);
                      // 關鍵是這里:移除元素同時變更坐標
                      i = i - 1;
                  }
              }
              System.out.println(studentDomains);
          }
          
          • 倒序遍歷

          采用倒序的方式可以不用變更坐標,因為:后一個元素被移除的話,前一個元素的坐標是不受影響的,不會導致跳過某個元素。

          @Test
          public void forOptimization() {
              List<StudentDomain> studentDomains = genData();
              for (int i = studentDomains.size() - 1; i >= 0; i--) {
                  StudentDomain item = studentDomains.get(i);
                  if (item.getScore() < 95.0) {
                      studentDomains.remove(i);
                  }
              }
              System.out.println(studentDomains);
          }
          

          3.2 使用 Iterator 的 remove()

          @Test
          public void iteratorRemove() {
              Iterator<StudentDomain> iterator = studentDomains.iterator();
              while (iterator.hasNext()) {
                  StudentDomain student = iterator.next();
                  if (student.getScore() < 95.0) {
                      iterator.remove();
                  }
              }
              System.out.println(studentDomains);
          }
          

          你肯定有疑問,為什么迭代器的 remove() 方法就可以呢,同樣的,我們來看看源碼:

          public void remove() {
              if (lastRet < 0)
                  throw new IllegalStateException();
              checkForComodification();
              try {
                  ArrayList.this.remove(lastRet);
                  cursor = lastRet;
                  lastRet = -1;
                  expectedModCount = modCount;
              } catch (IndexOutOfBoundsException ex) {
                  throw new ConcurrentModificationException();
              }
          }
          

          我們可以看到:每次執行 remove() 方法的時候,都會將 modCount 的值賦值給 expectedModCount,這樣 2 個變量就相等了。

          3.3 Stream 的 filter()

          了解 Stream 的童鞋應該都能想到該方法,這里就不過多贅述了。

          @Test
          public void streamFilter() {
              List<StudentDomain> studentDomains = genData();
              studentDomains = studentDomains.stream().filter(student -> student.getScore() >= 95.0).collect(Collectors.toList());
              System.out.println(studentDomains);
          }
          

          3.4 Collection.removeIf()【推薦】

          JDK1.8 中,Collection 以及其子類新加入了 removeIf() 方法,作用是按照一定規則過濾集合中的元素。

          @Test
          public void removeIf() {
              List<StudentDomain> studentDomains = genData();
              studentDomains.removeIf(student -> student.getScore() < 95.0);
              System.out.println(studentDomains);
          }
          

          看下 removeIf() 方法的源碼,會發現其實底層也是用的 Iteratorremove() 方法:

          default boolean removeIf(Predicate<? super E> filter) {
              Objects.requireNonNull(filter);
              boolean removed = false;
              final Iterator<E> each = iterator();
              while (each.hasNext()) {
                  if (filter.test(each.next())) {
                      each.remove();
                      removed = true;
                  }
              }
              return removed;
          }
          

          四、總結

          詳細認真的看完本文的話,最大感悟應該是:還是源碼靠譜!

          4.1 啰嗦幾句

          其實在剛從事 Java 開發的時候,這個問題就困擾過我,當時只想著解決問題,所以采用了很笨的方式:

          新建一個新的 List,遍歷老的 List ,將滿足條件的元素放到新的元素中,這樣的話,最后也完成了當時的任務。

          現在想一想,幾年前,如果就像現在一樣,抽空好好想想為什么不能直接 remove() ,多問幾個為什么,估計自己會比現在優秀很多吧。

          當然,只要意識到這個,什么時候都不算晚,共勉!

          4.2 文中代碼示例

          https://github.com/vanDusty/JDK/tree/master/code-optimization

          信息爆炸的互聯網時代,網絡爬蟲如同一把神奇的鑰匙,幫助我們打開海量網頁內容的大門。然而,在實際操作過程中,不規范的網頁格式、紛繁復雜的干擾元素,特別是那些占據屏幕空間、影響閱讀體驗的廣告,往往成為獲取高質量數據的一大阻礙。因此,一款專為網絡爬蟲設計的HTML廣告移除神器顯得尤為重要。這款工具利用強大的HtmlAgilityPack庫,能夠迅速而精準地識別并剔除帶有class='ad'屬性的廣告標簽,讓抓取到的頁面內容回歸其最純粹的本質。

          代碼執行效果如圖:


          調用代碼:

          // 假設這是從某個網頁上抓取的包含廣告的“混亂”HTML文本

          string clutteredHtml = @"<html><head><title>網頁標題</title></head><body><div class='header'><h1>網站標題</h1></div><div class='nav'><ul><li><a href='#'>首頁</a></li><li><a href='#'>關于我們</a></li><li><a href='#'>聯系我們</a></li></ul></div><div class='content'><p>正文內容1...</p><p>正文內容2...</p><p>正文內容3...</p></div><div class='ad'>廣告1...</div><div class='ad'>廣告2...</div><div class='ad'>廣告3...</div><div class='footer'><p>© 2023 版權所有</p></div></body></html>";

          // 使用廣告移除功能對抓取的“臟亂差”HTML進行深度清理

          string polishedHtml = ScrubAndRemoveAds(clutteredHtml);

          // 廣告移除及HTML內容凈化的具體實現方法

          public static string ScrubAndRemoveAds(string messyHtmlContent)

          {

          // 創建一個可以解析和理解HTML結構的對象,并載入抓取的HTML文本

          var htmlParser = new HtmlDocument();

          htmlParser.LoadHtml(messyHtmlContent);

          // 掃描整個HTML文檔,找到所有標記為廣告(class屬性值為"ad")的部分并刪除

          foreach (var adElement in htmlParser.DocumentNode.SelectNodes("//div[@class='ad']"))

          {

          adElement.Remove(); // 刪除廣告區域

          }

          // 返回已經清除廣告后的清爽HTML文本

          return htmlParser.DocumentNode.OuterHtml;

          }

          這個代碼有效地解決了網絡爬蟲在抓取數據時遇到的廣告難題。無論對于追求極致閱讀體驗的個人用戶,還是力求優化數據質量、節省資源成本的企業級用戶,這個小工具都展現出了卓越的價值。無需繁瑣的操作流程,一鍵即可輕松擺脫廣告干擾,讓你獲得高質量、純凈的網頁內容。無論是單獨處理單個網頁,還是批量清洗大量的抓取數據,此工具都能得心應手,為您提供高效便捷的網絡數據整理解決方案。朋友們,喜歡就拿去吧,別忘記關注我:代碼領域的詩人XY,我是一個樂于分享的人。樂于將自己的知識和經驗分享給朋友們,幫助你們解決問題,啟發你們的思考。我相信,只有通過分享和交流,我們才能不斷進步,才能不斷創新。


          主站蜘蛛池模板: 日韩成人无码一区二区三区| 亚洲综合无码一区二区三区| 亚洲A∨精品一区二区三区| 国内精品一区二区三区在线观看| 中文字幕无码一区二区三区本日| 无码丰满熟妇浪潮一区二区AV| 亚洲夜夜欢A∨一区二区三区| 波多野结衣一区二区三区88| 国产在线精品一区二区三区直播| 精品乱码一区二区三区四区| 色窝窝免费一区二区三区 | 久久伊人精品一区二区三区| 动漫精品第一区二区三区| 人妻av综合天堂一区| 亚洲综合无码一区二区痴汉| 久久无码AV一区二区三区| 免费看无码自慰一区二区| 日韩AV无码一区二区三区不卡毛片 | 日本在线电影一区二区三区| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 亚洲av色香蕉一区二区三区| 亚洲国产综合无码一区二区二三区 | 一区 二区 三区 中文字幕| 香蕉久久av一区二区三区| 大香伊蕉日本一区二区| 国产主播一区二区| 国产精品亚洲一区二区三区在线观看| 伊人精品视频一区二区三区| 精品一区二区ww| 国产AV午夜精品一区二区三区| 濑亚美莉在线视频一区| 一区二区三区四区免费视频| 一区二区三区免费视频观看| 亚洲熟妇无码一区二区三区| 国产精品无码一区二区三级| 日韩十八禁一区二区久久| 亚洲欧美国产国产综合一区| 久久国产视频一区| 国产一区二区视频在线观看| 精品日韩一区二区| 成人区精品一区二区不卡亚洲|