DOM,即文档对象模型(Document Object Model),是通过JavaScript来对HTML文档进行管理和操作的一类 对象模型,通过DOM可以操作HTML的元素和元素的属性,包括对元素的增删改等操作。
首先需要了解DOM的理论,DOM是将一系列HTML元素看做对象进行管理的操作方法,每个HTML的元素节点都是一个可调用的对象,通过对象的方法可以对元素进行操作。DOM是树形结构的模型,最顶级的节点是文档节点,即document对象,他可以理解为整个HTML文档,或者是
标签,然后在标签中有许多子元素,包括body和head都是html的子元素,接下来body是网页的主体部分,在这里又有很多的子元素,这些子元素又有很多属性,所有的这些节点和属性都可以被看做是对象。
DOM模型图示:
由图可知:文档是整个树的根,其中的根元素是标签,对应的JavaScript对象是document,往下一级元素是head和Body,这两个元素定义了文档的头部和主体,在头部中的title标签定义了文档的标题,这个标题有一个特殊点就是,虽然他是head的子元素,但是他可以在document对象中直接调用。
例如;
document.title="DOM测试";
这段代码就会改变整个文档的标题,因为title可看做是document对象的一个属性,调用这个属性并重新赋值就可以改变title的内容。
注意,虽然title是html下的一个子标签,但是他不作为节点,他是文档的属性(标题),所以通过document对象可以直接修改他的值。
我们也可以通过document对象直接操作body的内容,例如:
document.body.style.color="red";
这样会修改body内也就是整个页面的文字颜色为红色。
因为在document对象中直接包含了body作为子对象,且style是body标签属性,实际上在DOM中,style是用作对css进行操作的,这里我们暂时理解为标签属性,他是body的子对象,因此他可以包含一些属性和方法,显然,color就是style的对象属性。
简单来说,document是一个对象,body是一个对象,且是document的子对象,style又是body的子对象,而style不是标签,就没有子对象,color只能作为对象的属性了。
同理,修改body下的字体大小:
document.body.style.fontSize="20px";
值得注意的是,JavaScript的类属性和方法采用严格的小驼峰法命名,并且不能使用连字符作为命名,所以在CSS中对应的font-size属性在DOM中应该写为:fontSize.
同理,border-radius应该写作borderRadius。
我们是否可以这样做:
document.body.p.style.color="red";
绝对不可以!这样做会产生错误!因为DOM是树形展开的,并且只有属性能作为标签的子对象,在任何一个标签的对象下,都只包含这个标签的属性和一些DOM自带的属性、方法,子对象只能通过选择的方式获取对象。
如何对body下的标签进行管理呢?
需要使用document对象中的方法来完成操作:
1.getElementById()方法:
getElementById()方法是通过元素的id来获取元素对象,因为id在HTML文档中原则上是唯一的,所以它一次只会获取一个元素。然后返回的内容就是这个id的元素的对象。
例如:
HTML:
<p id="test">这是一段测试文本</p>
JS:
document.getElementById("test").inneHTML="但是他的文字被修改了";
innerHTML是元素对象下的一个属性,代表标签内的内容。通过getElementById()方法获取id为test的元素的对象,然后修改innerHTML属性即修改元素内容。也可以通过这种方式向元素内添加新元素:
document.getElementById("test").inneHTML="<a href='../'>这是一个链接</a>";
但是通常情况下我们不选择这么做,因为这样代码美观性不足,并且不适合完成复杂的添加节点操作,所以我们一般采用createElement()的方式,会在下文中叙述。
2.getElementsByName()方法:
getELementsByName()是通过HTML标签的name属性来查找HTML元素,所以方法名式Elements而不是Element,因为HTML允许多个标签是同一个name属性。此方法返回的是一组对象组成的数组。
而我们在对通过此方法获得的节点进行操作时,必须选中指定的元素才能访问DOM提供的方法和属性,因为他返回的不是某个节点的对象,而是所有符合条件的对象组成的数组,通常情况下,我们如果想要对所有的这些节点进行修改,会使用for循环来完成。
注意:即使只有一个节点的name属性与选择的内容相同,返回的仍然是节点组成的数组,通过指定数组下标才能选取对应的节点。同时对于新手可能还会有一个误区,通过typeof判断返回的数据类型是 Object,这不是对象吗?千万别忘了!JavaScript的数据类型比较特殊,所有的引用类型都是对象!Array
HTML:
<input type="checkbox" name="hobby" value="basketball">basketball
<input type="checkbox" name="hobby" value="baseball">baseball
<input type="checkbox" name="hobby" value="ping-pong">ping-pong
JavaScript:
list=document.getElementsByName("hobby"); //获取已选的复选框
for(i=0;i<=list.length;i++){
if(list[i].checked==true){
document.write("兴趣爱好是:"+list[i].value);
}
}
以上代码是是简单的验证已选的复选框的内容,上面已经提到,每个HTML标签的属性都会被作为属性存在标签的对象中,所以在我们选中节点(标签对象)时,就可以直接通过访问节点属性访问标签的内容。如上,list[i]就是遍历的每个复选框的节点对象。通过访问属性就可以得到对应的标签属性,list[i].checked就是复选框的check属性,如果复选框被勾选就是true如果没有被勾选就是false。
document.write()是在文档中写入内容的方法。
3.getElementsByClassName()方法:
getElementsByClassName()是通过HTML元素的类名获取节点,返回的同样是一组有序的对象的组成的数组,与getElementsByName用法相同。
例:修改所有类名为women的元素字体颜色为红色。
HTML:
<div>
<p class="women">小芳</p>
<p class="man">小刘</p>
<p class="women">小樱</p>
</div>
JavaScript:
list=document.getElementsByClassName("women");
for(i=0;i<=list.length;i++){
list[i].style.color="red";
}
效果:
3.getElementsByTagName()方法:
getElementsByTagName()即通过标签名选中节点,与上面两个方法一样,就不演示了。 4.createElement()方法:
createElement()方法是document对象的直属子方法,并且只有document对象可以使用此方法,别的节点对象没有此方法。此方法的用处是创建一个节点对象,但是这个对象不会直接写入文档,而是在内存中,需要通过appendChild()方法来将此节点添加到某个元素中,参数值是要创建的节点名即HTML标签名。
例:在body中插入一个div元素,并且在div中插入一个无序列表,然后将列表标记删除。
divnode=document.createElement("div");
ulnode=document.createElement("ul");
for(i=0;i<=3;i++){
linode=document.createElement("li");
linode.innerHTML="项目"+i;
ulnode.appendChild(linode);
}
ulnode.style.listStyleType="none";
divnode.appendChild(ulnode);
document.body.appendChild(divnode);
效果:
appendChild()方法:
appendChild()方法即在某个元素的节点下插入子元素,方法的参数是一个节点的对象,一般配合createElement()方法使用。
appendChild()方法可以用于节点对象下,如果用于document下,会产生一个错误:only one element on document allowed.
例:向表单中新增一个备注框。
HTML:
<form method="POST" id="form">
<input type="text" name="name" placeholder="姓名">
<input type="text" name="phone" placeholder="手机号">
<input type="text" name="code" placeholder="编号">
</form>
Javascript:
form=document.getElementById("form");
input=document.createElement("input");
input.type="text"; input.name="beizhu";
input.placeholder="备注";
form.appendChild(input);
效果:
能否选中一个元素,然后将他的内容添加到另一个元素中,比如:
var a=document.getElementById("a");
var div=document.getElementById("div");
div.appendChild("a"");
这样做的话,原来的id为a的元素会消失,会被移动到id为div的元素下,所以我们可以通过这种方法移动元素。因为每个元素对应的都是一个唯一的对象,获取的这个对象就是这个元素的整个标签内容,这个对象中也包含元素的节点位置,因此,将通过js选中的元素添加的另一个元素的子对象,会将唯一的元素添加到另一元素的对象中。
cloneNode()方法:
既然通过选中元素直接添加子元素的方法无法复制元素,JS自然会给出复制元素的方法,也就是cloneNode方法,cloneNode方法只会克隆节点以及节点的属性,而不会改变文档树。
该方法有一个参数,表示是否复制该节点下的子节点。参数类型是bool,如果是true则连同元素下的子节点一同复制,如果是false则只复制当前节点。
例:
HTML:
<p>是一个段落<a color="blue" href="../">这是一个超链接</a>
</p>
<div id="t">
</div>
JS:
div=document.getElementById("t");
p=document.getElementsByTagName("p");
pnode=p[0].cloneNode(0)
div.appendChild(pnode);
运行一下这段代码,发现没有任何反应?因为这时候参数为0,也就是false,这时方法只会克隆节点,而不会克隆节点内容,如果我们打印一下pnode,发现他的值是
<p></p>
查看源代码,div元素中多了一个子元素P,但是没有内容。
为什么p里面的字也没有被克隆呢?实际上,节点中的内容也可被认为是子元素,p中的文字是一个文字节点,他自然不能是与p同级的节点,所以不会被克隆,我们也可以对已选中节点新增文字节点。
上面的例子,只要将cloneNode的0改为1就可以将节点内容和子元素复制下来。接下来测试文本节点方法。
createTextNode()方法
createTextNode()方法即创建一个文本节点,他是document对象下的方法,返回一个文本节点对象。
例:
p=document.getElementsByTagName("p")
text=document.createTextNode("测试文本")
p[0].appendChild(text); //为第一个p元素添加测试文本。
以上是常用的DOM方法,然而这只是冰山一角,DOM提供了非常多的document属性方法和元素的属性和方法,关于这些更多的方法和属性,会另起篇幅详述。