2.03.08 DOM基础
1.DOM概念
- DOM的概念
- DOM: document object model 文档对象模型
- 是指对页面元素控制的一套标准,叫做DOM,控制页面元素的API
- 有了DOM这个API使得页面的标签变成了对象,一个个标签(即一个个页面元素)变成了一个个对象,这个标签的属性变成了这个标签对象的属性
(这个属性也可能是个对象) - 有了DOM,父标签与子标签的关系就变成了父对象与子对象的关系
- 查看DOM对象可以使用:console.dir(dom对象);
- 注意:DOM既不是HTML的一部分,也不是JavaScript一部分,而是浏览器厂商都实现了的一些独立的规则,并允许JavaScript可以访问和操作存储在DOM中的内容(DOM 也可以使用其他的语言来实现)
- 例如:
console.log( document);// #document //展开是一个页面文档结构
console.log(typeof document); // ' object '
console.log(typeof document === ' object'); // true
//通过该方法查看文档对象
console.dir(document) ;
//他的constructor属性是:constructor: ƒ HTMLDocument()
HTML:
<div id="box">1</div>
JS:
var el = document.getElementById("box" );
console.log(el); //打印一个div文档
console.dir(el) ;//打印一个div#box对象
//他的constructor属性是: constructor: ƒ HTMLDivElement()
console. log(typeof el);// 'object'
console. log(typeof el ==='object');// true
- 节点的概念
- 节点的概念:在 HTML DOM 中,所有事物都是节点。DOM 是被视为节点树的 HTML。
- 根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:
- 整个文档是一个文档节点
- 每个 HTML 元素是元素节点
- HTML 元素内的文本是文本节点
- 每个 HTML 属性是属性节点
- 注释是注释节点
2.获取页面元素
1.选择单个元素节点
- 通过ID获取页面的元素
- getElementById() 返回一个匹配特定 ID 元素节点对应的对象。若在当前 Document 下没有找到,则返回 null。
- 参数:字符串
- 返回值:标签对象
HTML:
<div id="box">1</div>
js:
var div= document.getElementById("box");
console.log(div) ; //打印一个div文档
- 注意1:假如页面元素是有id属性,直可以直接使用id与获取元素,不用使用getElementById方法
console.log(box); //打印一个div文档
- 注意2:id我们通常是唯一的,不建议两个元素的id是一样的,但如今的浏览器不会报错
HTML:
<p id="myid">0</p>
<div id="myid">1</div>
<div id="myid">2</div>
<div class="demo">a</div>
<div class="demo">b</div>
<div data-role='banner'>A</div>
JS:
console.log(myid); //打印一个长度为3的标签数组,这数组包括1个p标签,两个div标签
var div= document.getElementById("myid");
console.log(div) ; //打印一个p标签对象,即全HTML文档中第一个id名为myid的标签
- 注意3:
- JavaScript语言区分字母大小写,所以在使用“getElementById”时千万不要把id大小写弄错了,否则你得不到正确的结果。
- 不同于其他元素查找方法,getElementById() 只有在作为 document 的方法时才能起作用,而在DOM中的其他元素下无法生效。这是因为 ID 值在整个网页中必须保持唯一。因此没有必要为这个方法创建所谓的 “局部” 版本。
- 可以直接通过选择器获取元素
- querySelector(selectors) 返回文档中与指定选择器或选择器组匹配的第一个HTMLElement对象
- 参数:选择器字符串
- 返回值:标签
HTML:
<p id="myid">0</p>
<div id="myid">1</div>
<div id="myid">2</div>
<div class="demo">a</div>
<div class="demo">b</div>
<div class="demo2">c</div>
<div data-role='banner'>A</div>
js:
var el = document.querySelector("#myid");
console.log(el); //<p id="myid">0</p>
el=document.querySelector(".demo")
console.log(el); //<div class="demo">a</div>
- 注意:
- querySelector的选择器也可以非常强大,如 var el = document.querySelector(“div.user-panel.main input[name=‘login’]”);
- querySelect()可以在其他DOM元素中使用,即为该方法创建所谓的 “局部” 版本用来查询当前DOM元素内部符合css选择器的元素
2.选择多个元素节点
- 伪数组:存在着length属性,可以通过数组下标的方式进行每个元素的访问,但是不能够使用数组API。
- getElementsByClassName()
- 返回一个包含了所有指定类名的子元素的动态类数组对象(意味着它可以自动更新自己来保持和 DOM 树的同步而无需重复调用)。当在document对象上调用时,会搜索整个DOM文档,包含根节点。你也可以在任意元素上调用getElementsByClassName() 方法,它将返回的是以当前元素为根节点,所有指定类名的子元素。
- 参数:字符串
- 返回值:标签数组 伪数组 不可以使用数组的API
HTML:
<p id="myid">0</p>
<div id="myid">1</div>
<div id="myid">2</div>
<div class="demo">a</div>
<div class="demo">b</div>
<div class="demo2">
<div class="demo2_1">c</div>
</div>
<div data-role='banner'>A</div>
js:
var ele=document.getElementsByClassName('demo');
console.log(ele);//HTMLCollection(2) [div.demo, div.demo]
ele=document.getElementsByClassName("demo2")
console.log(ele);//HTMLCollection [div.demo2]
var ele2=ele[0].getElementsByClassName("demo2_1");
console.log(ele2);//HTMLCollection [div.demo2_1]
ele.forEach(function(val){
console.log(val);
});//报错
ele.push("a");//报错
- getElementsByTagName()
- 返回一个包含了所有指定标签名称元素的动态类数组对象(意味着它可以自动更新自己来保持和 DOM 树的同步而无需重复调用)。当在document对象上调用时,会搜索整个DOM文档,包含根节点。你也可以在任意元素上调用getElementsByTagName() 方法,它将返回的是以当前元素为根节点,所有指定标签名称的子元素
- 参数:字符串
- 返回值:标签数组 伪数组 不可以使用数组的API
HTML:
<p id="myid">0</p>
<div id="myid">1</div>
<div id="myid">2</div>
<div class="demo">a</div>
<div class="demo">b</div>
<div class="demo2" id="demo2">
<div class="demo2_1">c</div>
</div>
<div data-role='banner'>A</div>
js:
var p=document.getElementsByTagName("p");
console.log(p);//HTMLCollection [p#myid, myid: p#myid]
var div=document.getElementsByTagName("div");
console.log(div);//HTMLCollection(7)
var div_div=document.getElementById("demo2").getElementsByTagName("div");
console.log(div_div);//HTMLCollection [div.demo2_1]
div.push("a");//报错
div.forEach(function(val){
console.log(val);
});//报错
- querySelectorAll()
- 使用css选择器语法,返回全部与指定的选择器匹配的静态元素列表(即不会因为DOM树结构改变而自动更新),没有匹配的情况下为空伪数组。
- 参数:选择器字符串
- 返回值:标签数组 伪数组 不可以使用数组API 但可以使用forEach方法
HTML:
<p id="myid">0</p>
<div id="myid">1</div>
<div id="myid">2</div>
<div class="demo">a</div>
<div class="demo">b</div>
<div class="demo2" id="demo2">
<div class="demo2_1">c</div>
</div>
<div data-role='banner'>A</div>
js:
var p=document.querySelectorAll("p");
console.log(p); //NodeList [p#myid]
var div=document.querySelectorAll("div");
console.log(div);//NodeList(7)
var div_div=document.getElementsByClassName("demo2")[0].querySelectorAll(".demo2_1");
console.log(div_div); //NodeList [div.demo2_1]
div.forEach(function(val){
console.log(val);
}) //打印出了7个div标签
div.push("a");//报错
- 注意:
- 概念:NodeList 对象是节点的集合是一组元素的集合,每一个节点都有索引编号。通常是由document.querySelectorAll 等方法返回的。 元素节点在NodeList中保存的顺序和他们HTML页面中出现的顺序相同。
- NodeList 不是一个数组,是一个类似数组的对象(Like Array Object)。虽然 NodeList 不是一个数组,但是可以使用 forEach() 来迭代。你还可以使用 Array.from() 将其转换为数组。不过,有些浏览器较为过时,没有实现 NodeList.forEach() 和 Array.from()。
- 在一些情况下,NodeList 是一个实时集合,也就是说,如果文档中的节点树发生变化,NodeList 也会随之变化。例如,Node.childNodes 是实时的:
var parent = document.getElementById('parent');
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // 我们假设结果会是“2”
parent.appendChild(document.createElement('div'));
console.log(child_nodes.length); // 但此时的输出是“3”
- 在其他情况下,NodeList 是一个静态集合,也就意味着随后对文档对象模型的任何改动都不会影响集合的内容。比如 document.querySelectorAll 就会返回一个静态 NodeList。
- 最好牢记这种不同,尤其是在当你选择 NodeList 中所有项遍历的方式,或缓存它的长度的时候。
- NodeList具有的属性和方法:(了解一下)
- 属性:NodeList.length,NodeList 中包含的节点个数。
- 方法:
- NodeList.item()
- NodeList.entries()
- NodeList.forEach()
- NodeList.keys()
- NodeList.values()
- getElementsByName()
- 根据给定的name 返回一个包含了所有指定name值的子元素的动态类数组对象
- 参数:字符串
- 返回值:标签数组 伪数组 不可以使用数组API 但可以使用forEach
HTML:
<form name="up"><input type="text"></form>
<form name="up"><input type="text"></form>
<div name="down"><input type="text"></div>
JS:
var up_forms = document.getElementsByName("up");
console.log(up_forms[0].tagName); // "FORM"
console.log(up_forms);//NodeList(2) [form, form]
up_forms.forEach(function(val){
console.log(val);
})//可以正确打印
up_forms.push("a");//报错
- 比较querySelectorAll()和getElementsByClassName() 返回值
- 介绍:动态类数组对象在匹配元素发生改变时(删除、增加)数组中节点项会自动更新与页面中DOM树保持一致,而静态元素列表不会更新
HTML:
<p class = "test p1">段落1</p>
<p class = "test p2">段落2</p>
<p class = "test p3">段落3</p>
<p class = "test p4">段落4</p>
<p class = "test p5">段落5</p>
<p class = "test p6">段落6</p>
<p class = "test p7">段落7</p>
JS:
var getP = document.getElementsByClassName('test');
var queryP = document.querySelectorAll('.test');
console.log(getP); //HTMLCollection(7)
console.log(queryP);//NodeList(7)
在控制台中删除某个段落元素后再在控制台打印
console.log(getP)//HTMLCollection(5)
console.log(queryP)//NodeList(7)
3.元素常用属性
1.HTML标签有的属性
- .id
- 介绍:id 属性表示元素的标识符,同一文档中,若 id 的值不是空字符串 “”,便必须是独特的;也就是说,不同元素的 ID 必须是不同的。这有助于让常用的 getElementById 方法通过 id 的值找到对应的单个元素。
- 语法:
// 获取 id
var idStr = element.id;
// 设置 id
element.id = idStr;
- .style
- 介绍:包含应用到元素的 CSS 样式声明对象,该属性和其包含的样式属性的主要目的是允许快速样式化。
- 注意:
- CSS样式声明对象中的样式属性均为驼峰命名法
- 样式最好以css文件的形式定义在单独的文件中。
- 语法:
// 获取当前元素的 color 样式
var color = element.style.color;
// 设置当前元素的 backgroundColor 样式
element.style.backgroundColor = "#fc0";
//另一书写方法:
//该书写方法较为灵活,因为可以定义变量的形式去修改style属性
// 定义变量 记录属性名称
var v = 'height';
one.style[v] = "80px";
two.style[v] = "60px";
three.style[v] = "40px";
- 注意:使用元素对象去设置样式时,需要将js相关代码放在页面标签之后,要注意等标签渲染出来,才能获取需要的元素对象,不然,获取的元素对象是null
- .className
- 介绍:该属性用来获取或设置指定元素的class属性的值。
- 语法:
// 获取 class 属性值
var cName = element.className;
// 设置元素的 class 属性值
element.className = cName;
- 注意:使用名称className而不是class作为属性名,是因为"class" 在JavaScript中是个保留字。可以是由空格分隔的多个class属性值。
- .classList
- 这是一个对象属性,里面包含一些设置元素类名的方法
- add() 添加类名
- remove() 去除类名
- toggle() 切换类名(已有就去掉,没有就添加)
- contains() 判断是否包含类名
HTML:
<style>
.aaa {
width: 100px;
height: 100px;
background-color: #ccc;
}
.active {
background-color: red;
}
</style>
<div id="box" class="aaa"></div>
JS:
// 获取标签
var div = document.querySelector("#box");
// 属性
// 设置类名
// div.className="aaa active";
// 获取类名
// console.log(div.className);// 'aaa active'
// 方法
// 添加类名
div.classList.add("active");
// 删除类名
div.classList.remove("active");
// 切换类名
div.classList.toggle("active");// 添加
div.classList.toggle("active");// 移除
div.classList.toggle("active");// 添加
div.classList.toggle("active");// 移除
// 判断元素是否包含该类名
var isHas = div.classList.contains("active");
console.log(isHas);// true 表示包含,false 表示不包含
- .value
- 该属性可设置或者返回表单元素的 value 属性值。
- 用法:
<input type="text" name="name" value="ajanuw">
<select name="form-select" class="asd">
<option value="a" selected>aaa</option>
<option value="b" selected>bbb</option>
<option selected>ccc</option>
</select>
<textarea cols="30" rows="10">hello world</textarea>
<script>
var input = document.querySelector('input')
var select = document.querySelector('select')
var textarea = document.querySelector('textarea')
input.value = 'hello world'
console.log(select.value) // ccc
textarea.value = "你好"
</script>
- .placeholder
- 该属性可设置或者返回表单元素的 placeholder 属性值。
- 用法:
// 返回 placeholder 属性
textObject.placeholder
// 设置 placeholder 属性
textObject.placeholder = "请输入密码"
//代码:
<input type="text" name="name">
<select name="form-select" class="asd">
<option value="a" selected>aaa</option>
<option value="b" selected>bbb</option>
<option selected>ccc</option>
</select>
<textarea cols="30" rows="10">hello world</textarea>
<script>
var input = document.querySelector('input')
var select = document.querySelector('select')
var textarea = document.querySelector('textarea')
input.placeholder="shurua"
</script>
2.HTML标签没有的属性
- .nodeValue
- 该属性用来返回或设置当前节点的值。
- 对于元素节点,本身不包含文本所以nodeValue不可用,对于文本节点 nodeValue = 文本值,对于属性节点 nodeValue = “属性值”
- 用法:
<p id="myid">00000</p>
<div class="demo">a</div>
<div class="demo">b</div>
<div class="demo2" id="demo2">
<div class="demo2_1">c</div>
</div>
<script>
//获取p标签的子节点 返回值是一个NodeList数组
var p=document.querySelectorAll("p")[0].childNodes;
console.log(p);//一个NodeList数组
//p[0]是一个文本节点
var content=p[0].nodeValue;
console.log(content); //00000
p[0].nodeValue=80;
//获取p标签的属性节点 返回值是一个NamedNodeMap对象
var shuxing=document.querySelector("p").attributes;
console.log(shuxing);//一个NamedNodeMap对象
console.log(shuxing["id"].nodeValue); //myid
</script>
- nodeName 只读属性
- 用来返回当前节点的节点名称 这是个只可读不可写的属性
- 用法:
//对于元素节点 nodeName = 标签名(返回的名称是大写的)
//对于文本节点 nodeName = #text
//对于属性节点 nodeName = 属性名
<p id="myid">00000</p>
<div class="demo">a</div>
<div class="demo">b</div>
<div class="demo2" id="demo2">
<div class="demo2_1">c</div>
<script>
//获取第一个div标签
var div=document.querySelector("div");
var name=div.nodeName;
console.log(name); //DIV
//获取第一个div标签的子节点,一个文本节点
name=div.childNodes[0].nodeName;
console.log(name); //#text
//获取第一个div标签的属性节点 返回值是一个NamedNodeMap对象
var shuxing=div.attributes;
console.log(shuxing);//一个NamedNodeMap对象
console.log(shuxing["class"].nodeName); //class
//验证只读性
div.nodeName="p";
console.log(div); //<div class="demo">a</div>
//把div改写成p标签也没有效果
</script>
- nodeType 只读属性
- 只读属性 Node.nodeType 表示的是该节点的类型。可用来区分不同类型的节点,比如 元素, 文本 和 注释。
- 对于元素节点 nodeType === 1 即一个元素节点,例如 p 和 div。
- 对于属性节点 nodeType === 2 寄一个元素的属性
- 对于文本节点 nodeType === 3 即元素 或者 属性 中实际的 文字
- 对于文档元素 nodeType === 9 即 一个 Document 节点。
- 对于注释元素 nodeType === 8
- 用法:
<p id="myid">00000</p>
<script>
document.nodeType === 9; // true
var p = document.getElementById("myid");
p.textContent = "很久很久以前...";
p.nodeType === 1; // true
p.firstChild.nodeType === 3; // true
</script>
4.获取页面结构元素
- document.documentElement,document.head,document.body,document.title
// 文档对象:document
// 获取相关的元素
// var html = document.documentElement;
// var head = document.head;
// var body = document.body;
// var title = document.title;
// console.log(html);// 根元素
// console.log(head);// 头部元素
// console.log(body);// 主体元素
// console.log(title);// 字符串,网页标题
// title有点特殊,要获取title这个标签元素须通过querySelector(selectors) 等其他办法
注意:只有页面的结构元素才可以使用document.结构元素的方式获取,其他元素节点不可以使用父元素.子元素的方式获取
<div class="demo2" id="demo2">
<div class="demo2_1">c</div>
</div>
<script>
var box=document.querySelector(".demo2");
console.log(box);
console.log(box.div); //undefined
</script>
5.题外话
- 一个标签属性值,写在标签里面
- contenteditable 设置标签为可编辑的状态
- 属性值:true 或 false
- 代码技巧:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
input{
padding: 15px;
margin: 10px;
border: 1px solid black;
border-radius: 10px;
}
</style>
<body>
<input type="button" value="张三">
<input type="button" value="李四">
<input type="button" value="王五">
<input type="button" value="老六">
<input type="button" value="大奇">
<script>
var btn=document.getElementsByTagName("input");
for(var i=0;i<5;i++){
//函数自执行 + 闭包 + this指向
//这个函数会自执行,这个自执行的函数,执行一次就创造一个闭包环境
(function(){
var index=i; //该变量就是要创造闭包环境去保存的值
//给每个按钮绑定事件 //每个事件函数都有自己的私有变量index
btn[i].onclick=function(){
for(var j=0;j<btn.length;j++){
if(j==index){ //当j=index时不执行for里面的语句,即不给对应的按钮背景白色
continue;
}
btn[j].style.backgroundColor="white";
//除了下标为index的按钮,其他按钮都是背景白色
}
alert("我是"+this.getAttribute("value"));
this.style.backgroundColor="pink";
}
})()
}
(
function(){
console.log("我没有被调用就执行了!!");
}
)()
</script>
</body>
</html>
的私有变量index
btn[i].οnclick=function(){
for(var j=0;j<btn.length;j++){
if(j==index){ //当j=index时不执行for里面的语句,即不给对应的按钮背景白色
continue;
}
btn[j].style.backgroundColor=“white”;
//除了下标为index的按钮,其他按钮都是背景白色
}
alert(“我是”+this.getAttribute(“value”));
this.style.backgroundColor=“pink”;
}
})()
}
(
function(){
console.log("我没有被调用就执行了!!");
}
)()
```