雙引號
在js代碼中
在js中單、雙引號引起來的是字符串,如果我們要在字符串中使用單、雙引號,需要反斜杠進行轉義
let str='user\'s name'; // or let str=" user's name"; // or let str="she said:\"...\".";
如果在字符串中輸出反斜杠,仍然是用反斜杠轉義,即2個反斜杠輸出1個反斜杠
在html代碼中
html標簽中,屬性值通常用雙引號引起來,也可以使用單引號或不用引號。
<input name=user /> <input name="user" /> <input name='user' />
這3種寫法都正確,不過通常我們是選擇用雙引號引起來。
如果我們要在屬性值中使用單、雙綽號,我們不能直接寫成下面這樣
<input name=user'name /> <input name="user"name" /> <input name='user'name' />
這些全部是錯誤的。我們要像在js中對單、雙引號轉義一樣,對屬性中的單、雙引號轉義
在html中輸出預留符號,可以使用字符實體轉義的形式,這里有簡單介紹:http://www.w3school.com.cn/html/html_entities.asp。即想輸出一個雙引號可以使用"的形式,
<input name="user"name" />
除此之外,html還支持十進制與十六進制編碼的形式輸出字符,如我們知道字符a的ascii碼的十進制是97 十六進制是61
所以我們在頁面body中輸出一個字符a,有以下3種形式
<body> a<!--直接輸出--> a<!--十進制輸出--> a<!--十六進制輸出--> </body>
同樣,單雙引號也有十進制(單:39,雙:34)與十六進制(單:27,雙:22),所以我們在屬性中輸出一個單引號有2種選擇,十進制與十六進制
<input name='user'name' /><!--十進制--> <input name='user'name' /><!--十六進制-->
而輸出一個雙引號則有3種選擇
<input name="user"name" /><!--實體--> <input name="user"name" /><!--十進制--> <input name="user"name" /><!--十六進制-->
當js代碼遇上實體編碼
我們可以通過dom節點提供的事件寫上調用js的代碼,如點擊body彈出hello這個字符串,我們可以寫成
<body onclick="alert('hello')"> click here </body>
如果我們的需求是就彈出一個雙引號呢?
根據前述規則,我們要寫成:
<body onclick="alert('"')"><!--這里用十進制或十六進制都可以--> click here </body>
當然,alert里的單引號也可以使用十進制或十六進制編碼
<body onclick="alert("'")"><!--"單引號 '雙引號--> click here </body>
這樣也是可以的。
是不是有點xss的感覺?
如果我們把彈雙引號的需求改成單引號呢?
<body onclick="alert(''')"><!--這樣html中是合法的,但js中并不合法,因為在js中,中間的單引號并沒有轉義--> click here </body>
如果我們用十進制或十六進制編碼呢?
<body onclick="alert('"')"><!--這樣可以嗎--> click here </body>
這樣仍然是不可以的
我們要對js字符串中的單引號進行轉義,如
<body onclick="alert('\'')"><!--轉義后可正確彈出--> click here </body>
或
<body onclick="alert('\"')"><!--轉義后可正確彈出--> click here </body>
前面的onclick="alert('\'')"看起來還正常,后面的這個onclick="alert('\"')"就有點不直觀了。因為后面這個看上去反斜杠像在轉義&這1個字符,而&在js的字符串中并不需要轉義的。
動態輸出
如前述的alert彈出的消息,如果是一個變量控制,動態輸出呢?
<body onclick="alert('${msg}')"> click here </body>
那我們這個msg字符串就得注意了,從這個示例來看,這個動態的msg即出現在屬性onclick中,也出現在alert的單引號開始的字符串中。
我們要對msg中的雙引號轉成"或"或",并對msg中單引號的前面加上一個反斜杠\ ?
題外話:對msg中的反斜杠需要做double處理,因為反斜杠在html屬性中并不是特殊的,但在js的字符串中是特殊的。因此正確的做法是對反斜杠及單引號前面各加上一個反斜杠
然而,你并不能保證屬性是用雙引號,alert中的字符串用的是單引號,因為可以寫成下面這樣
<body onclick='alert("${msg}")'> click here </body>
?
這種情況我們要對msg中的單引號轉成'或',并對msg中雙引號前面加上一個反斜杠\
題外話:同上
看上去要根據不同的情況做不同的處理,其實也不需要
我們只需要對單、雙引號前面加上一個反斜杠\然后再對單、雙引號實體編碼即可。
在js中如果反斜杠后面跟的不需要反斜杠轉義的字符,那么這個反斜杠是被丟棄的,因此像
var str="user\'s name";
單引號前面多加一個反斜杠也不要緊的。
自動化處理與識別提醒
在magix項目中,由于magix-combine的支持,可識別出屬性中js代碼的部分,并自動化處理,如
<button mx-click="showName({name:'<%=name%>'})">click here</button>
name這個變量可包含任意的單、雙引號及反斜杠。工具自動識別并處理,開發者不需要做任何事情。
而對于這樣的寫法:
<button mx-click="showName({name:'"'})">click here</button> <!-- or--> <button mx-click="showName({name:'\"'})">click here</button>
第一種寫法其實并不正確,但第二種情況看上去又怪怪的。magix-combine工具能識別出來是否需要添加反斜杠,并自動添加處理。
第一種需要添加反斜杠,工具會自動加上,并提醒開發者這里的寫法是不正確的。
第二種說明開發者意識到了問題所在,自己處理了,工具就不再處理也不再提醒開發者。
內容是《Web前端開發之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學習。
文本節點用Text類型表示,包含的是可以按字面解釋的純文本內容;純文本內容可以包含轉義后的HTML字符,但不能包含HTML代碼;
Text類和Comment類都是CharacterData類的子類型;
CharacterData是一個抽象類(接口),代表 Node 對象包含的字符,它是在其他接口中被實現的,如Text、Comment 或 ProcessingInstruction具體的類;
CharacterData類繼承自Node類,其擁有data、length、nextElementSibling、previousElementSibling等屬性;
擁有的方法:appendData()、deleteData()、insertData()、replaceData()、substringData()。
特征:
data屬性:
可以通過nodeValue屬性或data屬性訪問或設置Text節點包含的文本;
var h2 = document.getElementsByTagName("h2")[0];
console.log(h2.childNodes); // NodeList [text]
var text = h2.childNodes[0];
// var text = h2.firstChild; // 也可以
console.log(text); // 零點程序員
console.log(text.nodeType); // 3
console.log(text.nodeName); // #text
console.log(text.nodeValue); // 零點程序員
console.log(text.data); // 零點程序員
text.nodeValue = "zeronetwork";
console.log(text.nodeValue); // zeronetwork
console.log(text.parentNode); // <h2>零點程序員</h2>
length屬性:
保存節點中字符的數目,而且nodeValue.length和data.length中也保存著相同的值;
console.log(text.length);
console.log(text.nodeValue.length);
console.log(text.data.length);
在默認情況下,每個可以包含內容的元素最多只能有一個文本節點,而且必須確實有內容存在;
var h4 = document.getElementsByTagName("h4")[0];
// <h4></h4> 返回null
// <h4> </h4> 返回空白,也是文本節點
// <h4>zeronetwork</h4> 返回文本節點
var text = h4.firstChild;
console.log(text);
在修改文本字符串時,字符串會經過HTML編碼,即小于號大于號或引號都會被轉義;也就是說,在向DOM文檔中插入文本之前,會先對其進行HTML編碼;
text.nodeValue = "零點程序員<strong>王唯</strong>";
// 會轉義為<strong>
console.log(text.nodeValue);
document.write(text.nodeValue);
注:瀏覽器已自動修正;如果使用document.write()方法,會解析為html代碼;
后面我們會學到Element類型的innerHTML和innerText等方法,它們就是獲取或設置元素內的HTML字符串或純文本內容的;如:
var mydiv = document.getElementById("mydiv");
console.log(mydiv.innerHTML)
console.log(mydiv.innerText);
其中,innerText就是把div內的所有后代的元素的純文本提取,并拼接起來;但我們不使用這個屬性也可以達到這種效果;
// 返回元素的純文本內容,遞歸進入其子元素
function textContent(e){
var child, type, s = ""; // s保存所有子節點的文本
for(child = e.firstChild; child != null; child = child.nextSibling){
type = child.nodeType;
if(type == 3 || type == 4) // Text和CDATASection節點
s += child.nodeValue;
else if(type == 1) // Element
s += textContent(child);
}
return s;
}
var mydiv = document.getElementById("mydiv");
console.log(mydiv.innerText);
console.log(textContent(mydiv));
將Text節點中的內容轉換成大寫形式:
// 遞歸把e的后代節點中的所有Text節點內容轉換成大寫
function upcase(e){
if(e.nodeType == 3 || e.nodeType == 4)
e.data = e.data.toUpperCase();
else
for(var i=0,len=e.childNodes.length;i<len; i++)
upcase(e.childNodes[i]);
}
var mydiv = document.getElementById("mydiv");
upcase(mydiv);
創建文本節點:
document.createTextNode(data)方法:
創建一個新的文本節點;該方法接受一個文本參數;該文本也將按照HTML或XML的格式進行編碼;在創建的同時,也會為其設置ownerDocument屬性;也需要添加到文件樹中;
注:不能直接為文本節點添加其他特性;
var textNode = document.createTextNode("零點程序員");
document.body.appendChild(textNode);
var div = document.createElement("div");
div.className = "newsdiv";
var textNode = document.createTextNode("zeronetwork");
// textNode.setAttribute("style","color:red"); // 異常
div.appendChild(textNode);
var textNode = document.createTextNode("<strong>零點</strong>zeronetwork");
var mydiv = document.getElementById("mydiv");
mydiv.appendChild(textNode);
console.log(mydiv.lastChild); // <strong>零點</strong>zeronetwork,因為被編碼了
console.log(mydiv.lastChild.nodeType); // 3,依然是Text_node
操作文本節點的方法:
normalize()方法:規范化文本節點;
默認情況下,每個元素只有一個文本節點,但如果該元素appendChild多個文本節點后,該元素就可能包含多個文本子節點;
var mydiv = document.getElementById("mydiv");
mydiv.appendChild(document.createTextNode("零點程序員"));
mydiv.appendChild(document.createTextNode("王唯"));
mydiv.appendChild(document.createTextNode("Web前端開發"));
// 此時查看渲染結果為:"零點程序員" "王唯" "Web前端開發"
console.log(mydiv.childNodes.length); // 3
console.log(mydiv.childNodes); // NodeList(3)
for(var i=0,len=mydiv.childNodes.length; i<len; i++)
console.log(mydiv.childNodes[i].nodeValue); // 零點程序員 王唯 Web前端開發
而這種在DOM中,存在相鄰的同胞文本節點很容易導致混亂,因為分不清哪個文本節點表示哪個字符串,而在實際開發中,出現這種情況還比較多,于是出現了一個能夠將相鄰文本節點合并的方法normalize();
該方法Node類型定義的,由父節點調用;
mydiv.normalize();
console.log(mydiv.childNodes.length); // 1
for(var i=0,len=mydiv.childNodes.length; i<len; i++)
console.log(mydiv.childNodes[i].nodeValue); // 零點程序員王唯Web前端開發
normalize()方法規范里說:在一個"規范化"后的DOM樹中,不存在一個空的文本節點,或者兩個相鄰的文本節點;這里的“空的文本節點”并不包括空白字符(空格,換行等)構成的文本節點;
splitText(offset):
分割文本節點;Text類型提供了一個作用與normalize()相反的方法:splitText();
該方法會將一個文本節點分成兩個兄弟文本節點,即按照指定的offset位置分割nodeValue值;原來的文本節點將包含從開始到指定offset位置之前的內容,新文本節點將包含剩下的文本,并返回這個新文本節點,并且該節點與原節點的parentNode相同;
var div = document.createElement("div");
div.className = "div";
var textNode = document.createTextNode("zeronetwork");
div.appendChild(textNode);
document.body.appendChild(div);
console.log(div.childNodes.length); // 1
var newNode = div.firstChild.splitText(4);
console.log(div.firstChild.nodeValue); // zero
console.log(newNode.nodeValue); // network
console.log(div.childNodes.length); // 2
如果指定的偏移量剛好等于原文本節點所包含字符串的長度,則返回一個內容為空的文本節點;
var fullNode = div.firstChild.splitText(div.firstChild.nodeValue.length);
console.log(div.firstChild);
console.log(fullNode.nodeValue); // ""
分割后的文本節點還可以使用Node.normalize()方法來合并;分割文本節點是從文本節點中提取數據的一種常用DOM解析技術;
// 在一個文本中插入另一個節點
var p = document.createElement("p");
p.appendChild(document.createTextNode("零點程序員"));
document.body.appendChild(p);
var programmer = p.firstChild.splitText(2);
var strongNode = document.createElement("strong");
strongNode.appendChild(document.createTextNode("zeronetwork"));
p.insertBefore(strongNode, programmer);
appendData(text):將text添加到節點的末尾;
deleteData(offset, count):從offset指定的位置開始刪除count個字符;
insertData(offset, text);在offset指定的位置插入text;
repalceData(offset, count, text):用text從offset開始替換count個文本;如果count為0,就是在offset處插入text文本;
substringData(offset, count):從offset位置開始提取count個文本;
<h1>零點程序員</h1>
<script>
var h1 = document.getElementsByTagName("h1")[0];
var txtNode = h1.firstChild;
txtNode.appendData("zeronetwork");
txtNode.deleteData(9, 3);
txtNode.insertData(5, "王唯");
txtNode.replaceData(2,3,"王唯");
var result = txtNode.substringData(2,2);
console.log(result); // 王唯
</script>
Comment類型:
在DOM中通過Comment類型來表示注釋;
同Text類一樣,Comment類也是繼承自CharacterData,它本身沒有定義屬性和方法,因此它的屬性和方法都是直接繼承自CharacterData或間接繼承自Node類;
特征為:
Comment類型與Text類型繼承自相同的基類,因此它擁有除了splitText()之外的所有字符串操作方法;其訪問方式同Text類型基本一樣;也可以通過其父節點來訪問,如:
var mydiv = document.getElementById("mydiv");
console.log(mydiv.firstChild);
console.log(mydiv.childNodes[0]); // mydiv中第1個子元素是注釋
console.log(mydiv.childNodes[0].nodeType); // 8
console.log(mydiv.childNodes[0].nodeName); // #comment
console.log(mydiv.childNodes[0].nodeValue); // 這是一段注釋
console.log(mydiv.childNodes[0].data); // 這是一段注釋
console.log(mydiv.childNodes[0].parentNode); // <div id="mydiv" ...
document.createComment(data)方法:創建注釋節,參數data為注釋文本;
var mydiv = document.getElementById("mydiv");
var comment = document.createComment("創建注釋節點");
mydiv.appendChild(comment);
注:chrome瀏覽器不會識別位于</html>標簽之后的注釋,其它可以,因此如果要訪問注釋節點,一定要保證它們是<html>元素的后代;
<!-- html外的注釋 -->
<script>
var c = document.childNodes[2];
console.log(c); // FF輸出為undefined,其余可以識別
</script>
在實際開發中,已經直接在代碼中注釋了,所以很少會創建和訪問注釋節點;
CDATASection類型:
CDATASection類型只針對基于XML的文檔,表示的是CDATA區域;該類繼承自Text類型,其本身沒有定義屬性和方法,全部繼承自祖先類,因此其擁有除了splitText()之外的所有字符串操作方法;
其特征:
在XML文檔中,可以使用document.createCDataSection()來創建CDATA區域,只須為其傳入節點的內容即可;
var cdata = document.createCDATASection("cdata"); // 異常,HTML文檔不支持
示例:data.xml文件:
<persons>
<person>
<name>王唯</name>
<age>18</age>
<sex>男</sex>
</person>
<person>
<name>靜靜</name>
<age>22</age>
<sex>女</sex>
</person>
<![CDATA[
if a < b
]]>
<person>
<name>娟娟</name>
<age>28</age>
<sex>女</sex>
</person>
</persons>
html文檔:
function loadXMLDoc(fileName){
var xmlHttp;
if(window.ActiveXObject)
xmlHttp = ActiveXObject("Microsoft.XMLDOM");
else
xmlHttp = new window.XMLHttpRequest();
xmlHttp.open("GET",fileName,true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function(e){
if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
var xmlDoc = xmlHttp.responseXML;
// console.log(xmlDoc);
parseXML(xmlDoc);
}
}
}
function parseXML(xmlDoc){
var persons = xmlDoc.documentElement;
// console.log(persons);
// console.log(persons.childNodes);
// var ps = persons.getElementsByTagName("person");
// console.log(ps);
// console.log(ps[0]);
// var name = ps[0].getElementsByTagName("name")[0];
// console.log(name.firstChild.nodeValue);
// 獲取cdata節點
// var cdata = persons.childNodes[5];
// console.log(cdata);
// console.log(cdata.nodeType); // 4
// console.log(cdata.nodeName); // #cdata-section
// console.log(cdata.nodeValue);
// console.log(cdata.data);
// console.log(cdata.parentNode);
var newCDATA = xmlDoc.createCDATASection("這是CDATA數據");
persons.childNodes[3].appendChild(newCDATA);
console.log(persons.childNodes[3].childNodes);
}
loadXMLDoc("data.xml");
Web前端開發之Javascript-零點程序員-王唯
Hyper Text Markup Language, 超文本標記語言
標記又稱為標簽(Tag), 一般語法:
<tagName></tagName>
它可以有屬性(Attribute):
<tagName attributeName="value">, 如:
<meta charset="utf-8" />
標簽也可以不成對地關閉:
<tagName />
HTML文檔由瀏覽器解釋并執行。
<!DOCTYPE html> ----- 告訴瀏覽器用html5的標準來解釋和執行該網頁
<html>
<head> ---- 頭部, 可包含meta, title等標簽
</head>
<body> ---- 主體, 包含主要內容
</body>
</html>
<meta charset="utf-8" /> 用于告訴瀏覽器用什么樣的字符編碼來解釋網頁中的文本.
常見編碼:
iso-8859-1: 純英文編碼
gbk, gb2312: 簡體中文編碼
big5: 大五碼,繁體中文編碼,主要應用于臺灣地區
utf-8: 國際首選編碼,它兼容所有的字符
除此之外, meta還可以通過keywords, description屬性對頁面關鍵詞及描述信息進行設置, 以提高搜索引擎的命中.
網頁標題, 顯示在瀏覽器選項卡的標題欄上!
h1-h6: 內容標題標簽
p: 段落
br: 換行
hr: 水平線
strong: 粗體文本
em: 斜體文本
span: 無任何特殊樣式的文本
pre: 預格式標簽,其中的內容在頁面上帶格式渲染
small: 比當前字體小的文本
空格
< 小于
> 大于
? 版權符
" 雙引號
<!-- 注釋內容 -->
<img
src="圖像地址"
title="鼠標懸停提示"
alt="圖像加載錯誤時的替代文本"
width="寬度"
height="高度"
/>
圖像地址分為2種:
1. 相對地址, 如: img/cc.jpg
2. 絕對地址, 如: http://img.bcd.com/2017/1644232421.jpg
<a href="鏈接地址" target="目標窗口">文本|圖片</a>
目標窗口:
_self: 目標頁面在當前窗口打開
_blank: 目標頁面在新窗口中打開
如果是在頁面具有frameset/frame/iframe的場景下:
_top: 在頂級窗口中打開
_parent: 在父級窗口中打開
_自定義名稱: 在指定的特定窗口中打開
三種用法:
1. 頁面間鏈接
<a href="page/login.html"></a>
2. 錨鏈接
<a href="#help"></a>
help是本頁面中一處id為help的標簽, 如: <p id="help">
或者:
help是通過a標簽命名的錨記, 如: <a name="help"></a>
3. 功能性鏈接
喚醒本地安裝的外部程序如 outlook/foxmail/qq/msn/aliwangwang...
<a href="mailto:abcdef@qq.com"></a>
div是一個容器, 常用于頁面的布局
標簽的分類:
1. 塊級標簽/塊級元素
如: div, h1-h6, p, hr
特征: 獨占容器中的一行, 其寬度是容器的100%
2. 行級標簽/行級元素
如: span, img, strong, em, a
特征1: 多個行級元素可以同處一行, 其寬度由內容來撐開(auto)
特征2: 大部分行級元素設置其width/height無效
ctrl + D : 刪除當前行
ctrl + PgUp : 當前行上移
ctrl + PgDown : 當前行下移
ctrl + / : 注釋 | 取消注釋
ctrl + shift + F : 整理代碼格式
ctrl + C : 復制當前行
ctrl + X : 剪切當前行
ctrl + V : 粘貼
ctrl + Z : 撤消上一步操作
ctrl + S : 保存當前文件
ctrl + shift + S : 保存項目中全部文件
ctrl + Enter : 在當前行的下方插入新行
ctrl + shift + Enter : 在當前行的上方插入新行
以上知識能做的效果圖
部分效果
*請認真填寫需求信息,我們會在24小時內與您取得聯系。