整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

html实体编码遇上js代码

双引号

在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()。

特征:

  • nodeType值为3;
  • nodeName的值为”#text”;
  • nodeValue的值为节点所包含的文本;
  • parentNode是一个Element;
  • 没有子节点;

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类;

特征为:

  • nodeType值为8;
  • nodeName值为#cooment;
  • nodeValue的值为注释内容;
  • parentNode可能是Document或Element;
  • 没有子节点;

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()之外的所有字符串操作方法;

其特征:

  • nodeType的值为4;
  • nodeName的值为#cdata-section;
  • nodeValue的值为CDATA区域中的内容;
  • parentNode可能为Document或Element;
  • 没有子节点;

在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-零点程序员-王唯

么是HTML

Hyper Text Markup Language, 超文本标记语言

标记又称为标签(Tag), 一般语法:

<tagName></tagName>

它可以有属性(Attribute):

<tagName attributeName="value">, 如:

<meta charset="utf-8" />

标签也可以不成对地关闭:

<tagName />

HTML文档由浏览器解释并执行。

HTML文档基本结构

<!DOCTYPE html> ----- 告诉浏览器用html5的标准来解释和执行该网页

<html>

<head> ---- 头部, 可包含meta, title等标签

</head>

<body> ---- 主体, 包含主要内容

</body>

</html>

meta

<meta charset="utf-8" /> 用于告诉浏览器用什么样的字符编码来解释网页中的文本.

常见编码:

iso-8859-1: 纯英文编码

gbk, gb2312: 简体中文编码

big5: 大五码,繁体中文编码,主要应用于台湾地区

utf-8: 国际首选编码,它兼容所有的字符

除此之外, meta还可以通过keywords, description属性对页面关键词及描述信息进行设置, 以提高搜索引擎的命中.

title

网页标题, 显示在浏览器选项卡的标题栏上!

文本排版标签

h1-h6: 内容标题标签

p: 段落

br: 换行

hr: 水平线

strong: 粗体文本

em: 斜体文本

span: 无任何特殊样式的文本

pre: 预格式标签,其中的内容在页面上带格式渲染

small: 比当前字体小的文本

html特殊字符/转义字符

空格

< 小于

> 大于

© 版权符

" 双引号

html注释

<!-- 注释内容 -->

图像标签

<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标签

div是一个容器, 常用于页面的布局

标签的分类:

1. 块级标签/块级元素

如: div, h1-h6, p, hr

特征: 独占容器中的一行, 其宽度是容器的100%

2. 行级标签/行级元素

如: span, img, strong, em, a

特征1: 多个行级元素可以同处一行, 其宽度由内容来撑开(auto)

特征2: 大部分行级元素设置其width/height无效

HBuilder常用快捷键

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 : 在当前行的上方插入新行


以上知识能做的效果图

部分效果