JavaScript HTML DOM
一、DOM(文档对象模型Document Object Model)
文档对象模型 (DOM) 是HTML和XML文档的编程接口。它给文档(结构树)提供了一个结构化的表述并且定义了一种方式—程序可以对结构树进行访问,以改变文档的结构,样式和内容。
DOM 提供了一种表述形式将文档作为一个结构化的节点组以及包含属性和方法的对象。换言之,它在web 页面和脚本或编程语言之间建立连接。
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。HTML DOM 模型被构造为对象的树。
二、做什么
要改变页面的某个东西,JavaScript就需要获得对HTML文档中所有元素进行访问的入口。这个入口,连同对 HTML 元素进行添加、移动、改变或移除的方法和属性,都是通过DOM来获得的
- JavaScript 能够改变页面中的所有 HTML 元素
- JavaScript 能够改变页面中的所有 HTML 属性
- JavaScript 能够改变页面中的所有 CSS 样式
- JavaScript 能够对页面中的所有事件做出反应
三、首先需知
window对象、document对象、element对象
四、查询 HTML 元素
为了能够操作页面中的元素,首先要先获取到对应的元素:
- 通过 id 查找 HTML 元素(getElementById)
- 通过标签名查找 HTML 元素(getElementsByTagName)
- 通过类名查找 HTML 元素(getElementsByClassName)
- 通过name属性查找拥有name属性的HTML 元素(getElementsByName)
- 通过指定的CSS选择器查找匹配的HTML 元素节点(querySelector)
- 通过指定的CSS选择器查找所有匹配的HTML 元素节点(querySelectorAll)
(一)通过 id查找 – getElementById()
返回匹配指定ID属性的元素节点。若没有发现匹配的节点,则返回null。这是获取一个元素最快的方法
<body>
<div id="demo">通过ID查找</div>
<script>
var demo = document.getElementById("demo");
console.log(demo); //<div id="demo">通过ID查找</div>
</script>
</body>
(二)通过标签名查找 – getElementsByTagName()
返回带有指定标签名的对象的集合。所有指定标签的元素(搜索范围包括本身)。返回值是一个HTMLCollection对象,也就是说,搜索结果是一个动态集合,任何元素的变化都会实时反映在返回的集合中。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。
注:
- 把特殊字符串 “*” 作为参数传递,将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序。
- getElementsByTagName方法会将参数转为小写后,再进行搜索。
<body>
<section id="far">
<div class="demo">通过标签名查找</div>
<div class="demo">通过标签名1查找</div>
<div class="demo demo1">通过标签名2查找</div>
<p>vhjvk</p>
<p>bkjbkj</p>
</section>
<script>
var demo = document.getElementsByTagName("div");
var far = document.getElementById("far");
var demoAll = document.getElementsByTagName("*");
//在document对象上调用
console.log(demo); //HTMLCollection(3) [div.demo, div.demo, div.demo.demo1]
console.log(demoAll); //HTMLCollection(14) [html, head, meta, meta, meta, title, body, section#far, div.demo, div.demo, div.demo.demo1, p, p, script, viewport: meta, far: section#far]
//在元素节点上调用:
console.log(far.getElementsByTagName("p")); //HTMLCollection(2) [p, p]
</script>
</body>
(三)通过类名查找 – getElementsByClassName()
返回文档中所有指定类名的元素集合。一个类似数组的对象(HTMLCollection类型的对象),包括了所有class名字符合指定条件的元素(搜索范围包括本身),元素的变化实时反映在返回结果中。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。
注:
- 可用length 属性来确定指定类名的元素个数,并循环各个元素来获取需要的那个元素。
- 参数,可以是多个空格分隔的class名字,返回同时具有这些节点的元素。
- 元素在集合中的顺序以其在代码中的出现次序排序。
<body>
<div class="demo">通过类名查找</div>
<div class="demo">通过类名1查找</div>
<div class="demo demo1">通过类名2查找</div>
<script>
var demo = document.getElementsByClassName("demo");
var demo1 = document.getElementsByClassName("demo demo1");
console.log(demo); //HTMLCollection(3) [div.demo, div.demo, div.demo.demo1]
console.log(demo1); //HTMLCollection [div.demo.demo1]
</script>
</body>
(四)通过name属性查找 – getElementsByName()
用于选择拥有name属性的HTML元素,比如form、img、frame、embed和object,返回一个NodeList格式的对象,不会实时反映元素的变化。
<body>
<form action="" name="demo"></form>
<form action="" name="demo"></form>
<script>
var demo = document.getElementsByName("demo");
console.log(demo); //NodeList(2) [form, form]
</script>
</body>
(五)通过匹配选择器查找
1、querySelector()
返回匹配指定的CSS选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null。
注:
- querySelector方法无法选中CSS伪元素。
<body>
<form action="" name="demo">1</form>
<form action="" name="demo" class="demo" id="demo1">2</form>
<script>
var demo = document.querySelector("form");//标签选择器
var demo1 = document.querySelector("[name]");//属性选择器
var demo2 = document.querySelector(".demo");//类名选择器
var demo3 = document.querySelector("#demo1");//ID选择器
// ……等等……
console.log(demo); //<form action="" name="demo">1</form>
console.log(demo1); //<form action="" name="demo">1</form>
console.log(demo2); //<form action="" name="demo" class="demo" id="demo1">2</form>
console.log(demo3); //<form action="" name="demo" class="demo" id="demo1">2</form>
</script>
</body>
2、querySelectorAll()
返回匹配指定的CSS选择器的所有节点,返回的是NodeList类型的对象。NodeList对象不是动态集合,所以元素节点的变化无法实时反映在返回结果中。
注:
- 参数,可以是逗号分隔的多个CSS选择器,返回所有匹配其中一个选择器的元素。
<body>
<form action="" name="demo">1</form>
<form action="" name="demo1" class="demo" id="demo1">2</form>
<script>
var demo = document.querySelectorAll("form");//标签选择器
var demo1 = document.querySelectorAll("[name]");//属性选择器
var demo2 = document.querySelectorAll(".demo");//类名选择器
var demo3 = document.querySelectorAll("#demo1");//ID选择器
var demo4 = document.querySelectorAll(".demo,[name=demo]");//逗号分隔多个选择器
// ……等等……
console.log(demo); //NodeList(2) [form, form#demo1.demo]
console.log(demo1); //NodeList(2) [form, form#demo1.demo]
console.log(demo2); //NodeList [form#demo1.demo]
console.log(demo3); //NodeList [form#demo1.demo]
console.log(demo4); //NodeList(2) [form, form#demo1.demo]
</script>
</body>
五、创建元素
(一)元素节点。
createElement():用来生成HTML元素节点。
参数:
- 元素的标签名,即元素节点的tagName属性。
- 如果传入大写的标签名,会被转为小写被解析。
- 如果参数带有尖括号(即<和>)或者是null,会报错。
<script>
var demo = document.createElement("div");
console.log(demo);//<div></div>
</script>
(二)文本节点
createTextNode():用来生成文本节点
参数: 是所要生成的文本节点的内容。
<script>
var demo = document.createElement("div");//创建一个div节点
var demoContent = document.createTextNode("Hello");//创建一个文本节点
console.log(demo);//<div></div>
console.log(demoContent);//"Hello"
</script>
(三)DocumentFragment对象。
createDocumentFragment():生成一个DocumentFragment对象。
DocumentFragment对象是一个存在于内存的DOM片段,但是不属于当前文档,常常用来生成较复杂的DOM结构,然后插入当前文档。这样做的好处在于,因为DocumentFragment不属于当前文档,对它的任何改动,都不会引发网页的重新渲染,比直接修改当前文档的DOM有更好的性能表现。
六、操作元素
(一)添加元素
1. 在末尾添加
appendChild():向元素(节点)的子元素(子节点)列表的末尾添加新的子元素(子节点)
<script>
var newDiv = document.createElement("div");
console.log(document.createElement("div"));
console.log(newDiv);
var newContent = document.createTextNode("Hello");
console.log(newContent);
newDiv.appendChild(newContent);
console.log(newDiv);
</script>
注:
- 如果文档树中已经存在了 要添加的节点(newchild),那么它将被删除,然后重新插入它的新位置。
- 如果 newchild 是 DocumentFragment 节点,则不会直接插入它,而是把它的子节点按序插入当前节点的 childNodes[] 数组的末尾。
<body>
<p>元素</p>
<div></div>
<script>
var box = document.querySelector("div");
var pBox = document.querySelector("p");
box.appendChild(pBox);
console.log(box);
</script>
</body>
appendChild操作前:
appendChild操作后:
2. 在××之前添加
insertBefore():在已有的子节点前插入一个新的子节点。在某个元素之前插入元素
语法结构:node.insertBefore(newnode,existingnode)
参数 | 描述 |
---|---|
newnode | 必填,要插入的节点对象 |
existingnode | 必填,要添加新节点的子节点。 |
<script>
var newDiv = document.createElement("div");
console.log(document.createElement("div"));
console.log(newDiv);
var newContent = document.createTextNode("Hello");
console.log(newContent);
console.log(newDiv.firstChild);
newDiv.insertBefore(newContent,newDiv.firstChild);
console.log(newDiv);
</script>
<body>
<p>元素</p>
<div>
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector("div");
var pBox = document.querySelector("p");
box.insertBefore(pBox,box.firstChild);
</script>
</body>
注:
- 如果文档树中已经存在了 要添加的节点(newchild),那么它将被删除,然后重新插入它的新位置。
- 如果 newchild 是 DocumentFragment 节点,则不会直接插入它,而是把它的子节点按序插入当前节点的 childNodes[] 数组的末尾。
insertBefore()操作前:
insertBefore()操作后:
(二)替换元素
replaceChild():将某个元素的子节点替换为另一个
注:新节点可以是文本中已存在的,或者是你新创建的。
语法结构:replaceChild(newnode,oldnode)
e.g.
a.replaceChild(newnode,a.lastChild)
参数 | 描述 |
---|---|
newnode | 必填,要插入的节点对象。 |
oldnode | 必填,要移除的节点对象。 |
<body>
<p>元素</p>
<div class="far">
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector(".far");
var pBox = document.querySelector("p");
console.log(box.lastChild);
box.replaceChild(pBox,box.lastChild);
console.log(box);
console.log(box.lastChild);
</script>
</body>
(二)删除元素
removeChild(): 从子节点列表中删除某个节点。
返回被删除的节点,删除失败,则返回 NULL。
<body>
<p>元素</p>
<div class="far">
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector(".far");
var pBox = document.querySelector("p");
console.log(box.lastChild);
box.removeChild(box.lastChild);
box.removeChild(box.lastChild);
console.log(box);
console.log(box.lastChild);
</script>
</body>
(三)clone克隆元素
clone(): 拷贝一个列表项到另外一个列表。复制并返回调用它的节点的副本。
- 可创建指定的节点的精确拷贝。
- 拷贝所有属性和值。
- 若参数是 true,将递归复制当前节点的所有子孙节点。否则,它只复制当前节点。
<body>
<p>元素</p>
<div class="far">
<div></div>
<div></div>
</div>
<div id="farTwo">
</div>
<script>
var box = document.querySelector(".far"); //获取far元素
var pBox = document.querySelector("p"); //获取p元素
box.replaceChild(pBox,box.lastChild); //替换box(far元素)中的最后一个节点(#text)为pBox(p元素)
var boxChild = box.lastChild.cloneNode(true); //克隆box的最后一个子节点中的所有子孙节点
document.getElementById("farTwo").appendChild(boxChild); //获取farTwo元素,并将克隆的副本添加到farTwo的最后一个子节点
</script>
</body>
七、操作属性
(一)获取属性值
getAttribute() :通过名称获取属性的值。返回字符串string。
注: 若无设置此属性,则返回null。
<body>
<div class="far"></div>
<script>
var box = document.querySelector(".far"); //获取far元素
console.log(box.getAttribute("id")); //null
console.log(box.getAttribute("class")); //far
</script>
(二)创建属性
createAttribute(name) :用于创建一个指定名称的属性,并返回Attr 对象属性。参数name,是属性的名称。
<body>
<div class="far">
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector(".far"); //获取far元素
var boxId = document.createAttribute("id"); //创建属性id
console.log(document.createAttribute("id")); //id=""
boxId.value = "far"; //设置id值
box.setAttributeNode(boxId); //将id属性添加到 box 元素中
</script>
</body>
创建前:
创建后:
注:
createAttribute(),与setAttributeNode()一起使用的,与createTextNode(),createElement() 类似:
同: 先独立的创建文本节点、属性节点或元素节点。然后再追加到已有的文档节点后面;
异: 追加文本节点和元素节点使用appendChild()方法;追加属性节点使用setAttributeNode()方法。
直接使用setAttribute()要方便的多。
(三)设置属性
setAttribute() :创建或设置某个新属性。
setAttribute(attributename,attributevalue)
参数 | 描述 |
---|---|
attributename | string,必填。属性名称 |
attributevalue | string,必填。属性值 |
<body>
<div class="far">
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector(".far"); //获取far元素
box.setAttribute("id","far");//将id属性添加到 box 元素中,并赋值
//下3行代码 = 上1句代码
var boxId = document.createAttribute("id"); //创建属性id
boxId.value = "far"; //设置id值
box.setAttributeNode(boxId); //将id属性添加到 box 元素中
</script>
</body>
创建前:
创建后:
(四)删除属性
romoveAttribute() :
<body>
<div class="far">
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector(".far"); //获取far元素
box.setAttribute("id","far"); //添加属性及设置值
box.removeAttribute("id"); //删除属性
</script>
</body>
添加前:
添加后:
删除后:
(五)属性集合
attributes:返回指定节点属性的集合。
<body>
<div class="far">
<div></div>
<div></div>
</div>
<script>
var box = document.querySelector(".far"); //获取far元素
box.setAttribute("id","far");
console.log(box.attributes); //NamedNodeMap {0: class, 1: id, class: class, id: id, length: 2}
</script>
</body>
八、常见使用
(一)修改样式
可修改指定元素的 style 属性,直接渲染在页面中
<body>
<p>元素</p>
<div class="far"></div>
<script>
var box = document.querySelector(".far"); //获取far元素
var pBox = document.querySelector("p"); //获取p元素
pBox.style.color = 'red';
box.style.width = '200px';
box.style.height = '200px';
box.style.backgroundColor = '#ccc';
</script>
</body>
修改前 :【因为box元素没有设置宽高,所以页面里看不见】
修改后 :
(二)获取样式
getComputedStyle :用于获取指定元素的 CSS 样式。
注:
- 此方法是window对象的一个方法;
- 获取的样式是元素在浏览器中最终渲染效果的样式。
<body>
<p>元素</p>
<script>
var pBox = document.querySelector("p"); //获取p元素
pBox.style.color = 'red';
var color = window.getComputedStyle(pBox).color;
console.log(color); //rgb(255, 0, 0)
</script>
</body>
(三)类名(class)的操作
样式的改变尽量使用 class 的新增删除来实现
<body>
<div class="far"></div>
<script>
var box = document.querySelector(".far"); //获取far元素
console.log( box.classList ); //DOMTokenList ["far", value: "far"]
box.classList.add('active'); //新增 class
box.classList.remove('active'); //删除 class
box.classList.add('active'); //新增 class
box.classList.toggle('active'); //新增/删除切换(有则删,无则增)
console.log(box.classList.contains('active')); // false;判断是否拥有 class
</script>
</body>
(四)window尺寸【页面的宽高】
<body>
<!-- css部分 -->
<style>
*{
margin: 0;
padding: 0;
}
body{
height: 2000px;
width: 100%;
}
.pFar {
height: 360px;
width: 360px;
}
</style>
<!-- html部分 -->
<p class="pBox">元素</p>
<div class="far">
<p class="pFar"></p>
</div>
<!-- js部分 -->
<script>
var box = document.querySelector(".far"); //获取far元素
var pBox = document.querySelector(".pBox"); //获取最外层p元素
pBox.style.color = 'red';
box.style.width = '200px';
box.style.height = '200px';
box.style.overflowY = 'auto';
box.style.overflowX = 'auto';
box.style.backgroundColor = '#ccc';
box.style.border = '10px solid red';
box.onscroll = function () {
console.log(box.clientHeight); //200
console.log(box.clientWidth); //183
console.log(box.offsetHeight); //220
console.log(box.offsetWidth); //220
console.log(box.scrollHeight); //200
console.log(box.scrollTop); //0
console.log(box.scrollLeft); //0
console.log(innerHeight); //0
console.log(outerHeight); //0
console.log("==============="); //0
}
</script>
</body>
1. 元素内部宽高【clientHeight 、clientWidth】W3C盒模型
(1)clientHeight : 是元素内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距。
(2)clientWidth:表示元素的内部宽度,以像素计。该属性包括内边距,但不包括垂直滚动条(如果有)、边框和外边距。
注 :该属性值会被四舍五入为一个整数。如果你需要一个小数值,可使用 element.getBoundingClientRect()。
2. 元素整体宽高【offsetHeight 、offsetWidth】IE盒模型
(1)offsetHeight :返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。
(2)offsetWidth :返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。
注 :不包含:before或:after等伪类元素的高度。
3. 元素滚动的宽高
(1)scrollHeight :该元素滚动内容的总长度。包括由于溢出导致的视图中不可见内容。也包括 ::before 和 ::after这样的伪元素。如果元素没出现滚动条, 则scrollHeight等于 clientHeight
(2)scrollTop :滚动的高度。可以获取或设置一个元素的内容垂直滚动的像素数。
一个元素的 scrollTop 值是这个元素的顶部到可见内容的顶部的距离。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0。
设置scrollTop值:
- 设置scrollTop < 0,scrollTop 被设为0
- 设置scrollTop > 这个容器可滚动的值, scrollTop 会被设为最大值.
- 如果一个元素不能被滚动(e.g.没有溢出,或者这个元素有一个"non-scrollable"属性), scrollTop则为0。
(3)scrollLeft:可以读取或设置元素滚动条到元素左边的距离。
设置scrollLeft值:
- 如果元素不能滚动(比如:元素没有溢出),那么scrollLeft 的值是0。
- 若scrollLeft < 0,则 scrollLeft值 为0。
- 若scrollLeft > 元素内容最大宽度,则scrollLeft 的值将被设为元素最大宽度。
4. 窗口的宽高【innerHeight、innerWidth】
(1)innerHeight:窗口的文档显示区的高度,如果存在水平滚动条,则包括它。
(2)innerWidth:窗口的文档显示区的宽度,如果存在垂直滚动条,则包括它。
注:不包括菜单栏、工具栏以及滚动条等的高度。
5. 浏览器整体的宽高【outerHeight、outerWidth】
(1)outerHeight:整个窗口的高度。
(2)outerWidth:整个窗口的宽度。
6. 获取元素在视图中的位置【getBoundingClientRect()】
getBoundingClientRect():方法返回元素的大小及其相对于视口的位置。
注:left是指元素右边到页面最左边的距离,bottom是指元素底边到页面顶边的距离。
<body>
<!--css部分-->
<style>
*{
margin: 0;
padding: 0;
}
</style>
<p class="pBox">元素</p>
<div class="far"></div>
<script>
var box = document.querySelector(".far"); //获取far元素
box.style.width = '200px';
box.style.height = '200px';
box.style.overflowY = 'auto';
box.style.overflowX = 'auto';
box.style.backgroundColor = '#ccc';
box.style.border = '10px solid red';
console.log(box.getBoundingClientRect()); //0
</script>
</body>
7. 制作滚动代码的常用属性
页可见区域宽: document.body.clientWidth;
网页可见区域高: document.body.clientHeight;
window.innerHeight;
网页可见区域宽: document.body.offsetWidth (包括边线的宽);
网页可见区域高: document.body.offsetHeight (包括边线的宽);
网页正文全文宽: document.body.scrollWidth;
网页正文全文高: document.body.scrollHeight;
网页被卷去的高: document.body.scrollTop;
网页被卷去的左: document.body.scrollLeft;
网页正文部分上: window.screenTop;
网页正文部分左: window.screenLeft;
屏幕分辨率的高: window.screen.height;
屏幕分辨率的宽: window.screen.width;
屏幕可用工作区高度: window.screen.availHeight;
图示(很棒,借用):