整合營銷服務商

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

          免費咨詢熱線:

          第47節 HTML5擴展-操作元素內容-零點程序員-王唯

          內容是《Web前端開發之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學習。

          Element.innerHTML屬性:

          操作元素內HTML內容,即可設置或獲取使用HTML代碼表示的元素的后代;

          在讀取時,該屬性返回與調用元素的所有子節點(包括元素、注釋和文本節點)對應的HTML代碼字會串,如:

          <div id="mydiv">
              <h2>零點程序員</h2>
              <ul id="myList">
                  <li>HTML</li>
                  <li class="current">CSS</li>
                  <li>JavaScript</li>
              </ul>
          </div>
          <script>
          var mydiv = document.getElementById("mydiv");
          console.log(mydiv.innerHTML);
          </script>

          注:不同瀏覽器返回的文本格式有可能不同,比如,部分低版本會把所有標簽轉換為大寫;另外,瀏覽器會按照原先文檔的格式返回,包括空格和縮進;

          在寫入時,會將給定的字符串解析為DOM子樹,將用這個DOM子樹替換調用元素原先的所有子節點;如果設置的值是文本沒有HTML標簽,其結果就是純文本,也就是文本節點,此時,如果該文本節點包含字符&、<或>, innerHTML將這些字符分別返回為&、<和>;

          mydiv.innerHTML = "零點程序員 & zeronetwork 主講><b>\"王唯\"</b>";
          console.log(mydiv.innerHTML);
          mydiv.innerHTML = "零點程序員";

          設置元素的innerHTML屬性將會刪除該元素的所有后代,因此,如果要保留原來的內容,可以在innerHTML屬性的基礎上,可以使用+=進行賦值,也就達到了追加內容的效果;

          mydiv.innerHTML += "<b>大師哥王唯</b>";

          如果設置innerHTML屬性時,使用了不合法的HTML代碼,瀏覽器會自動修正,但要避免出現這種問題;

          另外,不允許document對象使用該屬性,如果使用了,會靜默失敗;

          設置了innerHTML屬性后,可以像訪問文檔中的其他節點一樣訪問新創建的節點;

          console.log(mydiv.childNodes);

          從本質上來看,設置innerHTML屬性,瀏覽器會把給定的值被解析為HTML或者XML,結果就是一個DocumentFragment對象,其中保存著代表元素的DOM節點,然后再append到元素中;

          innerHTML也有一些限制,在多數瀏覽器中,通過innerHTML插入的<script> 元素不會被執行,因為有可能會產生潛在的安全問題;

          var content = document.getElementById("content");
          content.innerHTML = "<script>alert('wangwei');<\/script>";

          即使如此,使用innerHTML屬性也不能消除潛在的風險,比如,繞過<script>標簽,把腳本綁定到相關的事件中;

          mydiv.innerHTML = "<img src='nourl' onerror='alert(\"加載圖片出錯啦\")'>";

          通過innerHTML寫入<style>元素就可以運行;如:

          mydiv.innerHTML = "<style>body{background-color:purple;}</style>";
          // 放在head中
          document.head.innerHTML += "<style>body{background-color:purple;}</style>";
          console.log(document.head.innerHTML);

          在設置innerHTML屬性時,雖然元素的所有子元素被替換,其仍被保存在內存中,如果事先有變量在引用這些子元素,在設置innerHTML后,這些變量仍將保持對原始子元素的引用;

          var mydiv = document.getElementById("mydiv");
          var h2 = mydiv.querySelector("h2");
          mydiv.innerHTML = "新內容";
          console.log(h2);
          mydiv.appendChild(h2);

          并不是所有元素都有innerHTML屬性,不支持的有<col> <colgroup> <frameset> <head> <html> <style> <table> <tbody> <thead> <tfoot> <title> <tr>

          無論什么時候插入外界的HTML內容時,都應該對HTML進行無害化處理,IE8提供了window.toStaticHTML()方法,接受一個HTM字符串,返回一個經過無害化處理后的版本;

          var mydiv = document.getElementById("mydiv");
          var text = "<a href='#' onclick='alert(\"hi\")'>zeronetwork</a>";
          // mydiv.innerHTML = text;
          var sanitized = window.toStaticHTML(text);  // [?s?n?ta?zd]
          console.log(sanitized);  // 非IE會拋出異常
          mydiv.innerHTML = sanitized;

          小示例:

          使用innerHTML創建一種機制用于將消息記錄到頁面中的一個元素中;

          <style>
          .box{width: 600px;height: 300px;
          border:1px solid black; padding: 2em; overflow: hidden scroll;}
          </style>
          <div class="box">
              <h2>日志:</h2>
              <div class="log"></div>
          </div>
          <script>
          function log(msg){
              var logEle = document.querySelector(".log");
              var time = new Date().toLocaleTimeString();
              logEle.innerHTML += time + ": " + msg + "<br/>"; 
          }
          // log("打印一些數據");
          // 定義一個事件處理程序
          function logEvent(event){
              var msg = "Event <strong>" + event.type + "</strong> at <em>" + 
                  event.clientX + "," + event.clientY + "</em>";
              log(msg);
          }
          // 綁定事件處理程序
          var boxEle = document.querySelector(".box");
          boxEle.addEventListener("mousedown", logEvent);
          boxEle.addEventListener("mouseup", logEvent);
          boxEle.addEventListener("click", logEvent);
          boxEle.addEventListener("mouseenter", logEvent);
          boxEle.addEventListener("mouseleave", logEvent);
          </script>

          Element.outerHTML屬性:

          與innerHTML屬性基本一致,不同點是,innerHTML是訪問和設置元素的所有子節點,而outerHTML屬性不僅包括它的所有子節點,也包括它本身;

          console.log(mydiv.outerHTML);
          mydiv.outerHTML = "<p><h2>零點網絡</h2></p>";

          如果元素沒有父元素,即如果它是文檔的根元素,在設置其outerHTML屬性將拋出異常,如:

          document.documentElement.outerHTML = "content"; // 異常

          這個屬性應用的機會非常少;

          HTMLElement.innerText屬性:

          可以操作元素中包含的所有文本,最初是由IE實現的,后來被納入標準中;

          var mydiv = document.getElementById("mydiv");
          console.log(mydiv.innerText);
          mydiv.innerText = "零點程序員";
          console.log(mydiv.innerText);

          輸出一個文檔樹時,無論文本位于文檔樹中的什么位置,會按照由淺入深的順序,將子文檔樹中的所有文本拼接起來;

          <div id="content">
              <p>零點網絡<strong>zerontwork</strong>是一家從事IT教育的公司</p>
              <ul>
                  <li>HTML</li>
                  <li>CSS</li>
                  <li>Javascript</li>
              </ul>
          </div>
          <script>
          var content = document.getElementById("content");
          console.log(content.innerText);
          // 返回
          // 零點網絡zerontwork是一家從事IT教育的公司
          //
          // HTML/
          // CSS
          // Javascript
          </script>

          由于不同瀏覽器處理空白字符的方式不同,因此輸出的文本可能會也可能不會包含原始的HTML代碼中的縮進;

          使用innerText屬性設置內容時,會移除原先所有的子節點,將永遠只會生成當前節點的一個子文本節點;如果設置的內容包括HTML標簽,會自動被轉碼,也就是說,會對所有出現在文本中的HTML語法字符進行編碼(>、<、”、&);

          mydiv.innerText = "<h2>wangwei</h2>";  // < > 會被轉義

          因為在訪問innerText屬性時,其會過濾掉html標簽,所以可以利用它的這個特點,快速過濾掉元素的HTML標簽,即把innerText設置為innerText;

          content.innerText = content.innerText;
          console.log(content.innerText);

          如果在設置innerHTML屬性時,賦給的就是純文本字符串,那它就與innerText屬性作用一樣了;

          var mydiv = document.getElementById("mydiv");
          mydiv.innerText = "零點網絡 zeronetwork";
          mydiv.innerHTML = "零點網絡 zeronetwork";
          mydiv.innerText = "零點網絡\nzeronetwork";  // 有br
          mydiv.innerHTML = "零點網絡\nzeronetwork";  // 無br,但源碼格式有換行

          因為innerHTML是解析html標簽的,而\n不是標簽,所以當作空格被忽略了;但在innerText中,瀏覽器遇到\n,就會執行換行,所以把它解析為<br>;

          在實際使用中,如果要過濾html標簽,可以使用正則,如:

          // 去除html標簽可以使用正則
          content.innerHTML = content.innerHTML.replace(/<.+?>/img,"");
          console.log(content.innerText);  // 沒有格式<br>
          console.log(content.innerHTML);  // 沒有格式<br>

          HTMLElement.outerText屬性:

          與innerText一樣,只不過替換的是元素(包括子節點)本身;其是一個非標準屬性;

          var mydiv = document.getElementById("mydiv");
          console.log(mydiv.innerText);
          console.log(mydiv.outerText); // 返回值與innerText一致

          在讀取文本值時,outerText和innerText的結果完全一樣;

          但在寫模式下,outerText就完全不同了,其本身都會被新的文本節點都替代,從文檔中被刪除,但其仍然被保存在內存中,如果有變量引用,還可以再利用;

          mydiv.outerText = "零點程序員";
          console.log(mydiv);  // 依然保留著原有的引用

          FF不支持outerText屬性,如:

          mydiv.outerText = "零點程序員";  // 在FF中失效
          // 在FF中返回undefined,如果有上一行,會打印出“零點程序員”,但這和內置的outerText沒有關系
          console.log(mydiv.outerText);

          在實際使用中,只會用到innerHTML和innerText,其他兩個一般不用,也沒有多大的實際意義;

          Node.textContent屬性:

          DOM3規定了一個屬性textContent,該屬性被定義在Node接口中,它的作用類似innerText屬性,返回一個節點及其后代的所有文本內容;

          var mydiv = document.getElementById("mydiv");
          console.log(mydiv.innerText);
          console.log(mydiv.textContent); // 返回值與innerText基本一致,但格式不一樣

          如果設置textContent屬性,會刪除該元素的所有子節點,并被替換為包含指定字符串的一個單獨的文本節點;

          var mydiv = document.getElementById("mydiv");
          mydiv.textContent = "大師哥王唯";
          mydiv.textContent = "<h3>大師哥王唯</h3>";  // 會被轉碼
          console.log(mydiv.textContent);
          console.log(mydiv.childNodes);  // NodeList [text]

          如果節點是文本節點,此屬性可用于取代 nodeValue 屬性,如;

          var h2 = document.querySelector("h2").firstChild; // 取得文本節點
          console.log(h2.textContent); // zeronetwork
          console.log(h2.nodeValue);   // zeronetwork
          h2.nodeValue = "零點程序員";
          console.log(h2.textContent); // 零點程序員
          console.log(h2.nodeValue);   // 零點程序員

          可以看出,兩者是聯動的;

          如果事先有變量引用著它的后代節點,即使節點使用該方法移除所有后代節點,但被引用的后代節點依然存在,可以被再次利用;

          var content = document.getElementById("content");
          var h2 = content.querySelector("h2");  // content中的h2
          content.textContent = "王唯";
          console.log(content.textContent);
          console.log(h2);  // <h2>zeronetwork</h2>
          console.log(h2.parentElement);  // null
          var mydiv = document.getElementById("mydiv");
          mydiv.appendChild(h2);

          與innerText屬性的區別:

          兩者的返回的內容并不完全一樣,比如在輸出的格式上其與innerText是不同的,其會保留代碼中的空白符;同時,innerText針對表格,會試圖保留表格的格式;

          var mytable = document.getElementById("mytable");
          console.log(mytable.innerText);
          console.log(mytable.textContent);

          textContent屬性會返回元素的所有內容,包括其中的樣式和腳本代碼,而innerText只返回能呈現在頁面上的元素;

          // 在mydiv中添加<style>和<script>標簽
          var mydiv = document.getElementById("mydiv");
          console.log(mydiv.innerText); // 不包括<style>和<script>
          // 包括<style>和<script>標簽內的內容,但該標簽被過濾了
          console.log(mydiv.textContent);

          既然innerText只返回能呈現在頁面上的元素,所以它的返回值會受CSS樣式的影響,不會返回被CSS隱藏的元素的文本;

          <!-- textContent返回值沒有變化,但innerText不包括"HTML"和"CSS" -->
          <ul id="mylist">
              <li style="visibility: hidden;">HTML</li>
              <li style="display: none;">CSS</li>
              <li>JavaScript</li>
          </ul>

          textContent屬性能返回文本節點的文本內容,而innerText會返回undefined;如果是文本節點調用textContent屬性,其返回值與nodeValue一致;

          innerHTML有可能會引發安全問題,但textConent卻不會;

          mydiv.innerHTML = "<img src='nourl' onerror='alert(\"加載圖片出錯啦\")'>";
          mydiv.textContent = "<img src='nourl' onerror='alert(\"加載圖片出錯啦\")'>";
          console.log(mydiv.childNodes);  // index.html:20 NodeList [text]

          第一行的onerror會被執行,第二行不會執行,并且其被解析為文本節點,如此,textContent不會引發安全問題;

          所有主流的瀏覽器都支持textContent屬性,但IE8及以下不支持,可以包裝一個兼容的函數:

          function getInnerText(element){
              return (typeof element.textContent == "string") ? element.textContent : element.innerText;
          }
          function setInnerText(element, text){
              if(typeof element.textContent == "string")
                  element.textContent = text;
              else
                  element.innerText = text;
          }
          document.write(getInnerText(content));
          setInnerText(content, "零點程序員");

          或者直接定義在Node.prototype中:

          if(Object.defineProperty 
              && Object.getOwnPropertyDescriptor
              && !Object.getOwnPropertyDescriptor(Node.prototype, "textContent")){
              (function(){
                  var innerText = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerText");
                  Object.defineProperty(Node.prototype, "textContent",{
                      get: function(){
                          return innerText.get.call(this);
                      },
                      set: function(s){
                          return innerText.set.call(this, s);
                      }
                  });
              })();
          }

          <script>元素中的文本:

          內聯的<script>元素有一個text屬性用來獲取它們的文本;

          <script>
              console.log("function");
              function func(){return true;}
          </script>
          <script>
          var script = document.getElementsByTagName("script")[0];
          console.log(script.innerText);
          console.log(script.textContent);
          console.log(script.text);  // 三者輸出一致
          </script>

          如果將<script>元素的type屬性設置為”text/x-custom-data”,就表明了腳本為不可執行的Javascript代碼,如此,Javascript解析器將忽略該腳本,這也使得<script>元素可以被用來嵌入任意文本內容;

          <script type="text/x-custom-data">
              console.log("function");
              function func(){return true;}
          </script>
          <script>
          var script = document.getElementsByTagName("script")[0];
          console.log(script.innerText);
          console.log(script.textContent);
          console.log(script.text);  // 三者輸出一致
          </script>
          <script type="text/x-custom-data">
          <div style="border:1px solid red; width:300px;">
              <h2>視頻教程</h2>
          </div>
          </script>
          <script>
          var script = document.getElementsByTagName("script")[0];
          var mydiv = document.getElementById("mydiv");
          mydiv.innerHTML = script.text;
          </script>

          Element.insertAdjacentHTML(position, text)方法:

          該方法會將任意的HTML字符串text解析為Element元素,并將結果節點插入到DOM樹中的指定的元素”相鄰”的position位置;該方法最早是在IE4中出現的;它接收兩個參數:插入位置和要插入的HTML文本;

          第一個參數position的可能值:

          • beforebegin:在當前元素之前插入一個緊鄰的同輩元素;
          • afterbegin:在當前元素之下插入一個新的子元素或在第一個子元素之前插入新的子元素;
          • beforeend:在當前元素之下插入一個新的子元素或在最后一個子元素之后插入新的子元素;
          • afterend:在當前元素之后插入一個緊鄰的同輩元素;

          第二個參數text為HTML字符串,如果瀏覽器無法解析,會拋出錯誤,如;

          var mydiv = document.getElementById("mydiv");
          mydiv.insertAdjacentHTML("beforebegin","<p>前一個同輩元素</p>");
          mydiv.insertAdjacentHTML("afterbegin","<p>作為第一個子元素</p>");
          mydiv.insertAdjacentHTML("beforeend","<p>最后一個子元素</p>");
          mydiv.insertAdjacentHTML("afterend","<p>后一個同輩元素</p>");

          insertAdjacentHTML()方法同innerHTML屬性一樣,會遇到安全問題,在使用該屬性插入HTML內容時,需要轉義之后才能使用;

          另外,如果元素沒有子元素的時候,其和innerHTML就非常相像了;

          var newdiv = document.createElement("div");
          newdiv.insertAdjacentHTML("afterbegin", "<p>零點程序員</p>");
          // 同以下
          newdiv.innerHTML = "<p>零點程序員</p>";
          document.body.appendChild(newdiv);

          需要注意的是,如果position為beforebegin或afterend,那該元素必須具有一個parent元素;

          var newdiv = document.createElement("div");
          // 異常:The element has no parent,此時newdiv并沒有被添加到DOM樹中,它并沒有父節點,但是如果把下面行互換一下,就可以了;
          newdiv.insertAdjacentHTML("afterend", "<p>零點程序員</p>");
          document.body.appendChild(newdiv);

          基于insertAdjacentHTML()方法定義一個更符合語義邏輯的一個對象,如:

          // Insert.before()、Insert.after()、Insert.atStart()和Insert.atEnd()
          var Insert = {
              before: function(e,h) {
                  if(e.parentElement)
                      e.insertAdjacentHTML("beforebegin", h);
              },
              after: function(e,h) {
                  if(e.parentElement)
                      e.insertAdjacentHTML("afterend", h);
              },
              atStart: function(e,h) {e.insertAdjacentHTML("afterbegin", h);},
              atEnd: function(e,h) {e.insertAdjacentHTML("beforeend", h);}
          };
          var mydiv = document.getElementById("mydiv");
          Insert.before(mydiv, "<h2>zeronetwork</h2>");
          // 或者
          // 假定where值為before、after、innerfirst和innerlast
          function insertHTML(el, where, html){
              if(!el) return false;
              var _where = "beforeend";
              switch(where){
                  case "before":
                      _where = "beforebegin";
                      break;
                  case "after":
                      _where = "afterend";
                      break;
                  case "innerfirst":
                      _where = "afterbegin";
                      break;
                  case "innerlast":
                      _where = "beforeend";
                      break;
                  default:
                      _where = "beforeend";
                      break;
              }
              if(_where == "beforebegin" || _where == "afterend"){
                  if(!el.parentElement)
                      return false;
              }
              el.insertAdjacentHTML(_where, html);
          }
          var mydiv = document.getElementById("mydiv");
          insertHTML(mydiv, "innerfirst", "<h2>zeronetwork</h2>");

          小示例,添加商品:

          <div class="container">
              <div class="formdiv">
                  <label>商品:</label><input type="text" id="product" /><br/>
                  <label>價格:</label><input type="text" id="price" /><br/>
                  <label>數量:</label><input type="text" id="quantity" /><br/>
                  <button id="btnAdd">添加</button>
              </div>
              <table class="table">
                  <thead>
                      <tr>
                          <th>序號</th><th>商品</th><th>價格</th><th>數量</th><th>金額</th>
                      </tr>
                  </thead>
                  <tbody id="data"></tbody>
              </table>
          </div>
          <script>
          var id=1;
          var btnAdd = document.getElementById("btnAdd");
          btnAdd.addEventListener("click",function(e){
              var content = document.getElementById("data");
              
              var product = document.getElementById("product").value;
              var price = document.getElementById("price").value;
              var quantity = document.getElementById("quantity").value;
              var total = price * quantity;
              var newEntry = "<tr>" + 
                  "<td>" + id + "</td>" + 
                  "<td>" + product + "</td>" + 
                  "<td>" + price + "</td>" + 
                  "<td>" + quantity + "</td>" + 
                  "<td>" + total + "</td>" + 
                  "</tr>";
              content.insertAdjacentHTML('afterbegin', newEntry);
              id++;
          },false);
          </script>

          Element.insertAdjacentText(position, text)方法:

          該方法與insertAdjacentHTML()類似,只不過插入的是純文本內容,它的作用是將一個給定的文本text插入到相對于被調用的元素的給定position位置;

          position的值insertAdjacentHTML()中的position是一樣的;

          var mydiv = document.getElementById("mydiv");
          mydiv.insertAdjacentText("afterbegin","王唯");
          mydiv.insertAdjacentText("afterend","zeronetwork");

          如果text是html字符串,也會被當作純文本進行處理,如:

          // 頁面輸出:<h2>王唯</h2>
          mydiv.insertAdjacentText("afterbegin","<h2>王唯</h2>");

          Element. insertAdjacentElement(position, element)方法:

          將一個給定的元素節點插入到相對于被調用的元素的給定的position位置;與insertAdjacentHTML()方法類似,只不過插入的是一個節點對象;該方法會返回一個Element對象;

          var mydiv = document.getElementById("mydiv");
          var div = document.createElement("div");
          div.innerHTML = "<h2>zeronetwork</h2>";
          div.style.width = "200px";
          div.style.height = "100px";
          div.style.backgroundColor = "lightgray";
          var newdiv = mydiv.insertAdjacentElement("beforeend", div);
          console.log(div === newdiv); // true

          github上有人分享了一個包裝的方法,就是利用以上原生的方法;

          // 把一個節點插入到DOM樹中的一個位置
          function dominsert(parent, child, position){
              var pos = position || 'beforeend';
              if(typeof child === 'string')
                  dominsert.html(parent, child, pos);
              else
                  dominsert.element(parent, child, pos);
          }
          // 使用原生的insertAdjacentHTML()方法
          dominsert.html = function(parent, child, position){
              parent.insertAdjacentHTML(position, child);
          };
          // 使用原生的insertAdjacentElement()或insertBefore()方法
          dominsert.element = function(parent, child, position){
              if(parent.insertAdjacentElement)
                  parent.insertAdjacentElement(position, child);
              else{
                  switch (position){
                      case "beforebegin":
                          parent.parentNode.insertBefore(child, parent);
                          break;
                      case "afterbegin":
                          parent.insertBefore(child, parent.firstChild);
                          break;
                      case "beforeend":
                          parent.appendChild(child);
                          break;
                      case "afterend":
                          parent.parentNode.insertBefore(child, parent.nextSibling);
                          break;
                  }
              }
          };
          var mydiv = document.getElementById("mydiv");
          dominsert(mydiv,"<span>web前端</span>");
          dominsert(mydiv, "<b>零點程序員</b>", 'beforebegin');
          console.log(mydiv);

          內存和性能問題:

          使用以上的方法替換子節點可能會導致瀏覽器的內存占用問題,尤其是在IE中,問題更加明顯;

          如果被刪除的子樹中的元素設置了事件處理程序或者引用了一個Javascript對象作為屬性,被刪除的元素與事件處理程序或引用的JS對象之間的綁定關系在內存中并沒有一并刪除;如果這種情況頻繁出現,頁面占用的內存數量就會明顯增加;因此,在使用innerHTML、outerHTML屬性和insertAdjacentHTML()方法時,最好手工先移除要被替換的元素的所有事件處理程序和JS對象屬性;

          不要反復地使用innerHTML插入HTML;

          var arr = ["HTML","CSS","JavaScript"];
          var ul = document.getElementById("myList");
          for(var i=0,len=arr.length; i < len; i++){
              ul.innerHTML += "<li>" + arr[i] + "</li>"; 
          }

          ,最好的做法是:單獨構建字符串變量,再一次性的把結果賦給innerHTML;

          console.time("insert");
          var lisHTML = "";
          for(var i=0,len=arr.length; i<len;i++){
              lisHTML += "<li>" + arr[i] + "</li>";
          }
          ul.innerHTML = lisHTML;
          console.timeEnd("insert");

          adjacent三個方法與insertBefore()、appendChild()和innerHTML的比較;

          在某些時候,這些方法屬性都可以達到同樣的目的,但在實際開發中,要針對當時的情況,選擇一個合適的方法,沒有哪個方法就一定比另外的方法更好,只有相對的合適;

          同時,這三個方法的性能雖然不一樣,但相差不大,幾乎可以忽略;

          insertAdjacentHTML()與innerHTML屬性的性能:

          insertAdjacentHTML()方法不會重新解析它正在使用的元素,因此它不會破壞元素內的現有元素,這就避免了額外的序列化步驟,但使用innerHTML時,特別是在原有的基礎上追加元素時,都會對原有的元素重新序列化,因此,前者比后者效率更快;

          appendChild()與insertAdjacentHTML()方法的性能;

          // time 10ms
          console.time("append");
          for(var i=0; i<1000; i++)
              mydiv.appendChild(document.createElement("div"));
          console.timeEnd("append");
          // tim 30ms
          console.time("adjacent");
          for(var i=0; i<1000; i++)
              mydiv.insertAdjacentHTML("beforeend","<div></div>");
          console.timeEnd("adjacent");

          可以看到appendChild()方法比insertAdjacentHTML()方法快很多,但是改進以上代碼后,為其添加有文本內容的元素,如;

          // time 30ms多
          console.time("append");
          for(var i=0; i<1000; i++){
              var div = document.createElement("div");
              var h2 = document.createElement("h2");
              h2.appendChild(document.createTextNode("零點程序員"));
              div.appendChild(h2);
              var p = document.createElement("p");
              p.appendChild(document.createTextNode("由大師哥王唯主講"));
              div.appendChild(p);
              mydiv.appendChild(div);
          }
          console.timeEnd("append");
          // time 40ms多
          console.time("adjacent");
          for(var i=0; i<1000; i++)
              mydiv.insertAdjacentHTML("beforeend","<div><h2>零點程序員</h2><p>由大師哥王唯主講</p></div>");
          console.timeEnd("adjacent");

          可以看到,兩者相差10ms,幾乎可以忽略不計;

          比較appendChild()與insertAdjacentElement方法的性能;

          如:把測試appendChild()方法中的mydiv.appendChild(div)改成mydiv.insertAdjacentElement("beforeend", div);即可;

          發現兩者幾乎相同;

          比較insertBefore()與以上兩者的性能;

          如:把測試appendChild()方法中的mydiv.appendChild(div),改成mydiv.insertBefore(div, mydiv.lastChild);,結束也大同小異;

          小實例,排序表格;

          基于表格指定列中單元格的值來進行排序;

          <table id="mytable"  border="1">
              <thead>
                  <tr>
                      <th>ID</th><th>Name</th><th>Sex</th>
                  </tr>
              </thead>
              <tbody>
              <tr>
                  <td>1</td><td>wangwei</td><td>女</td>
              </tr>
              <tr>
                  <td>2</td><td>jingjing</td><td>男</td>
              </tr>
              <tr>
                  <td>3</td><td>juanjuan</td><td>女</td>
              </tr>
          </tbody>
          </table>
          <script>
          // 根據指定表格每行第n個單元格的值,對第一個<tbody>中的行進行排序
          // 如果存在comparator函數則使用它,否則按字母表順序比較
          function sortrows(table, n, comparator){
              var tbody = table.tBodies[0];  // 第一個<tbody>,可能是隱式創建的
              var rows = tbody.getElementsByTagName("tr");  // tbody中所有行
              rows = Array.prototype.slice.call(rows, 0);  // 變成數組
              // 基于第n個<td>元素的值進行排序
              rows.sort(function(row1, row2){
                  var cell1 = row1.getElementsByTagName("td")[n];  // 獲得第n個單元格
                  var cell2 = row2.getElementsByTagName("td")[n];  // 同上
                  var val1 = cell1.textContent || cell1.innerText; // 獲得文本內容
                  var val2 = cell2.textContent || cell2.innerText;
                  if(comparator) return comparator(val1,val2);  // 進行排序
                  if(val1 < val2) return -1;
                  else if(val1 > val2) return 1;
                  else return 0;
              });
              // rows中已經排好序,在tbody中按它們的順序把行添加到最后
              // 這將自動把它們從當前位置移走,并不是刪除,而是移動
              for(var i=0; i<rows.length; i++){
                  tbody.appendChild(rows[i]);
              }
          }
          // 查找元素的<th>元素,讓它們可單擊,可以按該列排序
          function makeSortable(table){
              var headers = table.getElementsByTagName("th");
              for(var i=0; i<headers.length; i++){
                  (function(n){
                      headers[i].onclick = function() {
                          sortrows(table, n);
                      };
                  }(i));
              }
          }
          var mytable = document.getElementById("mytable");
          makeSortable(mytable);
          </script>

          小實例,生成目錄表:

          <style>
          #TOC{border:solid black 1px; margin:10px; padding: 10px;}
          .TOCEntry{}
          .TOCEntry a{text-decoration: none;}
          .TOCLevel1{font-size: 2em;}
          .TOCLevel2{font-size: 1.5em; margin-left: 1em;}
          .TOCSectNum::after{content: ": ";}
          </style>
          <script>
          // 當執行這個函數時會去文檔中查找id為"TOC"的元素;
          // 如果這個元素不存在,就創建一個元素
          // 生成的TOC目錄應當具有自己的CSS樣式,整個目錄區域的樣式className設置為"TOCEntry";
          // 為不同層級的目錄標題定義不同的樣式,<h1>標簽生成的標題className為"TOCLevel1",
          // <h2>標簽生成的標題className為”TOCLevel2“,以此類推;段編號的樣式為"TOCSectNum"
          function createToc(){
              // 查找TOC容器元素,如果不存在,則在文檔開頭處創建一個
              var toc = document.getElementById("TOC");
              if(!toc){
                  toc = document.createElement("div");
                  toc.id = "TOC";
                  document.body.insertBefore(toc, document.body.firstChild);
              }
              // 查找所有的標題元素
              var headings;
              if(document.querySelectorAll)
                  headings = document.querySelectorAll("h1,h2,h3,h4,h5,h6");
              else
                  headings = findHeadings(document.body, []);
              // 遞歸遍歷document的body,查找標題元素
              function findHeadings(orrt, sects){
                  for(var c = root.firstChild; c!=null; c=c.nextSibling){
                      if(c.nodeType !== 1) continue;
                      if(c.tagName.length == 2 && c.tagName.charAt(0) == "H")
                          sects.push(c);
                      else
                          findHeadings(c, sects);
                  }
                  return sects;
              }
              // 初始化一個數組來保存跟蹤章節號
              var sectionNumbers = [0,0,0,0,0,0];
              // 循環找到所有標題元素
              for(var h=0; h<headings.length; h++){
                  var heading = headings[h];
                  // 跳過在TOC容器中的標題元素
                  if(heading.parentNode == toc) continue;
                  // 獲取標題的級別
                  var level = parseInt(heading.tagName.charAt(1));
                  if(isNaN(level) || level < 1 || level > 6) continue;
                  // 對于該標題級別增加sectionNumbers對應的數字
                  // 并重置所有標題比它級別低的數字為零
                  sectionNumbers[level-1]++;
                  for(var i=level; i<6; i++) sectionNumbers[i] = 0;
                  // 將所有標題級的章節號組合產生一個章節號,如2.3.1
                  var sectionNumber = sectionNumbers.slice(0, level).join(".");
                  // 為標題級別增加章節號
                  // 把數字放在<span>中,使得其可以秀樣式修飾
                  var span = document.createElement("span");
                  span.className = "TOCSectNum";
                  span.innerHTML = sectionNumber;
                  heading.insertBefore(span, heading.firstChild);
                  // 用命名的錨點將標題包起來,以便為它增加鏈接
                  var anchor = document.createElement("a");
                  anchor.name = "TOC" + sectionNumber;
                  heading.parentNode.insertBefore(anchor, heading);
                  anchor.appendChild(heading);
                  // 為該節創建一個鏈接
                  var link = document.createElement("a");
                  link.href = "#TOC" + sectionNumber; // 鏈接目標地址
                  link.innerHTML = heading.innerHTML; // 鏈接文本與實際標題一致
                  // 將鏈接放在一個div中,div用基于級別名字的樣式修飾
                  var entry = document.createElement("div");
                  entry.className = "TOCEntry TOCLevel" + level;
                  entry.appendChild(link);
                  // 該div添加到TOC容器中
                  toc.appendChild(entry);
              }
          };
          window.onload = function(){createToc();}
          </script>

          Web前端開發之Javascript

          面的指令可用于綁定應用程序數據到HTML DOM元素的屬性。

          S.No.

          名稱

          描述

          1

          ng-disabled

          禁用給定的控制

          2

          ng-show

          顯示了一個給定的控制

          3

          ng-hide

          隱藏一個給定的控制

          4

          ng-click

          表示一個AngularJS click事件

            ng-disabled 指令

            添加ng-disabled屬性到一個HTML按鈕,并把它傳遞模型。綁定模型到復選框,來看看變化。

          <input type="checkbox" ng-model="enableDisableButton">Disable Button
          <button ng-disabled="enableDisableButton">Click Me!</button>12復制代碼類型:[html]

            ng-show 指令

            添加 ng-show 屬性到HTML按鈕,并把它傳遞到模型。該模型綁定復選框。

          <input type="checkbox" ng-model="showHide1">Show Button
          <button ng-show="showHide1">Click Me!</button>
          
          1234復制代碼類型:[html]

            ng-hide 指令

            添加 ng-hide 屬性到HTML按鈕,并把它傳遞模型。該模型綁定復選框。

          <input type="checkbox" ng-model="showHide2">Hide Button
          <button ng-hide="showHide2">Click Me!</button>
          
          1234復制代碼類型:[html]

            ng-click 指令

            添加ng-click屬性到一個HTML按鈕,更新模型。綁定模型到HTML如下所示。

          <p>Total click: {{ clickCounter }}</p></td>
          <button ng-click="clickCounter = clickCounter + 1">Click Me!</button>

          開課吧廣場-人才學習交流平臺

          . 對 HTML 語義化的理解

          語義化是指根據內容的結構化(內容語義化),選擇合適的標簽(代 碼語義化)。通俗來講就是用正確的標簽做正確的事情。

          語義化的優點如下:

          對機器友好,帶有語義的文字表現力豐富,更適合搜索引擎的爬蟲爬 取有效信息,有利于 SEO。除此之外,語義類還支持讀屏軟件,根據 文章可以自動生成目錄;

          對開發者友好,使用語義類標簽增強了可讀性,結構更加清晰,開發 者能清晰地看出網頁的結構,便于團隊的開發與維護。

          常見的語義化標簽:

          2. DOCTYPE(?檔類型) 的作?

          DOCTYPE 是 HTML5 中一種標準通用標記語言的文檔類型聲明,它的目 的是告訴瀏覽器(解析器)應該以什么樣(html 或 xhtml)的文檔類 行定義來解析文檔,不同的渲染模式會影響瀏覽器對 CSS 代碼甚?JavaScript 腳本的解析。它必須聲明在 HTML?檔的第??。

          瀏覽器渲染頁面的兩種模式(可通過 document.compatMode 獲取,比 如,語雀官網的文檔類型是 CSS1Compat):

          CSS1Compat:標準模式(Strick mode),默認模式,瀏覽器使用 W3C 的標準解析渲染頁面。在標準模式中,瀏覽器以其支持的最高標準呈 現頁面。

          BackCompat:怪異模式(混雜模式)(Quick mode),瀏覽器使用自己的 怪異模式解析渲染頁面。在怪異模式中,頁面以一種比較寬松的向后 兼容的方式顯示。

          3. script 標簽中 defer 和 async 的區別

          如果沒有 defer 或 async 屬性,瀏覽器會立即加載并執行相應的腳本。它不會等待后續加載的文檔元素,讀取到就會開始加載和執行,這樣 就阻塞了后續文檔的加載。

          下圖可以直觀地看出三者之間的區別:

          其中藍色代表 js 腳本網絡加載時間,紅色代表 js 腳本執行時間,綠 色代表 html 解析。

          defer 和 async 屬性都是去異步加載外部的 JS 腳本文件,它們都不 會阻塞頁面的解析,其區別如下:

          執行順序:多個帶 async 屬性的標簽,不能保證加載的順序;多個帶 defer 屬性的標簽,按照加載順序執行;

          腳本是否并行執行:async 屬性,表示后續文檔的加載和執行與 js 腳本的加載和執行是并行進行的,即異步執行;defer 屬性,加載后 續文檔的過程和 js 腳本的加載(此時僅加載不執行)是并行進行的(異步),js 腳本需要等到文檔所有元素解析完成之后才執行,DOMContentLoaded 事件觸發執行之前。

          4. 行內元素有哪些?塊級元素有哪些? 空(void)元素有那 些?

          行內元素有:a b span img input select strong;

          塊級元素有:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p;

          空元素,即沒有內容的 HTML 元素。空元素是在開始標簽中關閉的,也就是空元素沒有閉合標簽:

          常見的有:<br>、<hr>、<img>、<input>、<link>、<meta>;

          鮮見的有:<area>、<base>、<col>、<colgroup>、<command>、<embed>、<keygen>、<param>、<source>、<track>、<wbr>。

          5. 瀏覽器是如何對 HTML5 的離線儲存資源進行管理和加載?

          在線的情況下,瀏覽器發現 html 頭部有 manifest 屬性,它會請求 manifest 文件,如果是第一次訪問頁面 ,那么瀏覽器就會根據 manifest 文件的內容下載相應的資源并且進行離線存儲。如果已經 訪問過頁面并且資源已經進行離線存儲了,那么瀏覽器就會使用離線 的資源加載頁面,然后瀏覽器會對比新的 manifest 文件與舊的 manifest 文件,如果文件沒有發生改變,就不做任何操作,如果文 件改變了,就會重新下載文件中的資源并進行離線存儲。

          離線的情況下,瀏覽器會直接使用離線存儲的資源。

          6. Canvas 和 SVG 的區別

          (1)SVG:

          SVG 可縮放矢量圖形(Scalable Vector Graphics)是基于可擴展標 記語言 XML 描述的 2D 圖形的語言,SVG 基于 XML 就意味著 SVG DOM 中的每個元素都是可用的,可以為某個元素附加 Javascript 事件處 理器。在 SVG 中,每個被繪制的圖形均被視為對象。如果 SVG 對象 的屬性發生變化,那么瀏覽器能夠自動重現圖形。

          其特點如下:

          不依賴分辨率

          支持事件處理器

          最適合帶有大型渲染區域的應用程序(比如谷歌地圖)

          復雜度高會減慢渲染速度(任何過度使用 DOM 的應用都不快)不適合游戲應用

          (2)Canvas:

          Canvas 是畫布,通過 Javascript 來繪制 2D 圖形,是逐像素進行渲 染的。其位置發生改變,就會重新進行繪制。

          其特點如下:

          依賴分辨率

          不支持事件處理器

          弱的文本渲染能力

          能夠以 .png 或 .jpg 格式保存結果圖像

          最適合圖像密集型的游戲,其中的許多對象會被頻繁重繪

          注:矢量圖,也稱為面向對象的圖像或繪圖圖像,在數學上定義為一 系列由線連接的點。矢量文件中的圖形元素稱為對象。每個對象都是

          一個自成一體的實體,它具有顏色、形狀、輪廓、大小和屏幕位置等 屬性。

          7. 說一下 HTML5 drag API

          dragstart:事件主體是被拖放元素,在開始拖放被拖放元素時觸發。

          darg:事件主體是被拖放元素,在正在拖放被拖放元素時觸發。dragenter:事件主體是目標元素,在被拖放元素進入某元素時觸發。dragover:事件主體是目標元素,在被拖放在某元素內移動時觸發。dragleave:事件主體是目標元素,在被拖放元素移出目標元素是觸 發。

          drop:事件主體是目標元素,在目標元素完全接受被拖放元素時觸發。

          dragend:事件主體是被拖放元素,在整個拖放操作結束時觸發。


          主站蜘蛛池模板: 精品理论片一区二区三区| 精品性影院一区二区三区内射| 日韩制服国产精品一区| 农村乱人伦一区二区| 国产Av一区二区精品久久| 精品乱子伦一区二区三区高清免费播放 | 日本一区中文字幕日本一二三区视频 | 久久人妻内射无码一区三区 | 人妻精品无码一区二区三区| 国产在线视频一区| 美女免费视频一区二区| 武侠古典一区二区三区中文| 中文字幕一区二区三区乱码| 韩国一区二区三区| 天天视频一区二区三区| 亚洲熟妇av一区二区三区漫画| 亚洲国产高清在线精品一区| 久久综合亚洲色一区二区三区| 国产一区二区三区在线| 一区二区国产在线播放| 成人精品一区二区三区不卡免费看| 亚洲综合一区国产精品| 日韩欧美一区二区三区免费观看| 亚洲综合无码一区二区| 亚欧在线精品免费观看一区| 波多野结衣久久一区二区| 亚洲AV网一区二区三区| 国产精品一区二区毛卡片| 精品无码一区二区三区在线| 少妇精品久久久一区二区三区| 亚洲一区精品无码| 国产亚洲3p无码一区二区| 人妻少妇精品一区二区三区| 国产一区二区三区不卡AV| 三上悠亚日韩精品一区在线 | 国产成人一区二区三区在线| 国产免费一区二区三区免费视频 | 国产一区在线mmai| 日韩视频在线一区| 国产精品乱码一区二区三区| 久久国产一区二区三区|