DOM基础
概念:document object model,文档对象模型,主要的目的就是把网页里面的元素当对象一样进行操作
网页当中的元素与我们之前所学习的对象非常像,它有标签名(对象名称),它也有属性,也有属性值
我们要是把网页当中的元素当成对象一样的去操作的时候,这样就很方便了
DOM技术的本质就是网页与JavaScript的结合,它将我们之前所学习的JavaScript应用在了页面上面,有JavaScript来操作网页
DOM技术里面又分为两个部分,第一个部分就是JavaScript与HTML的结合,第二部分就是JavaScript和CSS的结合
在学习DOM技术之前,有几个点要根据同学样说明一下
- document就是文档的意思,因为文档指的就是当前网页,所以在DOM里面整个网页最终会形成一个对象叫
document
对象 - 页面上面所有的元素(标签)最终都会被转换成JavaScript里面的对象(所以我们操作标签元素就可以像之前操作对象一样去操作了)
- 如果是非IE的浏览器,它会根据每个ID生成一个对象,方便我们直接取用
在上面我们已经讲过了可以直接使用ID来获取网页中当标签,如果这个标签没有ID名称怎么办呢?
如果我们想要操作某一个标签元素,最开始应该是怎么从网页当中获取这个元素
通过JavaScript获取页面元素
首先要弄清楚第一步:当前的页面指的是document
-
通过ID来获取页面的元素
document.getElementById("div1");
通过这种方式去获取,永远只能够获取到0个(null)或1个,如果通过id找到这个元素了就是1个,如果找不到这个元素就是null
注意ID名称重复的情况下,则找到的永远是第一个
-
通过class名称来获取页面元素
document.getElementsByClassName("div2");
通过这种方式,获取的是一个
HTMLCollection
的集合(类数组),具备数组的特性,不具备数组的方法 。这个集合里面存放是我们的DOM对象,如果一个元素都获取不到,它就是一个空的类数组[]
-
通过标签名称来获取页面元素
document.getElementsByTagName("p"); document.getElementsByTagName("div");
通过这种方式,获取到的的也是一个
HTMLCollection
的类数组,通过页面上面的某一个标签来获取页面上面的元素 -
通过name名称来获取页面上面的元素
document.getElementsByName("sex");
通过这种试,获取的是一个
NodeList
的集合,它也是一个类数组,具备数组特性,不具备数组方法,这个集合里面存放就是我们的DOM对象,如果一个元素都获取不到,则就是一个空的类数组[]
上面的4种方式是我们最基本的4种方式,这种方式兼容性比较好,可以在大多数的浏览器里面去使用,它可以解决我们日期工作当中的很多问题
如果页面的结构比较复杂,则我们就需要使用更高级的方式了。如下面的代码
<div id="div1">
<div class="div2">
我爱北京天安门
</div>
<div class="div2">
天安门上太阳升
</div>
<div class="div3">
大家好才是真的好
</div>
</div>
<div class="div2">这是第二个盒子</div>
<div class="div2">这是第二个盒子的副本</div>
<p>这是一个段落标签</p>
<input type="radio" name="sex">男
<input type="radio" name="sex">女
在上面的网页结构里面,如果我们想获取到id="div1"
里在的class="div2"
的元素又怎么办呢?
//第一步:先获取div1这个元素
var div1 = document.getElementById("div1");
//第二步:在div1里面去找class="div2"的元素,我们之前都是在document里面去找,现在在div1里面找
var div2 = div1.getElementsByClassName("div2");
这是我们很早以前的一种解决方案,现在我们已经不再使用这种方式了,转而使用新的方法(强烈推荐)
新的方法便是结合了HTML5与CSS3的东西,它将我们CSS3里面的9大选择器与之前的JavaScript进行了结合
-
通过
querySelector()
来获取元素document.querySelector("#div1"); //id="div1"的元素 document.querySelector(".div2"); //class="div2"的第一个元素
这种方式是通过选择器来选择元素,如果找到了元素就返回1个元素,如果找不到就返回
null
即使找到了多个元素,也只返回第1个元素
-
通过
querySelectorAll()
来获取元素document.querySelectorAll("#div1"); //id="div1"的所有元素,用集合包裹 document.querySelectorAll(".div2"); //class="div2"的所有元素,用集合包裹 document.querySelectorAll("#div1>.div2");
这种方式也是通过指定的选择器来获取元素,它返回的是一个
NodeList
的类数组,里面要包含了要查找了元素,如果找不到就返回一个空的NodeList[]
📘 总结:getElementById
与querySelector()
都是返回1个或null,找到就返回第1个,找不到就返回null
querySelectorAll
和后面的getElementsBy****
都是返回一个集合
DOM结构
DOM本身也是一个对象,我们之前也讲过对象,并且知道对象具备属性与方法
现在我们就来分析一下页面上面的DOM对象
通过对三种标签对象的对比分析,我们发现所有元素最终都会继承自Node
对象(EventTarget
暂不做考虑,后面在DOM事件章节进行讲解),我们就可以把Node对象当成所有页面元素对象的父级。这个时候,我们只要把Node对象弄清楚了,那么所有页面上面的元素也就弄清楚了
我们在上面的结构里面看到了第三级对象叫Element
第四级对象叫Node
,它们之间有什么区别呢
通过字面意义来理解,Element
是元素的意思,Node
是节点的意思
Element与Node的区别
<div id="div1">
我在前面插入了一段文字
<div class="div2">第一行</div>
<div class="div2">第二行</div>
<!-- 这是添加了一个注释 -->
</div>
- 在网页当中,所有的标签它都是一个元素(element),同时也是一个节点(Node)
- 但是并不是所有的节点
Node
都会是一个元素Element
(节点包括元素,文字,注释,回车)
在上面的网页结构里面,div1里面的元素就仅仅只有class="div2"
的这两个元素,但是它的节点就有很多,包含了里面的文字与注释,还有回车键
Element常用属性
element
指的就是页面上面的标签所形成的元素,我们现在就要去学习它面的属性以方便我们后期对页面进行相关的操作
-
children
属性,获取当前元素下面的子级元素,它返回的是一个HTMLCollection
的集合到目前为止,我们已经有三种方式获取页面的子级元素
//第一种方式 var ul1 = document.getElementById("ul1") var lis = ul1.getElementsByTagName("li"); //第二种方式 var lis = document.querySelectorAll("#ul1>li"); //第三种方式 var ul1 = document.querySelector("#ul1"); ul1.children;
表面上看起来这三种方式里面,后面的的新的方式没有前面的第一种与第二种好,但是要我们考虑一个问题,第一种方式的
getElementsByTagName
也好,第二种方式的CSS选择器也好,都只能选中儿子,不能选中父级,所以JavaScript里面的DOM操作中才会有children
,它就是为我们形成一整体的获取元素的方法 -
parentElement
属性,用于获取当前元素的父级元素 -
nextElementSibling
属性,用于获取当前元素的下一个兄弟元素 -
previousElementSibling
属性,用于获取当前元素的前一个兄弟元素
前面的四个方法就是以当前元素为中心去获取父级了,子级的,前一个,后一个的元素
-
className
属性,获取或设置当前元素的class
名称<style> .div1 { width: 200px; height: 200px; border: 1px solid black; } .p1{ color: red; } .p2{ color: blue; } .p3{ font-size: 46px; } </style> <div class="div1 p1"> 旧时茅店社林边,路转溪头忽现 </div> <script> var div1 = document.querySelector(".div1"); //拿到div1这个元素以后,我们调用className属性 div1.className; //"div1 p1"这么样个东西 //第一步操作:请将.p3这个样式设置在div1元素上面 div1.className += " p3"; //第二步操作:请将p1换成p2 div1.className = div1.className.replace("p1","p2"); </script>
通过上面这种方式去操作非常不方便 ,我们一般在工作中也不会这么去操作。我们有一个更好的方式去操作
-
classList
属性,返回当前元素的class名称集合,它返回的是是一个DOMTokenList
对象(类数组),这个集合里面包含了所有的class名称-
add()
方法,在当前元素的classList里面添加一个class名称div1.classList.add("p3");
-
remove()
方法,在当前的classList里面删除一个class名称div1.classList.remove("p1");
-
toggle()
方法,如果classList里面有这个样式就删除,如果没有这个样式就添加div1.classList.toggle("p3");
-
contains()
方法,判断当前的classList集合里面有没有这个class样式,如果有则返回true,如果没有则返回false
现在我们使用这一种方式去操作元素的class名称就比之前通过
className
的方式去操作class名称要方便很多 -
-
firstElementChild
属性,获取当前元素下面的第一个子元素,相当于children[0]
-
lastElementChild
属性,获取当前元素下面的最后一个子元素 -
innerText
属性,获取或设置当前元素里面的文本内容,如果赋值的时候是HTML标签,那么依然会以文本的形式赋值进去,不会进行HTML的转义<div class="div1"> <p id="p1">这是一个段落</p> </div> <script> var div1 = document.querySelector(".div1"); div1.innerText; //取值,"这是一个段落" div1.innerText="我在向里面赋值"; div1.innerText="<b>我向里面赋标签了</b>"; //赋值进去依然是一个带标签的文本 </script>
-
innerHTML
属性,获取或设置当前元素内部的HTML内容,如果赋值的时候是一个HTML标签文本,则会进行转义(我们以上一题的代码为例子)var div1 = document.querySelector(".div1"); div1.innerHTML; //取值 "<p id="p1">这是一个段落</p>" div1.innerHTML = "<b>我向里央赋值标签了</b>";
-
tagName
当前属性会返回当前元素的标签名称(这个标签名称是全大写的) -
value
属性,它是表单元素里面才会有属性,可以对这个属性取值与赋值<form> <input id="userName" name="userName" placeholder="请输入用户名"> <hr> <input type="password" id="pwd" name="pwd" placeholder="请输入密码"> <hr> <select id="select1"> <option value="男">男</option> <option value="女">女</option> </select> </form> <script> //所有的表单元素在这里面都会有一个value这样的属性 var userName = document.querySelector("#userName"); var pwd = document.querySelector("#pwd"); var select1 = document.querySelector("#select1"); //取值 userName.value; pwd.value; select1.value; //赋值 userName.value="杨兰芳"; pwd.value="abc"; select1.value="女"; </script>
-
childElementCount
当前元素的子元素的个数
Element常用方法
-
createElement()
方法,根据标签名创建一个标签元素var div1 = document.createElement("div"); var p1 = document.createElement("p");
-
appendChild()
方法,向当前元素里面的最后去追加一个新的元素div1.appendChild(p1); //将p1追加到了div1标签内部的最后 document.body.appendChild(div1); //再将div1追加到网页的body里面
-
remove()
方法,删除当前的元素(里面的子元素也会一并删除) -
removeChild()
方法,删除指定的子元素,返回这个删除的子元素ul1.children[1].remove(); //直接找到这个子元素去删除 ul1.removeChild(ul1.children[1]); //删除指定的子元素,返回删除的这个元素
-
cloneNode()
克隆一个相同的元素出来,它接收一个参数,这个参数是布尔类型,默认是false如果给它一个参数
true
,则代表要克隆子元素var ul2 = ul1.cloneNode(); //只克隆当前这个元素 var ul3 = ul1.cloneNode(true); //克隆当前的元素和所有的子元素
-
insertAdjacentElement()
方法,向指定的位置插入元素var ul1 = document.querySelector(".ul1"); //现在创建一个新的li var newli = document.createElement("li"); newli.innerText = "插入项"; //ul1.insertAdjacentElement(位置,newli); // 它的第一个参数接收一个位置,这个位置它是一个特殊的参数 ul1.insertAdjacentElement("afterend",newli);
参数值 解释 beforeBegin 开始标签之前 afterBegin 开始标签之后 beforeEnd 结束标签之前 afterEnd 结束标签之后 除了有
insertAdjacentElement
这个方法插入元素以外,我们还有与之相似的另外两个方法insertAdjacentHTML
这个方法插入网页标签insertAdjacentText
这个方法插入文字
var p1 = "<p>这是一个p标签</p>"; ul1.insertAdjacentHTML("beforeBegin",p1); //--------------------------------------------------- var str = "我在你的后面插入了文字了"; ul1.insertAdjacentText("afterEnd",str);
针对我们要插入的东西的不同,我们在这里调的方法也不相同
HTMLCollection与NodeList的区别
之前讲过元素的获取,我们通过document.getElementsByTagName
获取到的元素是一个HTMLCollection
的集合,而通过document.getElementsByName/document.querySelectorAll
获取到的又是一个NodeList
的集合,那么这两个集合有什么区别呢?
<body>
<ul class="ul1">
<li>第一项</li>
<li>第二项</li>
<li>第三项</li>
<li>第四项</li>
<li>第五项</li>
</ul>
</body>
<script>
//要求删除ul1内部所有的li元素
</script>
现在有上面的代码,我们如果要删除这个ul1内部所有的li,我们应该怎么操作呢
首先我们要先获取到里面的所有li,然后再去调用remove()
的方法去删除
第一种方式获取li
var ul1 = document.querySelector(".ul1");
var lis1 = ul1.children; //这个时候得到的是一个HTMLCollection的集合
for (var i = 0; i < lis1.length; i++) {
lis1[i].remove();
}
这个时候我们发现并没有完全删除里面的li,因为它是一个动态的集合,它的索引会发生改变,这种现象叫沙漏效应,对于这种动态的集合,我们一般都是采取倒序的形式去删除
for (var i = lis1.length - 1; i >= 0; i--) {
lis1[i].remove();
}
第二种方式获取li
var lis2 = document.querySelectorAll(".ul1>li");
//这个时候得到的是一个NodeList的集合
for (var i = 0; i < lis2.length; i++) {
lis2[i].remove();
}
这个时候我们看到页面上面所有的元素都删除了,说明NodeList
并没有形成一个沙漏效应
HTMLCollection
是一个动态的集合,而NodeList
是一个静态的集合
通过上面的例子我们演示了元素的删除,其实在元素添加的时候也可以看到HTMLCollection
与NodeList
的区别
<ul class="ul1">
<li>第一项</li>
<li>第二项</li>
<li>第三项</li>
<li>第四项</li>
<li>第五项</li>
</ul>
<script>
var ul1 = document.querySelector(".ul1");
//第一种方式获取li
var lis1 = ul1.children; //HTMLCollection
//第二种方式获取li
var lis2 = document.querySelectorAll(".ul1>li"); //NodeList
//现在创建了一个新的li
var newli = document.createElement("li");
newli.innerText = "我是新追加的项";
ul1.appendChild(newli);
//这个时候lis1已经变成6个了,因为它是动态集合
//而lis2还是5个,因为它是一个静态集合
</script>
作业与练习
-
根据代码完成指定要求
这个练习主要是对DOM里面的常用属性进行了一个练习
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>家庭作业</title> </head> <body> <div class="div1"> <p>大家好</p> <span>我是标哥哥</span> <div>在这里我们来演示DOM操作 <p>这是div里面的p标签</p> </div> <p class="p2">我是p2的class</p> <p>我又是一个p标签</p> </div> </body> <script> //要求,获取div1盒子里面所有的p元素的内容,然后打印出来,但是不能包含class为p2的元素 </script>
要求:获取div1盒子里面所有的p元素的内容,然后打印出来,但是不能包含class为p2的元素
第一种方法
var p_list = document.querySelectorAll(“.div1 p:not(.p2)”);
//需要把这个类数组里同的所有元素都拿出来,然后取出里面的内容
for (var i = 0; i < p_list.length; i++) {
console.log(p_list[i].innerText);
}
**第二种方法**,这种方法使用了递归的思路一层一层的去遍历
```javascript
var div1 = document.querySelector(".div1");
function getChildrenElemnts(childrenElements) {
for (var i = 0; i < childrenElements.length; i++) {
//判断当前元素的名称是p标签,但是class里面又不能有p2
if (childrenElements[i].tagName == "P" && childrenElements[i].classList.contains("p2") == false) {
console.log(childrenElements[i].innerText);
}
//判断当前元素还有没有子元素,如果有同则继续遍历
if (childrenElements[i].childElementCount > 0) {
//递归调用
getChildrenElemnts(childrenElements[i].children);
}
}
}
getChildrenElemnts(div1.children);
-
根据代码要求完成结果
<body> <ul class="ul1"> <li>第一项</li> <li>第二项</li> <li>第三项</li> </ul> </body> <script> //生成一个新的li,把这个li元素放到第二项和第三项之间 </script>
//生成一个新的li,把这个li元素放到第二项和第三项之间 var newli = document.createElement("li"); newli.innerText = "标哥向里面插入的内容"; var ul1 = document.querySelector(".ul1"); // ul1.children[1].insertAdjacentElement("afterEnd",newli); ul1.children[2].insertAdjacentElement("beforeBegin",newli);
-
现在如下对象,请按要求在页面上面生成指定代码
<body> <ul> <li>userName----标哥哥</li> <li>age----18</li> <li> <ul> <li>hobby----看书</li> <li>hobby----睡觉</li> </ul> </li> <li>address----湖北省武汉市</li> <li>sex----男</li> </ul> </body> <script> var stu1 = { userName: "标哥哥", age: 18, hobby: ["看书", "睡觉"], address: "湖北省武汉市", sex: "男" }; </script>
提示:这个地方要用到对象的属性遍历
//1. 先创建一个ul的标签 var ul1 = document.createElement("ul"); //2. 先遍历这个对象 for (var i in stu1) { //i就是stu1对象里面的每一个属性名 if (Array.isArray(stu1[i])) { //说明这个属性值是数组 var subul = document.createElement("ul"); for (var j = 0; j < stu1[i].length; j++) { var newli = document.createElement("li"); newli.innerText = i + "----" + stu1[i][j]; subul.appendChild(newli); } var outnewli = document.createElement("li"); outnewli.appendChild(subul); ul1.appendChild(outnewli); } else { var newli = document.createElement("li"); //3. 设置newli里面内容 newli.innerText = i + "----" + stu1[i]; ul1.appendChild(newli); } } //4. 将ul1追加到网页里面去 document.body.appendChild(ul1);
-
根据要求完成指定操作
var students = [ { userName:"张珊", sex:"好", age:18, hobby:"吃饭,睡觉" },{ userName:"李四", sex:"男", age:22, hobby:"打牌,看电视" },{ userName:"王五", sex:"男", age:34, hobby:"吃饭,睡觉 ,打豆豆" },{ userName:"赵六", sex:"男", age:25, hobby:"玩游戏,写代码" } ]
现有上面这一个JavaScript对象,请根据这个对象,生成下面这个表格
第一种方法
//1. 先创建一个table元素
var table1 = document.createElement("table");
//1.1 给当前这个表格添加一个class样式
table1.classList.add("table1");
//2. 创建表格的标题
var trTitle = document.createElement("tr");
var titleArr = ["姓名", "性别", "年龄", "爱好"];
//2.1 循环遍历数组,创建th
for (var i = 0; i < titleArr.length; i++) {
var th = document.createElement("th");
th.innerText = titleArr[i];
trTitle.appendChild(th);
}
//2.2 将创建好的trTitle追加到table1上面去
table1.appendChild(trTitle);
//3.遍历students数组,取到里面的对象
students.forEach(function (item, index, _arr) {
//item代表的就是当前数组的每一个元素,这个元素是每个学生对象,我们要根据这个学生对象创建tr
//3.1 创建tr
var newtr = document.createElement("tr");
//3.2 遍历对象的属笥, 创建td
for (var i in item) {
var newtd = document.createElement("td");
newtd.innerText = item[i];
newtr.appendChild(newtd);
}
//3.3将创建的 tr追加到table1里面去
table1.appendChild(newtr);
});
//最后将tabl1追加到页面上面去
document.body.appendChild(table1);
第二种方法
//1. 先创建一个table元素
var table1 = document.createElement("table");
//1.1 给当前这个表格添加一个class样式
table1.classList.add("table1");
//2. 创建表格的标题行
var trTitle = document.createElement("tr");
var titleArr = ["姓名", "性别", "年龄", "爱好"];
trTitle.innerHTML = "<th>" + titleArr.join("</th><th>") + "</th>";
table1.appendChild(trTitle);
//3.遍历数组,创建内容
students.forEach(function (item, index, _arr) {
//item代表当前遍历出来的每一个对象
//3.1 创建tr
var newtr = document.createElement("tr");
//3.2 获取对象里面的属性值,去创建td
newtr.innerHTML = "<td>" + Object.values(item).join("</td><td>") + "</td>";
//3.3 将创建的tr追加到table1上面
table1.appendChild(newtr);
});
document.body.appendChild(table1);
评论区