DOM浏览
HTML文档的树状结构包含表示HTML标签或元素和表示文本字符串的节点,也包含表示HTML注释的节点。
Conmment节点代表HTML或XML的注释。由于注释基本上是文本字符串,因此它们很像表示文档中显式文本的Text节点。CharacterData通常是Text和Conmment的祖先,它定义这两种节点所共享的方法。Attr节点类型代表XML或HTML属性,但它几乎从不使用,因为和文档节点不同,Element类型定义了将属性当做“名/值”对使用方法。
选取文档元素
通过ID选取元素
举个栗子
var section1 = document.getElementById("section1")
通过名字选取元素
举个栗子
var sections = document.getElementByName("section");
- 和id不一样的是name属性值是在少数HTML元素中有效,包括表单、表单元素、
<iframe>
和<img>
元素。 - 注意,getElementsByName()定义在HTMLDocument类中,而不在Document类中,所有它只征对HTML文档可用,在XML文档中不可用。
- 为某些HTML元素设置name属性将自动为window对象中创建对于的属性,对Document对象也类似。为
<form><img><iframe><applet><embed><object>
元素(其中只有<object>
元素没有后备对象)设置name属性值, 即在Document对象中创建以此name属性值为名字的属性。 - 如果给定的名字只有一个元素,自动创建的文档属性对应的值该是元素本身。如果有多个元素,该文档属性的值是一个NodeList对象,它表现为一个包含这些元素的数组。这也就意味着有些元素作为document属性仅通过名字就可以获取
举个栗子
<body>
<form action="" method="post" name = 'form1'>
<input type="checkbox" name="n1" value=""/><label for="n1">1</label>
<input type="checkbox" name="n1" value=""/><label for="n1">2</label>
<input type="checkbox" name="n1" value=""/><label for="n1">3</label>
<input type="checkbox" name="n1" value=""/><label for="n1">4</label>
<input type="submit" value="确认"/>
</form>
</body>
<script>
var form = document.form1;
form.style.backgroundColor = 'red';
</script>
通过标签名选取元素
- 类似于getElementByName(),getElementByTagName()返回一个NodeList对象
举个栗子
/*查找文档的第一个<p>元素里所有<span>元素*/
var firstpara = document.getElementsByTagName("p")[0];
var firstParaSpan = firstpara.getElementsByTagName("span")
- HTMLDocument对象还定义两个属性,它们指代包含特殊的单个元素而不是元素的集合。document.body是一个HTML文档的
<body>
元素,document.head是<head>
元素,浏览器隐式地创建它们。Document类的documentElement属性指代文档的根元素,在HTML文档中,它总指代<HTML>
元素。 - NodeList和HTMLCollection具有实时性,假设在一个没有
<div>
元素的文档中调用getElementByTagName(“div”),此时返回值是一个length为0的NodeList对象。如果再在此文档中插入一个新的<div>
,元素将自动成为NodeList的一个成员,并且它的length属性变成1。
通过CSS类选取元素
getElementByClassName()只需要传入一个字符串参数,字符串参数可以使用空格隔开的标识符。只有当元素的class属性完全包含标识符的元素才会被匹配,但是标识符的顺序无关紧要。
举个栗子
// 查找以log命名且包含有"error"和"fatal"类的元素的所有后代
var log = document.getElementById("log");
var total = log.getElementsByClassName("error fatal");
通过CSS选择器选取元素
文档结构和遍历
作为节点树的文档
document对象,element对象和文档中表示文本的text对象都是node对象,并定义了一下属性:
node属性 | 注释 |
---|---|
parentNode | 该节点父节点(或者征对类似Document对象的应该是null,因为它没有父节点) |
childNodes | 只读数组的对象(NodeList对象),它是该节点的实时表示 |
firstChild、lastChild | 该节点子节点的第一个和最后一个,如果该节点没有字节点则为null |
nextSibling、previousSibling | 该节点的兄弟节点的前一个和下一个。具有相同父节点的两个节点为兄弟节点。节点的顺序反映了它们在文档中出现的顺序。这两个属性将节点之间的以双向链表的形式连接起来。 |
nodeType | 该节点的类型,9代表Document节点,1代表Element节点,3代表Text节点,8代表Comment节点,11代表DocumentFragment节点 |
nodeValue | Text节点或Comment节点的文本内容 |
nodeName | 元素的标签名,以大写形式表示 |
举个栗子
/*使用这些Node属性,可以用下面类似的表达式得到文档的第一个节点下面的第二个子节点的引用*/
document.childNodes[0].childNodes[1];
document.firstChild.firstChild.nextSibling;
作为元素树的文档
element属性 | 注释 |
---|---|
firstElementChild,lastElementChild | 类似firstChild和lastChild,但只代表Element |
nextElementSibling,previousElementSibing | 类似nextSibing和previousSibling,但只代表兄弟Element |
childElementCount | 子元素的数量。返回的值和chilren.length值相等 |
注意节点和元素不一样,举个栗子,<p>this is a text</p>
中,‘this is a text’是一个text节点,但不是element元素。
属性
HTML属性作为Element的属性
- HTML属性名不区分大小写,但是JavaScript属性名则大小写敏感,从HTML属性名装欢到JavaScript属性名应该采用小写,但是,如果属性名包含不止一个单词,则将第一个单词以外的单词的首字母大写
- 有些HTML属性名在JavaScript中是保留字,至于这些属性,一般的规则是为属性名加上前缀html,for–>htmlFor; class–>className;
举个栗子
var img = document.getElementById("myimage");
var imgsrc = img.src;
img.src === "myimage" //进行判断
获取和设置非标准的HTML属性
- Element类型同样定义了getAttribute()和setAttribute()方法可以查询和设置这些非准的HTML属性,当然也可以用来查询和设置XML文档中元素上的属性。
举个栗子
var image = document.images[0];
var width = parseInt(image.getAttribute("width"));
image.setAttribute("class","firstImage");
- 可以看出,基于属性的API与这种方法有两个重要的区别:1.属性值被当作是字符串,其返回值是字符串,而不是数值\布尔值对象。2.方法使用标准属性名,对于HTML来说,属性名不区分大小写
- Element类型还设置了两个相关的方法。hasAttribute()和removeAttribute(),他们用来检测是否存在属性和完全删除属性
数据集属性
- HTML5提供了一个解决方法,任意以小写data-作为前缀的属性名字都是合法的。这些“数据集属性”不会影响元素的表现,它们定义了标准的,附加额外数据的方法,并不是在文档合法性上做出让步。
- HTML5还在Element对象上定义了dataset属性。该属性指代一个对象,他的每一个属性相对于去掉前缀的data-属性。也就是说dataset.x保存的是data-x属性的值。并且对应这驼峰起名法。
作为Attr节点的属性
attributes属性是只读的类数组对象,它代表元素的所有属性。具有实时性,可以用数组索引访问,也可以用属性名索引访问(个人建议使用属性名)
举个栗子
document.body.attributes[0]; //<body>元素的第一个属性
document.body.attributes.bgColor //<body>元素的bgColor属性
document.body.attributes["ONLOAD"] //<body>元素的onload属性
元素的内容
作为HTML的元素内容
作为纯文本的元素内容
- 如果要查询元素中的纯文本,使用textContent属性来实现
var para = document.getElementsByTagName("p")[0];
var text = para.textContent; //'this is a simple document'
para.textContent = "hello world!" //修改段落内容
textContent(除IE)与innerText(除火狐)具有兼容性问题。两个区别是:
- textContent获取包含
<script>
和<style>
元素的所有元素的内容时,IE特定属性innerText不会。 - innerText会意识到元素的样式,不会返回隐藏的元素,textContent会将隐藏的元素一并返回;
- innerText有回流,textContent没有;
- innerText会解释HTML与CSS样式,并去除代码中的格式信息(如换行,缩进等),textContent不会有此步骤;
两者非常相似,经常可以互换,但是要小心空元素
举个栗子
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p>
this is a
<a href="#" style="color: red;">simple</a><br />document
</p>
<p style="display: none;">display</p>
<p style="visibility: hidden;">hidden</p>
</body>
<script>
var para =document.getElementsByTagName('p')[0];
var bd = document.getElementsByTagName('body')[0];
</script>
</html>
控制台输出
作为Text节点的元素内容
使用nodeValue属性。
创建、插入、删除节点
创建节点
创建新的Element节点可以使用Document对象的createElement()方法。给方法传递元素的标签名:对HTML文档来说名字不容易区分大小写,对XML文档则区分大小写。
插入节点
insertBefore()就像appendChild()一样,接受两个参数,第一个是待插入的节点,第二个参数是已经存在的节点,新节点将插入该节点的前边。该方法应该是在新节点的父节点上调用,第二个参数必须是该父节点的子节点。如果传递null作为第二个参数,insertBefore()的行为类似appendChild(),它将节点插入在最后。
举个栗子
//表格的行排序(网易2017春招题目)
/**表格的排序**/
//根据指定表格每行第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;
});
//在tobody中按他们的顺序把行添加到最后
//这将自动把它们从当前位置移走,故没必要预先删除它们
//如果<tbody>还包含除了<tr>的任何其他元素,这些节点都将会悬浮到顶部位置
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)); //将i的全局变量赋值给局部变量n
}
}
删除和替换节点
- removeChild()就是从文档树中删除一个节点,但是请小心:该方法不是在待删除的节点上调用,而是(就像其名字的一部分“child”所暗示的一样)在其父节点上调用。在父节点上调用该方法,并将需要删除子节点作为方法参数传递给它。
- replaceChild()方法删除一个子节点并用一个新的节点取而代之。在父节点上调用该方法,第一个参数是新节点,第二个参数是要替代的节点
举个栗子
//用新的元素<b>替换n节点,并将n作为该节点的子节点
function embolden(n){
if(typeof n == "string") n = document.getElementById("n");
var parent = n.parentNode;
var b = document.createElement("b");
parent.replaceChild(b,n);
b.appendChild(n);
}
使用DocumentFragment
DocumentFragment是一种特殊的node,作为其他节点的一个临时容器,类似于Document节点,但是DocumentFragment式独立的,并不是任何文档的一部分,它的parentNode总是null,类似于Element,可以有任意数量的子节点,可以使用appendChild()、inserBrfore()或者replaceChild()传递一个DocumentFragment。
举个栗子
文档和元素的几何形状和滚动
文档坐标和视口坐标
- 向右为+x,向下为+y,有像个不同的原点坐标:相对于文档的左上角或者相对于在其中的显示文档的视口的左上角。
- 如果闻到那股比视口要小,或者说它没有出现滚动条,这个时候文档的左上角就是视口的左上角,视为同一个。
- 一般来说,两个原点的相互转化必须加上滚动条的偏移量。
查询元素的几何尺寸
- 判定一个元素尺寸和位置最简单的方法是调用它的getBoundingClientRect()方法,它不需要参数,返回一个有left,right,top,bottom的属性对象。left和top表示左上角的x和y坐标。right和bottom属性表示元素右下角的x和y坐标。
- getBoundingClientRect()对象还包含width和height属性,但在原始的ie中未实现。还返回元素的边框和内编剧,但是不包含元素的外边距。
var box = e.getBoundingClientRect(); //获得视口在坐标中的位置
var w = box.width || (box.right - box.left);
var h = box.height || (box.bottom - box.top);
- (冷门)注意,浏览器在布局时块级元素总是矩形,但是,内联元素可能跨越多行,因此可能由多个矩形组成。例如,一个被切断的斜体字体,它由第一行的右边和第二行的左边共同组成,此时调用getBoundingClientRect(),它返回的“边界矩形”,会包含整整两行的宽度。
- 注意返回值都是只读属性,且结果不具有实时性。
滚动scrollTo() scrollBy() scroll()
- scrollTo()与scroll()等价,包含两个参数,第一个表示x轴的偏移量,第二个表示y轴的偏移量。让窗口滚动到指定的点,使其出现在视口。相对与视口原点的偏移
- scrollBy()参数与上述相同,不同的是偏移量表示的是在当前滚动条的偏移量基础上的增加。
HTML表单
HTML元素 | 类型属性 | 事件处理程序 | 描述和事件 |
---|---|---|---|
<input type="button">或<button type="button"> | “button” | onclick | 按钮 |
<input type="checkbox"> | “checkbox” | onchange | 复选按钮 |
<input type="file"> | “file” | onchange | 载入web服务器文件的文件名输入域;它的value属性是只读的 |
<input type="hidden"> | “hidden” | none | 数据由表单提交,但是对用户不可见 |
<option> | none | none | select对象的单个选项,事件处理发生在select上面 |
<input type="password"> | “password” | onchange | 密码输入框,输入的字符不可见 |
<input type="radio"> | “radio” | onchange | 单选按钮 |
<input type="reset">或<button type="reset"> | onclick | 重置表单按钮 | |
<select> | “select-one” | “onchange” | 选项只能单选的列表或者下拉菜单 |
<select multiple> | “select-multiple” | onchange | 可以多选的下拉菜单 |
<input type="submit">或<button type="submit"> | “submit” | onclick | 表单提交按钮 |
<input type="text"> | “text” | onchange | 单行文本输入域,type属性缺少或者无法识别时默认的input元素 |
<textarea> | “textarea” | onchange | 多行文本输入域 |
选取表单和表单元素
- querySelectorAll()可以选取表单元素
举个栗子
var fields = document.getElementById("address").getElementsByTagName("input");
/*id为shipping的表单中的所有name为methed的单选按钮*/
document.querySelectorAll('#shipping input[type="radio"][name="methed"]');
- 要明确选取一个表单元素,可以索引表单对象的elements属性,例如选取shipping表单中name为methed的单选按钮,需要注意的是,form表单本身就有HTML属性和对应的js属性交“methed”,所以,必须使用该表单的elements属性进行间接访问methed属性。
var methed = document.forms.shipping.elements.methed
表单元素相关
- placeholder属性指定了输入域中显示的提示信息
- 获取select选取的元素使用selected属性
其他文档特性
- 会将字符串连接起来,然后将字符串插入到调用它的脚本元素的位置。
注意:只有在脚本解析结束之后才会出现在文档中,执行如下代码
举个栗子
document.write('1');
document.write('2');
alert('3');
document.write('4');
document.write('5');//会发现,只有在alert确认之后才会生成字符串显示,也就是说先弹出3,后显示1245
- 查询选取的文本使用getSelection
举个栗子
function getSelectedText(){
if(window.getSelection){//标准api
return window.getSelection().toString()''
}else if(document.selection){//兼容IE
return document.selection.createRange().text;
}
}
- 可编辑内容使用属性contenteditable
<div contenteditable>click to edit</div>