Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
avaScript 數組用于在單一變量中存儲多個值。
var cars=["Saab", "Volvo", "BMW"];
數組是一種特殊的變量,它能夠一次存放一個以上的值。
如果您有一個項目清單(例如,汽車品牌列表),在單個變量中存儲汽車品牌應該是這樣的:
var car1="Saab";
var car2="Volvo";
var car3="BMW";
不過,假如您希望遍歷所有汽車并找到一個特定的值?假如不是三個汽車品牌而是三百個呢?
解決方法就是數組!
數組可以用一個單一的名稱存放很多值,并且還可以通過引用索引號來訪問這些值。
使用數組文本是創建 JavaScript 數組最簡單的方法。
var array-name=[item1, item2, ...];
var cars=["Saab", "Volvo", "BMW"];
空格和折行并不重要。聲明可橫跨多行:
var cars=[
"Saab",
"Volvo",
"BMW"
];
請不要最后一個元素之后寫逗號(比如 "BMW",)。
可能存在跨瀏覽器兼容性問題。
下面的例子也會創建數組,并為其賦值:
var cars=new Array("Saab", "Volvo", "BMW");
以上兩個例子效果完全一樣。無需使用 new Array()。
出于簡潔、可讀性和執行速度的考慮,請使用第一種方法(數組文本方法)。
我們通過引用索引號(下標號)來引用某個數組元素。
這條語句訪問 cars 中的首個元素的值:
var name=cars[0];
這條語句修改 cars 中的首個元素:
cars[0]="Opel";
var cars=["Saab", "Volvo", "BMW"];
document.getElementById("demo").innerHTML=cars[0];
[0] 是數組中的第一個元素。[1] 是第二個。數組索引從 0 開始。
這條語句修改了 cars 中第一個元素的值:
cars[0]="Opel";
var cars=["Saab", "Volvo", "BMW"];
cars[0]="Opel";
document.getElementById("demo").innerHTML=cars[0];
通過 JavaScript,可通過引用數組名來訪問完整數組:
var cars=["Saab", "Volvo", "BMW"];
document.getElementById("demo").innerHTML=cars;
數組是一種特殊類型的對象。在 JavaScript 中對數組使用 typeof 運算符會返回 "object"。
但是,JavaScript 數組最好以數組來描述。
數組使用數字來訪問其“元素”。在本例中,person[0] 返回 Bill:
var person=["Bill", "Gates", 62];
對象使用名稱來訪問其“成員”。在本例中,person.firstName 返回 Bill:
var person={firstName:"Bill", lastName:"Gates", age:19};
JavaScript 變量可以是對象。數組是特殊類型的對象。
正因如此,您可以在相同數組中存放不同類型的變量。
您可以在數組保存對象。您可以在數組中保存函數。你甚至可以在數組中保存數組:
myArray[0]=Date.now;
myArray[1]=myFunction;
myArray[2]=myCars;
JavaScript 數組的真實力量隱藏在數組的屬性和方法中:
var x=cars.length; // length 屬性返回元素的數量
var y=cars.sort(); // sort() 方法對數組進行排序
我們將在下一章學習數組方法。
length 屬性返回數組的長度(數組元素的數目)。
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.length; // fruits 的長度是 4
length 屬性始終大于最高數組索引(下標)。
fruits=["Banana", "Orange", "Apple", "Mango"];
var first=fruits[0];
fruits=["Banana", "Orange", "Apple", "Mango"];
var last=fruits[fruits.length - 1];
遍歷數組的最安全方法是使用 "for" 循環:
var fruits, text, fLen, i;
fruits=["Banana", "Orange", "Apple", "Mango"];
fLen=fruits.length;
text="<ul>";
for (i=0; i < fLen; i++) {
text +="<li>" + fruits[i] + "</li>";
}
您也可以使用 Array.foreach() 函數:
var fruits, text;
fruits=["Banana", "Orange", "Apple", "Mango"];
text="<ul>";
fruits.forEach(myFunction);
text +="</ul>";
function myFunction(value) {
text +="<li>" + value + "</li>";
}
向數組添加新元素的最佳方法是使用 push() 方法:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.push("Lemon"); // 向 fruits 添加一個新元素 (Lemon)
也可以使用 length 屬性向數組添加新元素:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits[fruits.length]="Lemon"; // 向 fruits 添加一個新元素 (Lemon)
添加最高索引的元素可在數組中創建未定義的“洞”:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits[6]="Lemon"; // 向 fruits 添加一個新元素 (Lemon)
很多編程元素支持命名索引的數組。
具有命名索引的數組被稱為關聯數組(或散列)。
JavaScript 不支持命名索引的數組。
在 JavaScript 中,數組只能使用數字索引。
var person=[];
person[0]="Bill";
person[1]="Gates";
person[2]=62;
var x=person.length; // person.length 返回 3
var y=person[0]; // person[0] 返回 "Bill"
假如您使用命名索引,JavaScript 會把數組重定義為標準對象。
之后,所有數組的方法和屬性將產生非正確結果。
var person=[];
person["firstName"]="Bill";
person["lastName"]="Gates";
person["age"]=62;
var x=person.length; // person.length 將返回 0
var y=person[0]; // person[0] 將返回 undefined
在 JavaScript 中,數組使用數字索引。
在 JavaScript 中,對象使用命名索引。
數組是特殊類型的對象,具有數字索引。
沒有必要使用 JavaScript 的內建數組構造器 new Array()。
請使用 [] 取而代之!
下面兩條不同的語句創建了名為 points 的新的空數組:
var points=new Array(); // 差
var points=[]; // 優
下面兩條不同的語句創建包含六個數字的新數組:
var points=new Array(40, 100, 1, 5, 25, 10); // 差
var points=[40, 100, 1, 5, 25, 10]; // 優
new 關鍵詞只會使代碼復雜化。它還會產生某些不可預期的結果:
var points=new Array(40, 100); // 創建包含兩個元素的數組(40 和 100)
假如刪除其中一個元素會怎么樣?
var points=new Array(40); // 創建包含 40 個未定義元素的數組!!!
常見的問題是:我如何知曉某個變量是否是數組?
問題在于 JavaScript 運算符 typeof 返回 "object":
var fruits=["Banana", "Orange", "Apple", "Mango"];
typeof fruits; // 返回 object
typeof 運算符返回 "object",因為 JavaScript 數組屬于對象。
為了解決這個問題,ECMAScript 5 定義了新方法 Array.isArray():
Array.isArray(fruits); // 返回 true
此方案的問題在于 ECMAScript 5 不支持老的瀏覽器。
創建您自己的 isArray() 函數以解決此問題:
function isArray(x) {
return x.constructor.toString().indexOf("Array") > -1;
}
假如參數為數組,則上面的函數始終返回 true。
或者更準確的解釋是:假如對象原型包含單詞 "Array" 則返回 true。
假如對象由給定的構造器創建,則 instanceof 運算符返回 true:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits instanceof Array // 返回 true
創建數組,為其賦值,然后輸出這些值。
<html>
<body>
<script type="text/javascript">
var mycars=new Array()
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
for (i=0;i<mycars.length;i++)
{
document.write(mycars[i] + "<br />")
}
</script>
</body>
</html>
使用 for...in 聲明來循環輸出數組中的元素。
<html>
<body>
<script type="text/javascript">
var x
var mycars=new Array()
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
for (x in mycars)
{
document.write(mycars[x] + "<br />")
}
</script>
</body>
</html>
如何使用 concat() 方法來合并兩個數組。
<html>
<body>
<script type="text/javascript">
var arr=new Array(3)
arr[0]="George"
arr[1]="John"
arr[2]="Thomas"
var arr2=new Array(3)
arr2[0]="James"
arr2[1]="Adrew"
arr2[2]="Martin"
document.write(arr.concat(arr2))
</script>
</body>
</html>
如何使用 join() 方法將數組的所有元素組成一個字符串。
<html>
<body>
<script type="text/javascript">
var arr=new Array(3);
arr[0]="George"
arr[1]="John"
arr[2]="Thomas"
document.write(arr.join());
document.write("<br />");
document.write(arr.join("."));
</script>
</body>
</html>
如何使用 sort() 方法從字面上對數組進行排序。
<html>
<body>
<script type="text/javascript">
var arr=new Array(6)
arr[0]="George"
arr[1]="John"
arr[2]="Thomas"
arr[3]="James"
arr[4]="Adrew"
arr[5]="Martin"
document.write(arr + "<br />")
document.write(arr.sort())
</script>
</body>
</html>
如何使用 sort() 方法從數值上對數組進行排序。
<html>
<body>
<script type="text/javascript">
function sortNumber(a, b)
{
return a - b
}
var arr=new Array(6)
arr[0]="10"
arr[1]="5"
arr[2]="40"
arr[3]="25"
arr[4]="1000"
arr[5]="1"
document.write(arr + "<br />")
document.write(arr.sort(sortNumber))
</script>
</body>
</html>
數組對象用來在單獨的變量名中存儲一系列的值。
我們使用關鍵詞 new 來創建數組對象。下面的代碼定義了一個名為 myArray 的數組對象:
var myArray=new Array()
有兩種向數組賦值的方法(你可以添加任意多的值,就像你可以定義你需要的任意多的變量一樣)。
var mycars=`new Array()`
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
也可以使用一個整數自變量來控制數組的容量:
var mycars=`new Array(3)`
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
var mycars=`new Array("Saab","Volvo","BMW")`
注意:如果你需要在數組內指定數值或者邏輯值,那么變量類型應該是數值變量或者布爾變量,而不是字符變量。
通過指定數組名以及索引號碼,你可以訪問某個特定的元素。
下面是代碼行:
document.write(mycars[0])
下面是輸出:
Saab
如需修改已有數組中的值,只要向指定下標號添加一個新值即可:
mycars[0]="Opel";
現在,以上代碼:
document.write(mycars[0]);
將輸出:
Opel
我建了一個【前端學習群】,【免費領取學習資料】或學習的同學可以關注我:
前端學習交流 - 知乎
內容是《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的可能值:
第二個參數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
信息爆炸的大數據時代,我們每天都被無數的數據包圍。如何在這茫茫的數字海洋中迅速找到自己所需的信息?傳統的搜索方式或許已經無法滿足我們的需求。此時,一種名為“爬蟲”的技術逐漸嶄露頭角,成為了大數據時代中不可或缺的利器。
下面舉個小例子講講爬蟲可以做什么?以Python工具爬取王者榮耀官網的英雄人物頭像為例,將網頁上的圖片爬取并保存,Python爬蟲爬取網頁圖片可以分為四步:明確目的、發送請求、數據解析、保存數據,具體實例操作如下。
1.1 明確目的
打開王者榮耀英雄介紹主頁,該主頁包含很多種英雄的頭像圖片,主頁網址鏈接如下。
官網地址:https://pvp.qq.com/web201605/herolist.shtml
1.2 發送請求
使用requests庫發送請求,返回狀態碼顯示為200,服務器連接正常。
import requests
u='https://pvp.qq.com/web201605/herolist.shtml'
response=requests.get(u)
print('狀態碼:{}'.format(response.status_code))
if response.status_code !=200:
pass
else:
print("服務器連接正常")
1.3 數據解析
在數據解析之前,需要提前安裝pyquery,pyquery庫類似于Beautiful Soup庫,初始化的時候,需要傳入HTML文本來初始化一個PyQuery對象,它的初始化方式包括直接傳入字符串,傳入URL,傳入文件名等等,這里傳入URL,并且查找節點。
#解析數據
from pyquery import PyQuery
doc=PyQuery(html)
items=doc('.herolist>li')#.items()
print(items)
同時遍歷,使用find函數查找子節點,遍歷爬取圖片URL和圖片名。
for item in items:
url=item.find('img').attr('src')
#print(url)
urls='http:'+url
name=item.find('a').text()
#print(name)
url_content=requests.get(urls).content
1.4 保存數據
最后保存數據,需要提前新建一個文件夾用于數據存儲,同時,存儲數據的代碼需要寫在for循環里面,不然只會保存一張圖片。
with open('C:/Users/尚天強/Desktop/王者榮耀picture/'+name+'.jpg','wb') as file:
file.write(url_content)
print("正在下載%s......%s"%(name,urls))
同時加一個計時器,用于計時圖片爬取的時長,這里顯示圖片爬取共計耗時7.03秒。
import time
start=time.time()
…
end=time.time()
print('圖片爬取共計耗時{:.2f}秒'.format(end-start))
爬取過程動態演示如下,運行過程很快。
以上我們成功將王者榮耀的英雄人物頭像爬取下來,代碼文件中有高清頭像。
爬蟲,這個看似高深莫測的詞匯,實則卻是我們應對大數據挑戰的得力助手。在這個數據無限增長的時代,爬蟲為我們開辟了一條快速、高效獲取信息的道路,上面的實例需要編程基礎,這里給大家介紹使用Bright Data無編程爬取數據。
2.1 Bright Data 注冊
要使用Bright Data的功能,首先我們要在其官網注冊,使用個人郵箱即可注冊,注冊完成后的界面如下所示。
官網地址:https://get.brightdata.com/dhsjfx
2.2 主要功能
登錄官網后,可以看到在主界面中已經展示了常用的功能:代理&爬蟲基礎設施與數據集和Web Scraper IDE,分別介紹其功能。
代理&爬蟲基礎設施:最快且穩定的代理網絡,靜態動態IP覆蓋全球195個國家,告別反爬限制和封鎖。包括:
數據集和Web Scraper IDE:不管是完整豐富的大數據集,還是大規模輕松開發數據挖掘抓取工具,都能在此找到。包括:
2.3 代理&爬蟲基礎設施
在進行網絡爬蟲工作時,許多網站會采取一些措施來限制或阻止來自特定 IP 地址的訪問。這主要是為了防止過度抓取和保護網站數據的隱私。因此,如果你使用的是固定的 IP 地址進行爬蟲操作,很可能會遇到訪問受限的問題。
為了避免該情況,許多爬蟲開發者選擇使用代理 IP。代理 IP 是一種隱藏真實 IP 地址的方法,通過代理服務器進行數據傳輸。當你使用代理 IP 進行爬蟲操作時,網站服務器接收到的請求會顯示為代理服務器的 IP 地址,而不是你的真實 IP,Bright Data含有多種代理IP功能。
使用代理 IP 的好處在于,你可以更換不同的代理 IP 來訪問目標網站,這樣即使某個代理 IP 被限制或封禁,你仍然可以通過其他可用的代理 IP 繼續進行爬蟲操作。此外,使用真實的代理 IP 還可以幫助你更好地模擬真實用戶的訪問行為,提高爬蟲的效率和成功率。
2.4 數據集和Web Scraper IDE
在數據科學和機器學習的世界里,一個龐大的數據集是必不可少的。有時候,為了獲得所需的數據,我們需要從網站上抓取信息。而這個過程,雖然必要,但往往也是耗時和復雜的。幸運的是,一些平臺和工具已經為我們提供了方便的解決方案。
在Web Scraper IDE中,官方為我們提供了許多知名站點的爬取數據。這意味著,你不需要從零開始,手動地抓取每一個網站。你可以直接使用這些已經爬好的數據集,節省大量的時間和精力。
這些數據集通常覆蓋了各種領域,從社交媒體、新聞網站到電子商務平臺等。無論你是在進行市場分析、內容生成還是模式識別,都可以在這些數據集中找到你需要的數據。
更令人興奮的是,這些數據集的質量都是經過嚴格篩選和清洗的,確保了數據的準確性和完整性。你可以放心地使用這些數據,而無需擔心數據的缺失或錯誤。
使用Web Scraper IDE提供的數據集,可以大大簡化數據抓取的過程,使你能夠更快地進入數據分析的核心工作。如果你需要快速獲取高質量的數據,那么這些官方提供的數據集無疑是你的最佳選擇。
2.5 Web Scraper IDE
Bright Data還提供了 web 端的 IDE 工具,并提供了相關的示例代碼,你可以直接使用模板和對應的代碼!也可以自己自定義爬蟲,可以按照你的需求來定制數據集,點擊制定按鈕即可進入自定義數據集的界面。
這里以爬取豆瓣電影TOP250的數據為例,按照提示的要求填入對應的信息,填寫示例的URL時,需要填寫至少兩條URL的鏈接,這樣才能爬取數據。
接著,對于網頁返回的字段可以編輯字段名稱、數據類型等,限于爬取的數據信息,并且,返回的數據字段可以做預覽,提前查看爬取的數據結果。
數據字段設置好后,就可以點擊下載按鈕將數據下來下來,這里有JSON和CSV兩種數據保存格式,通過預覽我們就可以看到爬取的基本數據信息,使用自定義爬取數據也很簡單。
借助爬蟲,我們可以輕松抓取和整理數據,無論你是需要大規模收集數據,還是需要突破網站封鎖,或需要管理你的代理,Bright Data都能為你提供優質的服務,如果你想學習Bright Data更多數據爬取功能,點擊閱讀原文,申請還可以免費試用,開啟你的爬蟲之旅!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。