javascript 的组成部分
- - DOM (document object model) 文档对象模型
- - BOM (browers object model) 浏览器对象模型
- - ECMAScript js 的核心
DOM树:
1.DOM 节点
1.1节点分类
- - 元素节点:每个 HTML元素
- - 属性节点:HTML元素的属性
- - 文本节点:HTML元素内的文本 。换行在,文档解析时会解析成空白符,所以属于文本节点
- - 注释节点:注释 <!---->
- - 文档节点:整个文档document
<body>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
{
let list = document.querySelector("#list");
//发现li之前和li之间的换行,都是一个文本节点
// console.log(list.childNodes);//NodeList(11) [text, li, text, li, text, li, text, li, text, li, text]
//发现document下有两个子节点,文档声明也是一个子节点
console.log(document.childNodes);//NodeList(2) [html, html]
}
</script>
</body>
1.2常用节点类型 --- nodeType
- - 元素节点:1
- - 属性节点:2
- - 文本节点:3
- - 注释节点:8
- - 文档节点:9
- -文档声明节点:10
1.3节点名称 --- nodeName
- - 元素节点:标签名大写
- - 文本节点:为#text
- - 注释节点:为#comment
- - 文档节点:为#document
- 文档声明节点:为 html
<body>
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>
<span>span1</span>
<span>span2</span>
</li>
<!-- 这是一条注释 -->
<li>5</li>
</ul>
<script>
{
let list = document.querySelector("#list");
console.log(document.nodeType,document.nodeName);//9 文档节点 "#document"
//发现:document根节点下有两个节点,1 元素节点,节点名称元素标签名大写;10 文档声明节点 节点名称 HTML
document.childNodes.forEach(item=>{
console.log(item.nodeType,item.nodeName);
});
//3 文本节点 #text;8 注释节点 #comment
list.childNodes.forEach(item=>{
console.log(item.nodeType,item.nodeName);
});
}
</script>
</body>
2.DOM关系
父子级关系;兄弟级关系
2.1查找子级:
getElementsByTagName/ByClassName,quarySelector/quarySelectorAll()等方法都是查找子级,但会把子级和孙子级也查找出来
- - childNodes 子节点:包括所有节点(文本节点、注释节点、元素节点......)。返回类型为NodeList
<div id="wrap">
<p>p1</p>
<p>p2</p>
<!-- 注释 -->
<h3>h2</h3>
<p>p3</p>
<p>p4</p>
<h3>h2</h3>
<p>p5</p>
<h3>h2</h3>
<p>p6</p>
</div>
<script>
{
let wrap = document.querySelector("#wrap");
//childNodes获取到所有子节点(包括所有子节点:包括文本节点、元素节点、注释节点...)
console.log(wrap.childNodes);//NodeList(21) [text, p, text, p, text, comment, text, h3, text, p, text, p, text, h3, text, p, text, h3, text, p, text]
//要使用childNodes获取到所有子级元素节点(使用过滤方法,当nodeType == 1时返回)
let childrens = wrap.childNodes;
childrens = [...childrens].filter(item => item.nodeType == 1 );
console.log(childrens);//(9) [p, p, h3, p, p, h3, p, h3, p]成功过滤出所有的元素节点
}
</script>
</body>
- - children 子元素:只包含元素节点。返回类型为HTMLCollection
let wrap = document.querySelector("#wrap");
//children获取到所有元素
console.log(wrap.children);//HTMLCollection(9) [p, p, h3, p, p, h3, p, h3, p]
- - firstChild 第0个子节点
- - firstElementChild 第0个子元素
- - lastChild 最后一个子节点
- - lastElementChild 最后一个子元素
let wrap = document.querySelector("#wrap");
console.log(wrap.firstChild,wrap.firstElementChild);//#text <p>p1</p>
console.log(wrap.lastChild,wrap.lastElementChild);//#text <p>p6</p>
2.2查找兄弟级:
- - nextSibling 下一个兄弟节点
- - nextElementSibling 下一个兄弟元素
- - previousSibling 上一个兄弟节点
- - previousElementSibling 上一个兄弟元素
let wrap = document.querySelector("#wrap");
let h2 = wrap.children[2];
console.log(h2);//<h3>h2</h3>
console.log(h2.nextSibling,h2.nextElementSibling);//#text h3前换行 <p>p3</p>
console.log(h2.previousSibling,h2.previousElementSibling);//#text p3前换行 <p>p2</p>
2.3查找父级:
- - parentNode 父节点 ,获取父节点和父元素没有任何区别,因为本身只有元素才可以有子级,所以父级一点会是一个元素
- - parentElement 父元素
- - offsetParent 定位父级。元素根据定位的父级进行获取,如果有定位父级就是定位父级,没有定位父级,就是该元素的父级
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
position: relative;
}
span {
position: absolute;
display: block;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div id="box">
<div id="box2">
<span></span>
</div>
</div>
<script>
{
/*
- parentNode 父节点 ,获取父节点和父元素没有任何区别,因为本身只有元素才可以有子级,所以父级一点会是一个元素
- parentElement 父元素
- offsetParent 定位父级。元素根据定位的父级进行获取,如果有定位父级就是定位父级,没有定位父级,就是该元素的父级
*/
let span = document.querySelector("span");
console.log(span.parentElement,span.parentNode);//都是box2
//定位父级
console.log(span.offsetParent);//因为span的定位父级是box,所以offsetParent获取到的父级是box;如果没有设置,其父级就是box2
}
</script>
</body>
</html>
2.4NodeList 和 HTMLCollection的区别:
获取元素得到值为NodeList:
- childNodes
- querySelectorAll()
获取元素得到值为HTMLCollection:
- children;
- getElementsByTagName
- getElementsByClassName
- NodeList可以使用forEach方法,但是HTMLCollection不能使用forEach方法;
- HTMLCollection每次调用都会进行动态获取;虽然NodeList的childNodes可以进行动态获取,但NodeList的querySelectorAll不能进行动态获取,需要手动进行更新;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="box">
<p class="pAll"></p>
<p class="pAll"></p>
<p class="pAll"></p>
</div>
<script>
{
let box = document.querySelector("#box");
let childNode = box.childNodes;
console.log(childNode);//NodeList(7) [text, p.pAll, text, p.pAll, text, p.pAll, text]
let qsAll = box.querySelectorAll("p");
console.log(qsAll);//NodeList(3) [p.pAll, p.pAll, p.pAll]
let eBClass = box.getElementsByClassName("pAll");
console.log(eBClass);//HTMLCollection(3) [p.pAll, p.pAll, p.pAll]
let eBTagName = box.getElementsByTagName("p");
console.log(eBTagName);//HTMLCollection(3) [p.pAll, p.pAll, p.pAll]
let childs = box.children;
console.log("动态获取-----------------");
//所有HTMLCollection的都可以进行动态获取
box.innerHTML = '';
console.log(qsAll);// querySelectorAll里面的P标签并没有被清空NodeList(3) [p.pAll, p.pAll, p.pAll]
//只有重新进行querySelectorAll手动获取才能动态更新
console.log(box.querySelectorAll("p"));//手动获取后得到的是被清空后的内容NodeList []
//childNodes、getElementsByClassName、getElementsByTagName都会进行自动动态获取
console.log(childNode);//NodeList []
console.log(eBClass);//HTMLCollection []
console.log(eBTagName);//HTMLCollection []
}
</script>
</body>
</html>
3.DOM 属性操作
注意 . 和 [] 都是 ECMAScript 中,对象的属性操作,对象属性的值会被存在内存中, 想要直接获取存在 文档中属性,或者 想把一个属性设置在文档中我们需要使用DOM 的属性操作
合法属性:w3c规定的元素的属性,都存到这个对象中。
通过 ECMAScript的属性操作都是存在内存中,而通过DOM属性操作,属性及值存在DOM文档中
使用ECMAScript的属性操作 . 和 [] 获取或设置w3c规定之外的非合法属性,会返回undefined。
- - el.attributes 元素所有属性名的集合(不包括属性值)
- - el.getAttribute("attr") 获取属性
- - el.setAttribute("attr","val") 设置属性
- - el.removeAttribute("attr") 移出属性
- - el.hasAttribute("attr") 判断是否有这个属性
- - 只要操作了innerHTML 元素的所有子元素上,存在内存中的事件和相关的属性都会丢失。如果希望元素的某些属性在操作了父级的innerHTML 之后,还存在就把这个属性加在 DOM 中
3.1 . 和 [] 都是 ECMAScript的属性操作:
<body>
<div id="box" class="box" kkb="DOM"></div>
<script>
{
//. 和 [] 都是 ECMAScript的属性操作,通过 ECMAScript的属性操作都是存在内存中,而通过DOM属性操作,属性及值存在DOM文档中
//直接通过. 和 [] 获取到的是存在内存中的属性及值
let box = document.querySelector("div");
console.log(box.id);//box
console.log(box.className);//获取class的值时,为避免冲突,必须使用className
//使用ECMAScript的属性操作 . 和 [] 获取或设置w3c规定之外的非合法属性,会返回undefined
console.log(box.kkb);//undefined
}
</script>
</body>
3.2 DOM的属性操作:
- - el.attributes 元素所有属性名的集合(不包括属性值)
- - el.getAttribute("attr") 获取属性。attr必须和文档中属性名一致,获取不到就返回null
- - el.setAttribute("attr","val") 设置属性
- - el.removeAttribute("attr") 移出属性
- - el.hasAttribute("attr") 判断是否有这个属性。返回布尔值
- - 只要操作了innerHTML 元素的所有子元素上,存在内存中的事件和相关的属性都会丢失。如果希望元素的某些属性在操作了父级的innerHTML 之后,还存在就把这个属性加在 DOM 中
<body>
<div id="box" class="box" kkb="DOM"></div>
<script>
{
/*
- el.attributes 元素所有属性名的集合(不包括属性值)
- el.getAttribute("attr") 获取属性
- el.setAttribute("attr","val") 设置属性
- el.removeAttribute("attr") 移出属性
- el.hasAttribute("attr") 判断是否有这个属性
*/
let box = document.querySelector("div");
//el.attributes元素所有属性的集合
console.log(box.attributes);//NamedNodeMap {0: id, 1: class, 2: kkb, id: id, class: class, kkb: kkb, length: 3}
//el.getAttribute("attr") 获取属性
console.log(box.getAttribute("class"));//box
//也可以获取非w3c的属性
console.log(box.getAttribute("kkb"));//DOM
//el.setAttribute("attr","val") 设置属性
box.setAttribute("miaov","kaikeba");
console.log(box.attributes);//NamedNodeMap {0: id, 1: class, 2: kkb, 3: miaov, id: id, class: class, kkb: kkb, miaov: miaov, length: 4}
// el.removeAttribute("attr") 移出属性
box.removeAttribute("kkb");
console.log(box.attributes);//NamedNodeMap {0: id, 1: class, 2: miaov, id: id, class: class, miaov: miaov, length: 3}
//el.hasAttribute("attr") 判断是否有这个属性 返回布尔值
console.log(box.hasAttribute("kkb"));//false
}
</script>
</body>
3.3 DOM属性操作和ECMAScript属性操作区别:
- ECMAScript属性操作,操作的是元素获取后编译成的对象,具体的数据存在内存中;DOM属性操作,值是存在文档中。
- ECMAScript属性操作,内存中可以存任何类型的数据;DOM中只能存字符串类型的数据,不是字符串也会转成字符串
- 通过ECMAScript属性操作设置的属性,再通过DOM属性操作获取时,会返回null(因为通过ECMAScript属性操作设置的属性是存在内存中的,在DOM文档里面获取不到)
- 通过DOM属性操作设置的非法属性,再通过ECMAScript属性操作获取时,会返回undefined(因为通过DOM属性设置的值并没有保存在内存中)
-
只要操作了innerHTML 元素的所有子元素上,存在内存中的事件和相关的属性都会丢失。如果希望元素的某些属性在操作了父级的innerHTML 之后,还存在就把这个属性加在 DOM 中
<body>
<div id="box" class="box">
<div></div>
</div>
<script>
{
let box = document.querySelector("#box");
//ECMAScript属性操作,操作的是元素获取后编译成的对象,具体的数据存在内存中。内存中可以存任何类型的数据
box.index = 0;
//DOM属性操作,值是存在文档中。DOM中只能存字符串类型的数据,不是字符串也会转成字符串
box.setAttribute("kkb","kaikeba");
box.setAttribute("miao",1);
console.log(typeof box.getAttribute("miao"));//string
//通过ECMAScript属性操作设置的属性,再通过DOM属性操作获取时,会返回null(因为通过ECMAScript属性操作设置的属性是存在内存中的,在DOM文档里面获取不到)
console.log(box.getAttribute("index"));//null
//通过DOM属性操作设置的非法属性,再通过ECMAScript属性操作获取时,会返回undefined(因为通过DOM属性设置的值并没有保存在内存中)
console.log(box.kkb);//undefined
//只要操作了innerHTML 元素的所有子元素上,存在内存中的事件和相关的属性都会丢失。如果希望元素的某些属性在操作了父级的innerHTML 之后,还存在就把这个属性加在 DOM 中
let childBox = box.children[0];
childBox.index = 1;
childBox.setAttribute("kkb","kaikeba");
//注意此处是操作父级的innerHTML 之后才会有问题
box.innerHTML = box.innerHTML;
console.log(box.children[0].index);//undefined
console.log(box.children[0].getAttribute("kkb"));//kaikeba
}
</script>
</body>
4.data 自定义属性
- 在标签中定义data自定义属性:data-key="value";
-data自定义属性本身是将属性存在DOM文档中,所以只能是字符串类型,不是也会转为字符串类型
- 在js操作该元素的 data 自定义属性:el.dataset
- - 获取:el.dataset.key
- - 设置: el.dataset.key = "value"
<body>
<div id="box" class="box" data-kkb="kaikeba">
<div></div>
</div>
<script>
{
let box = document.querySelector("#box");
console.log(box.dataset.kkb);//kaikeba
box.dataset.kkb = "miaov";
console.log(box.dataset.kkb);//miaov
}
</script>
</body>
5.节点操作
5.1创建节点
- 语法:element document.createElement("tagName"); 创建一个节点
- 参数:tagName 标签名称
- 返回值:创建好的节点
createElement()可以创建任何类型的标签,甚至可以是w3c中没有的,但是建议每次都创建合法标签。
注意:element document.createElement("tagName");方法创建好节点后不会直接渲染到页面,还需要调用添加节点方法,才能真正渲染到页面。
<body>
<div id="box">
</div>
<script>
{
//elment document.createElement("tagName");创建元素
let box = document.querySelector("#box");
let h1 = document.createElement("h1");
h1.innerHTML = "标题";
console.log(h1);//<h1>标题</h1>
}
</script>
</body>
5.2向页面中添加节点
- el.appendChild(node) 在元素的末尾添加一个子级
- el.insertBefore(newNode,oldNode) 在 oldNode 前边添加入 newNode。第二个参数oldNode是必须的,如果第一个参数不存在,等同于appendChild()操作会在末尾添加一个子级
- 在使用 appendChild 和 insertBefore时,如果添加是一个页面上已经存在的节点,会先从原位置删除,然后在添加到新的位置去。
<body>
<div id="box">
<p>这是一个p标签</p>
</div>
<script>
{
let box = document.querySelector("#box");
let p = document.querySelector("p");
let h1 = document.createElement("h1");
h1.innerHTML = "标题";
// box.appendChild(h1); //在末尾添加元素
box.insertBefore(h1,p); //在某节点之前添加一个节点
}
</script>
</body>
结果:
添加已有节点时:如果添加是一个页面上已经存在的节点,会先从原位置删除,然后在添加到新的位置去。
<body>
<div id="box">
<div id="div1"></div>
</div>
<div id="box2"></div>
<script>
{
let box = document.querySelector("#box");
let div1 = box.querySelector("#div1");
let box2 = document.querySelector("#box2");
box2.appendChild(div1);
}
</script>
</body>
使用insertBefore(newNode,oldNode) :
<body>
<div id="box">
<div id="div1"></div>
</div>
<div id="box2">
<h1></h1>
</div>
<script>
{
let box = document.querySelector("#box");
let div1 = box.querySelector("#div1");
let box2 = document.querySelector("#box2");
let h1 = document.querySelector("h1");
// box2.appendChild(div1);
box2.insertBefore(div1,h1);
}
</script>
</body>
5.3 替换节点
- parent.replaceChild(newNode,oldNode) 将oldNode替换成newNode。两个节点需在同一个parent下
使用已存在的节点进行替换,会先从原位置删除,然后在添加到新的位置去。
<body>
<div id="box">
<div id="div1"></div>
</div>
<script>
{
let box = document.querySelector("#box");
let div1 = box.querySelector("#div1");
let h1 = document.createElement("h1");
box.replaceChild(h1,div1);
}
</script>
</body>
5.4删除节点
- parent.removeChild(el) 删除掉某个子元素。返回值为删除的节点。建议使用
-parent.remove()删除子元素。新方法兼容性不是很好。返回值undefined
<body>
<div id="box">
<div id="div1"></div>
<h1>标题</h1>
</div>
<script>
{
let box = document.querySelector("#box");
let div1 = box.querySelector("#div1");
let h1 = box.querySelector("h1");
console.log(box.remove(h1));
console.log(box.removeChild(div1));
}
</script>
</body>
5.5克隆节点
- node.cloneNode(deep)
- - deep: 默认为false
- - deep 为 true, 克隆元素及属性,以及元素的内容和后代
- - deep 为 false, 只克隆元素本身,及它的属性
克隆节点,只会克隆元素内容,不会克隆元素上的事件。
<style>
#box {
width: 100px;
height: 100px;
border: 1px solid red;
}
</style>
</head>
<body>
<div id="box">
<div id="div1"></div>
<h1>标题</h1>
</div>
<script>
{
let box = document.querySelector("#box");
let box2 = box.cloneNode();
console.log(box2);//<div id="box"></div>
let box3 = box.cloneNode(true);
console.log(box3);//<div id="box"><div id="div1"></div><h1>标题</h1></div>
box.appendChild(box3);
}
</script>
</body>
6.文档碎片document.createDocumentFragment()
使用循环添加innerHTML时不建议直接添加,而是将所有元素累加到字符串中,最后循环完后再一次性添加:
6.1使用字符串累加:
直接添加1000个div时,用时:1311.780029296875ms
<style>
#box div{
width: 100px;
height: 100px;
border: 1px solid black;
background: red;
float: left;
margin: 10px;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
{
let box = document.querySelector("#box");
//使用循环添加innerHTML时不建议直接添加,而是将所有元素累加到字符串中,最后循环完后再一次性添加
// let inner = '';
console.time();
for (let i = 0; i < 1000; i++) {
box.innerHTML += '<div id="box">'+i+'</div>';
}
console.timeEnd();//发现总用时:default: 1311.780029296875ms
}
</script>
</body>
使用先存进字符串,再一次性添加时:default: 9.087890625ms,性能大大提高
console.time();
let inner = '';
for (let i = 0; i < 1000; i++) {
inner += '<div id="box">'+i+'</div>';
}
box.innerHTML = inner;
console.timeEnd();//发现总用时:default: 9.087890625ms
6.2使用文档碎片document.createDocumentFragment():
普通创建:
//直接添加节点
console.time();
for (let i = 0; i < 1000; i++) {
let div = document.createElement("div");
div.innerHTML = i;
box.appendChild(div);
}
console.timeEnd();//发现总用时:default: 15.39208984375ms
使用文档碎片:
console.time();
let fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
let div = document.createElement("div");
div.innerHTML = i;
fragment.appendChild(div);
}
box.appendChild(fragment);
console.timeEnd();//发现总用时:default: 8.47119140625ms
7.元素的尺寸获取
7.1offset
- - offsetWidth 可视宽度
- - offsetHeight 可视高度
- - offsetLeft 距离定位父级的left坐标
- - offsetTop 距离定位父级的top坐标
元素offsetWidth/offsetHeight可视宽高 = 元素width/height + border + padding
元素offsetTop/offsetLeft:元素距离定位父级的top/left位置 = 元素top/left + margin
<style>
#box {
position: relative;
width: 400px;
height: 400px;
margin: 100px 0 0 700px;
border: 1px solid black;
}
#box div{
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
border: 4px solid black;
padding: 40px;
background: red;
margin: 10px;
}
</style>
</head>
<body>
<div id="box">
<div></div>
</div>
<script>
{
let box = document.querySelector("#box");
let div = box.querySelector("div");
//元素offsetWidth/offsetHeight可视宽高 = 元素width/height + border + padding
console.log(div.offsetWidth,div.offsetHeight);//188 188
//元素offsetTop/offsetLeft:元素距离定位父级左上角的位置 = 元素top/left + margin
console.log(div.offsetTop,div.offsetLeft);//60 60
}
</script>
</body>
7.2client
- - clientWidth = 可视宽度 - border
- - clientHeight = 可视高度 - border
- - clientTop 上边框宽度
- - clientLeft 左边框宽度
<style>
#box {
position: relative;
width: 400px;
height: 400px;
margin: 100px 0 0 700px;
border: 1px solid black;
}
#box div{
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
border: 4px solid black;
padding: 40px;
background: red;
margin: 10px;
}
</style>
</head>
<body>
<div id="box">
<div></div>
</div>
<script>
{
/*
- clientWidth = 可视宽度 - border
- clientHeight = 可视高度 - border
- clientTop 上边框宽度
- clientLeft 左边框宽度
*/
let box = document.querySelector("#box");
let div = box.querySelector("div");
//元素clientWidth/clientHeight = 元素width/height+ padding
console.log(div.clientWidth,div.clientHeight);//180 180
//元素clientTop/clientLeft:元素上边框宽度/元素左边框宽度
console.log(div.clientTop,div.clientLeft);//4 4
}
</script>
</body>
</html>
7.3scroll
- - scrollWidth 内容宽度
- - scrollHeight 内容高度
- - scrollLeft 左右滚动距离
- - scrollTop 上下滚动距离
- scrollHeight:如果内容高度 > 元素高度,scrollHeight就为内容高度,否则scrollHeight就为元素高度;有滚动条会去除滚动条高度
- scrollWidth:如果内容宽度 > 元素宽度,scrollWidth就为内容宽度,否则scrollWidth就为元素宽度;有滚动条会去除滚动条宽度
- 元素scrollTop/scrollLeft:上下滚动条位置/左右滚动条位置
<style>
#box {
position: relative;
width: 400px;
height: 400px;
margin: 100px 0 0 700px;
border: 1px solid black;
overflow: auto;
}
#box div{
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
border: 4px solid black;
padding: 40px;
background: red;
margin: 10px;
}
</style>
</head>
<body>
<div id="box">
<div>这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容这是div内容</div>
</div>
<script>
{
/*
- scrollWidth 内容宽度
- scrollHeight 内容高度
- scrollLeft 左右滚动距离
- scrollTop 上下滚动距离
*/
let box = document.querySelector("#box");
let div = box.querySelector("div");
//scrollHeight:如果内容高度 > 元素高度,scrollHeight就为内容高度,否则scrollHeight就为元素高度;有滚动条会去除滚动条高度
console.log(box.scrollHeight);//3359
//scrollWidth:如果内容宽度 > 元素宽度,scrollWidth就为内容宽度,否则scrollWidth就为元素宽度;有滚动条会去除滚动条宽度
console.log(box.scrollWidth);//400 有滚动条383
//元素scrollTop/scrollLeft:上下滚动条位置/左右滚动条位置
box.onscroll = () =>{
console.log(box.scrollTop,box.scrollLeft);//110 0 在滚动条滚动时不断变化
}
}
</script>
</body>
7.4 getBoundingClientRect()
- - left 元素左侧距离可视区左侧距离
- - right 元素右侧距离可视区左侧距离
- - top 元素顶部距离可视区顶部距离
- - bottom 元素底部距离可视区顶部距离
- - width 元素的可视宽度
- - height 元素的可视高度
getBoundingClientRect()随着元素在页面上的移动,各个位置会发生改变。此方法本身不兼容IE浏览器低版本
<style>
div{
height: 100px;
border: 1px solid black;
padding: 40px;
margin: 10px;
}
#box {
position: relative;
top: 20px;
left: 40px;
height: 200px;
border: 4px solid black;
background: red;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div id="box"></div>
<div></div>
<div></div>
<script>
{
/*
getBoundingClientRect()
- left 元素左侧距离可视区左侧距离 margin+left+父级距离左侧位置 即 距离浏览器左侧的可视距离
- right 元素右侧距离可视区左侧距离
- top 元素顶部距离可视区顶部距离
- bottom 元素底部距离可视区顶部距离
- width 元素的可视宽度
- height 元素的可视高度
*/
let box = document.querySelector("#box");
box.onclick = () =>{
console.log(box.getBoundingClientRect().left,box.getBoundingClientRect().right,box.getBoundingClientRect().top,box.getBoundingClientRect().bottom,box.getBoundingClientRect().width,box.getBoundingClientRect().height);
}
}
</script>
</body>
getBoundingClientRect()不兼容IE浏览器低版本,如果需要兼容可以使用offset不断获取其父级的相对位置+自身和父级的边框宽度:
<style>
body {
margin: 0;
}
div{
position: relative;
top: 100px;
left: 100px;
width: 400px;
height: 400px;
border: 1px solid black;
padding: 40px;
}
#box {
position: absolute;
top: 20px;
left: 40px;
width: 100px;
height: 100px;
border: 4px solid black;
background: red;
}
</style>
</head>
<body>
<div>
<div id="box"></div>
</div>
<script>
{
let box = document.querySelector("#box");
let getPageOffset = (el) =>{
let top = el.offsetTop + el.clientTop;
let left = el.offsetLeft + el.clientLeft;
while(el.offsetParent){
el = el.offsetParent;
top += el.offsetTop + el.clientTop;
left += el.offsetLeft + el.clientLeft;
}
return {top,left}
}
console.log(getPageOffset(box));//{top: 125, left: 145} 本身top20+父级top100 + 上边框 本身left40+父级left100+左边框
}
</script>
</body>
8 表格相关操作
- tBodies、tHead、tFoot、rows、cells
- tBodies获取HTMLCollection 获取到的是一组tBody
- tHead获取表头tHead
- rows 获取所有行(tr)
- cells 获取所有列
- tFoot 获取tFoot
<body>
<table id="table" border="1px" width="200px">
<thead>
<tr>
<th>表头1</th>
<th>表头2</th>
<th>表头3</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
<script>
{
let table = document.querySelector("#table");
console.log(table.tHead);
console.log(table.tBodies);
console.log(table.tBodies[0].rows);
console.log(table.tBodies[0].rows[0].cells);
console.log(table.tFoot);
}
</script>
</body>