DOM
- DOM,全称Document Object Model文档对象模型。
- JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随 心所欲的操作WEB页面,改变页面的内容、结构、样式。
- 文档
文档表示的就是整个的HTML网页文档 - 对象
对象表示将网页中的每一个部分都转换为了一个对象(通过修改对象去修改页面)。 - 模型
使用模型来表示对象之间的关系,这样方便我们获取对象。
DOM树
- 文档:一个页面就是一个文档,DOM中使用document表示
- 元素:页面中所有的标签都是元素,DOM中使用element表示
- 节点:网页中所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
模型
节点
-
节点Node,构成HTML文档最基本的单元,是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点。
-
比如:html标签、属性、文本、注释、整个文档等都是一个节点。
-
虽然都是节点,但是实际上他们的具体类型是不同的。
-
比如:标签我们称为元素节点、属性称为属性节点、文本称为 文本节点、文档称为文档节点。
-
节点的类型不同,属性和方法也都不尽相同。
-
常用节点分为四类
-
文档节点:整个HTML文档
-
元素节点:HTML文档中的HTML标签
-
属性节点:元素的属性
-
文本节点:HTML标签中的文本内容
节点的属性
nodeName | nodeType | nodeValue | |
---|---|---|---|
文档节点 | #document | 9 | null |
元素节点 | 标签名 | 1 | null |
属性节点 | 属性名 | 2 | 属性值 |
文本节点 | #text | 3 | 设置和获取文本内容 |
注释节点 | #comment | 8 | 注设置和获取释的内容 |
如何区分
根据nodeType区分节点
文档节点(document)
- 文档节点document,代表的是整个HTML文档,网页中的所有节点都是它的子节点。
- document对象作为window对象的属性存在的,我们不用获取可以直接使用。
- 通过该对象我们可以在整个文档访问内查找节点对象,并可以通过该对象创建各种节点对象。
元素节点(Element)
- 中的各种标签都是元素节点,这也是我们最常用的一个节点。
- 浏览器会将页面中所有的标签都转换为一个元素节点,我们可以通过document的方法来获取元素节点。
- 比如:
- document.getElementById()
- 根据id属性值获取一个元素节点对象
文本节点(Text)
-
文本节点表示的是HTML标签以外的文本内容,任意非HTML的文本
都是文本节点。 -
它包括可以字面解释的纯文本内容。
-
文本节点一般是作为元素节点的子节点存在的。
-
获取文本节点时,一般先要获取元素节点。在通过元素节点获取文本
节点。 -
例如:
- 元素节点.firstChild;
- 获取元素节点的第一个子节点,一般为文本节点
属性节点(标签的属性)(Attr)
- 属性节点表示的是标签中的一个一个的属性,这里要注意的是属性节点,并非是元素节点的子节点,而是元素节点的一部分。
- 可以通过元素节点来获取指定的属性节点。
- 返回的是对象
- 例如:
- 元素节点.getAttributeNode(“属性名”);
- 注意:我们一般不使用属性节点。
注释节点(commnet)
var comment=childNodes[9];
层级关系
父节点(parent)
子节点(child)
同胞节点(sibling)
根节点 (root)html
事件
-
事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间,即用户和浏览器之间的交互行为。
-
JavaScript 与 HTML 之间的交互是通过事件实现的。
-
对于 Web 应用来说,有下面这些代表性的
- 事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键,关闭窗口,等等
事件三元素
-
事件源
事件被触发的对象 谁 按钮
-
事件类型
如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
-
事件处理程序
通过一个函数赋值的形式 完成
事件执行的过程
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采取函数赋值形式)
处理事件
onclick 单击事件
ondblclick 双击触发
onmousemove 鼠标移动到该位置触发
onload 事件会在整个页面加载之后才触发
可以在事件对应的属性中设置一些js代码,当事假被触发时,这些代码将会执行
<button id="btn" onclick="alert('点我干啊')">我是一个按钮</button>
事件的设置方式
- 在标签处绑定,结构和行为耦合(不推荐)
<button id="btn2" ondblclick="alert('双击')">我是一个按钮</button>
- 可以为按钮的对应事件 绑定处理函数的形式来响应事件
// 获取按钮对象
var btn = document.getElementById("btn1");
// 绑定点击事件
// 像这种被单机事件绑定的函数,我们称为点击响应函数
btn.onclick = function () {
alert('你还点?');
}
多元素 (集合) 绑定事件
遍历集合获取单个元素循环绑定事件
- 页面加载时事件只做绑定
- 当点击对应的li时才会执行对应函数
问题出现
只返回终止下标,对应的元素,触发事件
解决1 寻找替换li和i的方案
- 使用this,代替本个li
- 循环的时候,使用自定义属性(html的属性),给每个元素一个独特的编号,代替下标
- html的属性可见
- 元素节点返回的是对象
- 使用元素的自定义属性
解决2 用函数做中间商 把事件中的i和li变为局部的
老版 匿名函数的自调用
解决3 ES6中的let
var
和let
都可以声明全局变量和局部变量
不同点:
-
变量提升方面
var
声明的变量有变量提升let
声明的变量没有变量提升
-
重复声明方面
var
声明的变量,可以重复声明let
声明的变量,不能重复声明
-
es6新增块级作用域(含有{}的,都可以形成块级作用域)
-
常见的块级作用域
if(true){ //选择结构 if switch } //循环结构 while do ...while for for...in for...of while(true){ break; }
-
在块级作用域中,
let
声明的变量是局部变量 -
块级作用域对
var
没有影响,如果块级作用域处在全局作用域中 ,var
声明的变量就是全局变量 -
如果块级作用域处在函数作用域中,
var
声明的变量就是就是局部变量{ var a = 100; var b = 200; console.log('块级作用域内',a,b); } console.log('块级作用域外',a,b)
-
-
文档的加载
浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行
-
将js代码代码页面底部
-
onload等到页面加载完成之后 再执行,确保代码执行时,所有的DOM对象已经加载完毕了
window.onload = function(){
// 获取id为btn的按钮
var btn = document.getElementById("btn");
// 为按钮绑定一个点击响应函数
btn.onclick = function(){
alert('hello');
}
}
H5新增根据类名获取元素
document.getElementsClassName
根据类名获得某些元素集合
返回的是对应的元素对象集合(伪数组)
根据下标取值
doucument.querySelector(‘选择器’)
以选择器的形式获取
获取单个元素,即第一个元素对象,多个也默认也返回第一个
切忌里面的选择器需要加符号,类名选择器需要加 .
,id选择器需要加#
doucument.querySelectorAll(‘选择器’)
以选择器的形式获取多个元素,返回指定选择器的所有集合
即使只有一个元素,也返回集合,通过下标[0]取值
返回的是对应的所有元素对象集合(伪数组)
切忌里面的选择器需要加符号,类名选择器需要加 .
,id选择器需要加#
获取body元素和html元素
获取body元素
var bodyEle = document.body;
获取html元素
var htmlEle = document.documentElement;
获取元素节点(DOM的查)
通过document对象调用
getElementById()
通过id属性获取一个元素节点对象
document.getElementsClassName()
根据类名获得某些元素集合
返回的是对应的元素对象集合(伪数组)
根据下标取值
获取单个元素时,通过下标[0]取值
getElementsByTagName()
通过标签名获取一组元素节点对象
这个方法返回是一个类数组对象,所有查询到的元素都会封装到对象中
即使查询到的元素之只有一个,也会封装到数组中返回
获取单个元素时,通过下标[0]取值
可通过.lenth(类数组的长度) 返回查询的标签元素的个数
可通过遍历,打印查询到的每一个对象,并用list[i].innerHTML返回遍历的每一个标签元素的内容
注意**:innerHTML用于获取元素内容的HTML代码**
对于自结束的单闭合标签(<input/>等自结束标签
),这个属性没有意义
getElementsByName()
返回的是类数组对象
一般用于表单元素
获取单个元素时,通过下标[0]取值
通过name属性获取一组元素节点对象
可以通过.length遍历,返回的根据name属性获取的一组元素节点对象
注意**:innerHTML用于获取元素内容的HTML代码**
对于自结束的单闭合标签(<input/>等自结束标签
),innerHTML属性没有意义
如果需要读取元素节点属性,直接使用 元素.属性名
例子:元素.id 元素.name 元素.value
注意:class属性不能采用这种方式,
读取class属性时需要使用 元素.className
获取元素节点的子节点
通过具体的元素节点调用
getElementsByTagName()节点的指定标签名后代节点
通过父元素,只能通过对应的class名和标签名查找,即只能使用getElementByClassName, getElementsByTagName来获取
获取单个元素时,通过下标[0]取值
方法,返回当前节点的指定标签名后代节点
注意:方法是有括号的,其他的属性是没有括号的
childNodes 当前节点的所有子节点
属性,表示当前节点的所有子节点
- 注意:属性是没有括号的
childNodes属性会获取**包括文本节点(标签和标签之间的换行会被获取为Text文本节点)**在内的所有节点
-
标签和标签之前的换行,会被获取为Text文本
-
根据DOM标签的标签空白 也会被当成文本节点
注意:在IE8及以下的浏览器中,不会将空白文本当成子节点,在低版本浏览器中,childNodes和children属性是一样的
但是,children属性可以获取当前元素的所有子元素,而不包括空白的节点
children属性 获取子元素的结合
firstChild 当前节点的第一个子节点
属性,表示当前节点的第一个子节点
只要是节点,最终被获取的时候,标签之间的换行、空格等,都会被获取为Text文本节点
但是,firstElementChild属性,可以获取当前元素的第一个子元素(不会将换行获取为Text文本节点),不建议使用,因为不支持IE8及其以下
firstElementChild属性 兼容解决
获取当前元素的第一个子元素
lastChild当前节点的最后一个子节点
属性,表示当前节点的最后一个子节点
只要是节点,最终被获取的时候,标签之间的换行、空格等,都会被获取为Text文本节点
lastElementChild 当前节点的最后一个子元素,在低版本浏览器中不存在
lastElementChild 兼容解决
当前节点的最后一个子元素
父节点和父元素
parentNode 获取父节点
属性,表示当前节点的父节点
innerText 可以获取到元素内部的文本内容
它和innerHTML类似,不同的是,它会自动将html标签去除,只获取文本
parentElement 父元素
和父节点是一样的
获取兄弟(同胞)节点和元素
previousSibling 获取当前节点的前一个兄弟节点
属性,表示当前节点的前一个兄弟节点
标签之间的空格和换行,会被获取成文本节点Text
但是,previousElementSibling 是获取当前元素的前一个兄弟元素,不包括文本,IE8及其以下不支持
previousElementSibling 前一个兄弟元素
不包括文本,IE8及其以下不支持
兼容解决
nextSibling 表示当前节点的后一个兄弟节点
属性,表示当前节点的后一个兄弟节点
nextElementSibling 后一个同级元素
在低版本浏览器中,没有该属性
兼容解决
三种动态创建元素的区别
DOM操作之新增
新增元素节点
document.createElement(“新增的元素”)
注意:元素节点生成的时候,可以绑定事件
parent.appendChild(node) 将新增的节点(元素节点/文本节点) 附加到父元素的最后方
- parent 是父元素
- node 是新增的元素
// 新增元素节点
var li = document.createElement("li");
// 把新增的元素节点,添加到ul上
ul.appendChild(li);
parent.appendChild(node)
parent.appendChild(node) 将新增的节点(元素节点/文本节点),放到父元素最后面
parent.append()
parent.append() 将新增的节点(元素节点/文本节点),放到父元素最后面
parent.prepend()
parent.prepend() 将新增的节点(元素节点/文本节点) 附加到父元素最前面
parent.insertBefore(newNode,oldNode)
将一个节点(新节点/已存在的节点)插入到一个已存在的节点的前面,即在某个节点前面插入
// 如何将新增的1i插入到second后面 ,即后一个的前面,就是前一个的后面
nav.insertBefore(1i,second.nextElementsibling);
新增属性节点
document.createAttribute(“新增的属性名”) 配合nodeValue
var attr = document.createAttribute("class");
attr.nodeValue = "addClass";
li.setAttributeNode(attr);
ul.appendChild(li);
// 简洁方式
li.setAttribute('class', "newClass");
ul.appendChild(li);
新增文本节点
document.createTextNode(“新增的文本”)
新增的文本也是对象类型,所有的节点都是对象类型
parent.appendChild(node) 将新增的节点(元素节点/文本节点) 附加到父元素的最后方
- parent 是父元素
- node 是新增的元素
// 新增 文本节点
var text = document.createTextNode("create");
li.appendChild(text);
// 简洁方式
li.innerText = '简洁创建文本节点';
ul.appendChild(li);
DOM操作之删除
自删
- 删除的元素不可还原
- 返回值是undefined
// 本元素.remove()
btn1.onclick = function () {
// 自删
var res1 = firLi.remove();
console.log('自删',res1);
}
父删
- 可以被还原
- 返回值是被删除的那个元素
// 释放空间,没有则不删 parent.removeChild();
btn2.onclick = function () {
// 自删
if(lastLi){
// 返回被删除的元素
var res2 = ul.removeChild(lastLi);
lastLi= null; // 删除之后清空元素
console.log('父删',res2);
}
}
DOM操作之替换
parent.replaceChild(newNode,oldNode) 用新的节点(元素)替换已存在的节点
.cssText 批量设置样式
element.style.cssText=”width:20px;height:20px;border:solid 1px red;”;
DOM操作之克隆
ele.cloneNode()
只会克隆元素及其属性,并不会克隆子内容
需要添加布尔值,默认为false,要想克隆子内容,接收布尔值为true
元素节点的属性(通用)
获取的元素 元素节点 => 都是对象类型(对象类型(对一个或一类事物特征(属性)和行为(方法)的描述))
console.dir(对象);//打印对象或方法的详细属性
innerText 获取和设置 元素内对应的文本内容
- 不识别html标签,里面的标签会直接进行显示
- 可以获取元素内容
- 去除空格和换行
innerHTML 获取和设置 元素内对应的html结构
- 识别html标签
- 可以获取元素内容
- 保留空格和换行
textContent 获取和设置 元素对应的文本内容
- 渲染的时间更快
outerHTML 获取和设置 元素以及元素内对应的html结构
- 完全替换一个元素的结构,连自己都改
tagName 返回元素的标签名
返回的是大写
id 获取和设置元素的id名称
nav.id = "first";//修改元素节点的属性
nav.setAttribute("id","first"); //修改htm1属性
className 获取和设置元素的class名(单类名)
适用于 单类名
console.1og(nav.className);
nav.className ="change"; //修改元素节点的属性
nav.setAttribute("class","change"); // 修改html属性
classLIst 返回所有class名的集合
返回是是伪数组,适用于多类名
classLIst的相关方法(一般用于元素多个class名操作)
- 直接操作classList
- 一般用于元素多个class名操作
- 操作影响页面,会渲染到页面上
add() 给元素添加一个class
- 没有就添加,有就不做任何操作
- 新增class之后,同样渲染到页面上
remove() 删除对应的class名
- 有就删,没有就不做任何操作
replace(oldClass,newClass)
- 用新的class替换原本的class名
contains() 判断元素是否包含某个class名
- 包含则返回true,不包含则返回false
toggle 切换类名
有就删除,没有就添加(可用于点击或取消点击切换样式)
- 没有返回true
- 有则返回false
title 鼠标悬浮提示
获取行内样式
- 可以通过style设置样式
- 但是使用box.style.backgroundColor,只能获取行内样式
获取非行内样式(内部样式、外部样式、默认样式)
- 常规浏览器
// 接收一个html元素,返回所有css对象
// 也同时返回默认样式
window.getComputedStyle(ele);
// 取值(对象取值)
// 点语法
var bgc=window.getComputedStyle(box).backgroundColor;
// 颜色返回rgb
// 中括号语法
var height=window.getComputedstyle(box)["height"];
// 取值的时候,要记得去单位
- IE浏览器
// 把css组成的对象 存在元素节点的属性上ele.currentStyle上
// 颜色返回16进制
console.1og(window.getcomputedstyle);// undefined console.1og(box.currentStyle);
兼容处理
// 中括号语法
// 先兼容常规浏览器,再兼容IE
点击变色
元素节点自定义属性
元素节点本质是对象
元素节点的属性(某些元素独有 )
非表单元素独有
href 获取和设置元素的href属性(a,link)
src 获取和设置元素的href属性(img,script)
contentEditable 非表单元素是否可以编辑(类型输入框)
表单元素独有
required
要求输入的内容,必须有值,采取浏览器默认字段验证
- true 必填
- false 默认不是必填
disabled
user.disabled=true;//禁用user
是否禁用
- true 是禁用
- false 默认不禁用
注意:禁用之后,即使有required属性,也不会触发
placeholder
获取和设置 表单输入提示
checked
用于单选框和复选框是否选中
- true 选中
- 默认是false 不选择
selected
选中状态
- sel.selectedIndex 设置或返回 下拉框被选中option元素的下标(从0开始)
- selectedOptions 下拉框被选中的option的集合(可以设置多选)
- sel.multiple 是否多选 (用于文件上传)
- 默认 是false 单选
- true 是多选
hidden
是否隐藏
- 默认是不隐藏 false
- true 是隐藏
type
设置获取类型
form内元素快速获取
操作元素
修改元素内容
innerHTML
- 识别html标签
- 可以获取元素内容
- 保留空格和换行
innerText
- 不识别html标签,里面的标签会直接进行显示
- 可以获取元素内容
- 去除空格和换行
修改元素属性
src href
id alt title
value
修改表单属性
利用DOM可以操作如下表单元素的属性:
type、value、checked、selected、disabled(禁用)
// 禁用按钮
btn.disabled = true;
// this.disabled = true;
修改样式属性
我们可以通过JS修改元素的大小、颜色、位置等样式。
行内样式操作
element.style //行内样式操作
类名样式操作
element.className //类名样式操作,点击后添加相应的类名
之前这个元素必须没有类名,否则添加类名后,会覆盖之前的类名
注意
-
如果样式修改较多,可以采取操作类名方式更改元素样式
-
class因为是个保留字,因此使用className来操作元素类名属性
-
className会直接更改元素的类名,会覆盖原先的类名
-
如果想要保留原先的类名,我们可以这么做多类名选择器
// this.className='change'; this.className='first change';
注意
- js里面的样式采取驼峰命名法比如 fontsize、backgroundcolor
- js修改style样式操作,产生的是行内样式,css权重比较高
属性节点(html属性)的获取、设置、删除
本质是标签的属性(标签内可见)
getAttribute(arrrName) 获取某个元素的对应html属性
- 根据html的属性名,获取对应的属性值
setAttribute(“attrName”,attrValue) 设置属性
- 操作元素,根据属性名,设置对应的属性值(html属性)
添加、删除、修改、获取自定义属性
removeAttribute() 删除html属性
根据对应属性名删除
删除谁,就找谁
快捷获取元素宽高
clientwidth/clientHeight 获取可视宽度/高度
(conten+padding)不包含border
offsetwidth/offsetHeight 偏移宽度/高度
(conten+padding+border)包含border
scrollWidth/scrollHeight 实际宽度/高度
(content+padding),如果有滚动条,content则为实际宽度
-
如果没有padding和border三个属性均可
-
想获取包含padding clientwidth
-
想获取包含padding+border offsetwidth
-
想获取实际内容srcollwidth(如果有滚动条)
缺点
- 只能取值,不能赋值
- 对于元素隐藏(display:none,hidden),则三个属性无法生效(都是0)
offsetLeft offsetTop 快捷获取当前元素相对于参照物父元素
快捷获取当前元素相对于参照物父元素(offsetParent)的偏移
- margin-left,margin-top
- 定位 left/top
如何确定参照物父元素?(类似绝对定位的查找流程)
- 自当前元素的父元素开始,查找各种定位属性(relative、absolute、fixed)
- 如果有,则父级就是该元素的参照物(offsetParent)父元素
- 如果没有继续向上一级查找,以此类推
- 如果最终都找不到,则body就是该元素的参照物父元素
缺点
- 只能取值,不能赋值
- 对于元素隐藏(display:none,hidden),则该属性无法生效(都是0)