# DOM
DOM(document object model):将标记语言文档的各个组成部分,封装为对象。可以使用这些对象,对标记语言文档进行CRUD 的动态操作
W3C DOM 标准被分为 3 个不同的部分:
- 核心 DOM - 针对任何结构化文档的标准模型
- Node:原生节点对象,以下节点对象都继承于此
- Document:文档对象,整个文档树的顶层节点
- DocumentType:
doctype标签(比如<!DOCTYPE html> - Element:元素对象,网页的各种HTML标签(比如
<body>、<a>等) - Attribute:属性对象,网页元素的属性(比如
class="right") - Text:文本对象,标签之间或标签包含的文本
- Comment:注释对象
- DocumentFragment:文档的片段
- XML DOM - 针对 XML 文档的标准模型
- HTML DOM - 针对 HTML 文档的标准模型
解析过程:根据html的层级结构,在内存中分配一个树形结构,需要把html中的每部分封装成对象
# Node
节点对象,其他对象的父对象。所有dom对象都可以被认为是一个节点
JS中有宿主对象 document(文档对象本身),是 window 对象的属性。DOM中的对象又称为节点对象,4种常用节点:
| nodeName | nodeType | nodeValue | |
|---|---|---|---|
| Document 文档节点 | #document | 9 | null |
| Element 元素节点 | 标签名 | 1 | null |
| Attribute 属性节点 | 属性名 | 2 | 属性值 |
| Text 文本节点 | #text | 3 | 文本内容 |
属性:
nodeType:一个整数值表示==节点的类型==。如Element为1、Attribute为2、Text为3、Document为9nodeName:节点的名称。如Element为大写标签名、Attribute为属性名、Text为#text、Document为#documentnodeValue:一个字符串,表示当前节点本身的文本值。只有Attribute、Text、Comment有值,其余返回nulltextContent:当前节点和它的所有后代节点的==所有文本内容==,自动忽略当前节点内部的 HTML 标签baseURI:一个字符串,表示当前网页的绝对路径ownerDocument:当前节点所在的顶层文档对象,document本身的这个属性为null。与getRootNode()一样作用previousSiblin:当前节点==前==面的、距离最近的一个同级节点,没有同级节点则返回nullnextSibling:紧跟在当前节点==后==面的第一个同级节点,没有同级节点则返回nullparentNode:==当前节点的父节点==,可能有三种类型,如Document、Element、DocumentFragmentparentElement:当前节点的父元素节点,排除了上述类型中首尾两个
方法(CRUD DOM树):
appendChild(newNode):==将其作为最后一个子节点,插入当前节点==。若newNode为DOM中已存在的,相当于剪贴insertBefore(newNode,oldNode):节点之前插入一个新的节点,没有insertAfter()方法可以结合nextSibling实现removeChild(Node):通过父节点删除指定子节点,并返回被删除的节点。不存在DOM中,但在内存中仍可使用replaceChild(newNode,oldNode):通过父节点用新节点替换一个子节点cloneNode(boolean b):复制节点返回新节点,boolean表示是否复制子节点,会丧失该节点上的事件回调函数childNodes:当前节点的所有子节点的NodeList集合,但是包括Text、Commnet!空格之类的都包括!别用!hasChildNodes():当前节点是否有子节点,也是包括所有类型节点!空格也算!别用!
# NodeList 接口(了解)
NodeList实例是一个类似数组不是数组的对象,它的成员是节点对象。通过以下方法可以得到NodeList实例Node.childNodes:说了别用!省的没注意空格!document.querySelectorAll()等节点搜索方法
- 属性:
length,NodeList 实例包含的节点数量
- 方法:
forEach,也可以使用for循环。没pop、pust等方法哦!item(index):接受一个整数值作为参数,表示成员的位置,返回该位置上的成员。
- 。。。懒得看了
# HTMLCollection 接口(了解)
HTMLCollection是一个节点对象的集合,只能包含元素节点(element),不能包含其他类型的节点。它的返回值是一个类似数组的对象,但是与NodeList接口不同,HTMLCollection没有forEach方法,只能使用for循环遍历- 返回
HTMLCollection实例的,主要是一些Document对象的集合属性,比如document.links、docuement.forms、document.images、document.styleSheets、document.scripts等 HTMLCollection实例都是动态集合,节点的变化会实时反映在集合中- 属性
length:返回HTMLCollection实例包含的成员数量
- 方法
item():接受一个整数值作为参数,表示成员的位置,返回该位置上的成员namedItem():参数是一个字符串,表示id属性或name属性的值,返回对应的元素节点。如果没有则返回null
# ParentNode 接口
- 只有元素节点(element)、文档节点(document)和文档片段节点(documentFragment)拥有子节点,因此只有这三类节点会继承
ParentNode接口 - 属性
children:返回一个HTMLCollection实例,成员是当前节点的所有元素子节点。该属性只读。firstElementChild:当前节点的第一个元素子节点。如果没有任何元素子节点,则返回nulllastElementChild:当前节点的最后一个元素子节点,如果不存在任何元素子节点,则返回nullchildElementCount:返回一个整数表示当前节点的所有元素子节点的数目。如果不包含任何元素子节点则返回0
- ==方法(如下方法都没有返回值)==
append():为当前节点的最后一个元素子节点后追加一个或多个子节点。可以添加元素子节点、文本子节点prepend():为当前节点的的第一个元素子节点前追加一个或多个子节点。同append()方法- 若是若
newNode为DOM中已存在的,相当于剪贴
- 若是若
# ChildNode 接口
- 如果一个节点有父节点,那么该节点就继承了
ChildNode接口 - ==方法(都是本节点调用方法)==
remove():==用于从父节点移除当前节点,自己调用删除自己!因为已知本节点有父节点==before():当前节点的前面,插入一个或多个同级节点,两者拥有相同的父节点。可以插入元素节点、文本节点after():在当前节点的后面,插入一个或多个同级节点,两者拥有相同的父节点。同before()方法replaceWith():使用参数节点,替换当前节点。参数可以是元素节点,也可以是文本节点
# Document 🔥
# 简介
在 HTML DOM 模型中有宿主对象document,它是window对象的属性(也可以省略)。
继承了Node、ParentNode等接口
# 常用属性(好像不太常用)
body该属性封装的是body元素对象的引用
documentElement属性值为HTML元素对象
all属性值为当前页面中的所有元素节点的数组。这个属性值本身为
undefined,它的typeof值也为undefinedURL获取当前页面的url
domain获取当前页面的域名部分
referrer获取是哪个页面链接跳转到当前页面,没有则返回空字符串
# 常用 CRUD 方法 🔥
# 获取 Element 对象
注意
可以使用Document对象和Element对象调用如下函数。但是~ById()函数只能用在Document对象上
注意
如下方法都支持 IE8 及以上
querySelector():CSS选择器为参数,如果有多个节点满足匹配条件,则返回第一个匹配的节点,没有则返回 nullquerySelectorAll():返回一个NodeList对象,包含所有匹配给定选择器的节点。用法同上【注意】不支持CSS伪元素选择器和伪类选择器
getElementById("id"):根据 ID 属性获取一个元素对象,效率比querySelector()高getElementsByClassName("className"):标签的class的属性值得到元素集合(HTMLCollection实例)getElementsByTagName("tagName"):标签名称得到元素集合(HTMLCollection实例)getElementsByName("name"):标签的name属性值得到元素集合(NodeList实例),radio、checkBox等只有一个标签时通过
document.getElementsByTag/ClassName("input")[0]获取元素对象获取标签下面的子孙标签的唯一有效办法,使用父节点**
getElementsByTagName()**方法,不使用childNodes属性
# 添加 DOM 对象
createElement("元素名称"):创建元素节点,参数为tagName属性,对HTML不区分大小写,但不能加尖括号createTextNode("文本内容"):创建文本节点,可以在内容中添加标签。不能对属性赋值,不会转义单双引createAttribute(name):创建拥有指定名称的属性节点,并返回新的 Attr 对象。通过Node来设置属性createComment():创建注释节点
# 其他
- write():向页面输出变量(值)、html代码
# Element 🔥
通过document来获取和创建
# 常用属性
innerHTML:返回一个字符串,等同于该元素包含的所有 HTML 代码,该属性可读写。用来设置某个节点的内容innerText:同上,但是只显示文本代码,不带标签的!!,设置内容也不会解析为HTMLtextContent:显示文本或插入的是文本时使用来替代上面方法。原样显示,不像上面方法会转为&**;来显示value:代表的是元素的value属性,一般用于**input标签值的获取**,**select**标签值也可以使用style:用来读写该元素的行内样式信息,配合CSS。如display可取值none、block、inner也可以提前定义好类选择器的样式,通过元素的
className属性来设置其class属性值。
# 常用 Attribute 方法
getAttribute("name"):获取属性里面的值setAttribute("name","value"):设置属性的值removeAttribute("name"):删除属性,不能删除value属性
# Event
# 加载事件
onload文档被浏览器加载时触发,只能写一次;一般在body标签中注册函数;或用window来调用。此时可以操作DOM元素**。
window.onload = function () { document.getElementById("btn").onclick = function () { alert("haha"); } }
# 点击事件
onclick:点击事件(按钮)ondblclick:双击事件
# 焦点事件(表单校验)
onfocus:组件获得焦点事件(输入框/单选/多选/下拉) ,光标闪动onblur:组件失去焦点事件(输入框/单选/多选/下拉)
# 改变事件
onchange:域的内容改变/选择的值发生变化事件(输入框/下拉)onselect:文本被选中
# 表单事件
onsubmit:表单提交按钮按下时触发的事件(表单校验)在form后注册函数,有返回值true/false,控制提交与否必须写
return 函数名否则不能获取到返回的boolean值onreset:重置按钮按下时
# 鼠标事件
onmouseover():鼠标移动到组件上时触发onmouseout:鼠标移出组件时触发onmousemove:鼠标移动就触发onmousedown:鼠标按键按下时触发定义方法时,定义一个形参来接收
event对象,它的button属性可以获取鼠标哪个按钮被点击(0,1,2)onmouseup:鼠标按键松开时触发
# 键盘事件
onkeydown:某个键盘按键被按下onkeyup:某个键盘按键被松开onkeypress:某个键盘按键被按下并松开
# 案例
# 动态显示时间
let ele = document.getElementById("h1");
function setTime() {
let s = new Date().toLocaleString();
ele.innerText = s;
}
setInterval(setTime,1000);
# 轮播图(正常不这么做)
var i = 1;
function changeImg () {
i++;
if ( i > 3 )
i = 1;
document.getElementById("img1").src = "img/" + i + ".jpg";
}
setInterval(changeImg, 5000);
# 定时弹出广告(style.display)
showTime = setTimeout(showAd, 3000);//定义为全局变量
function showAd() {
document.getElementById("adImg").style.display = "block";
clearTimeout(showTime);
hiddenTime = setTimeout(hiddenAd, 3000);
}
function hiddenAd() {
document.getElementById("adImg").style.display = "none";
clearTimeout(hiddenTime);
}
# 动态增删表格
document.getElementById("btn").onclick = function () {
let id = document.getElementById("id").value;
let name = document.getElementById("name").value;
let sex = document.getElementById("sex").value;
//thead
let tbd = document.getElementsByTagName("thead")[0];
document.getElementById("btn").onclick = function () {
let id = document.getElementById("id").value;
let name = document.getElementById("name").value;
let sex = document.getElementById("sex").value;
let thd = document.getElementsByTagName("thead")[0];
thd.innerHTML += "<tr>\n" +
" <td>" + id + "</td>\n" +
" <td>" + name + "</td>\n" +
" <td>" + sex + "</td>\n" +
" <td><a href=\"javascript:void(0);\" onclick=\"delTr(this);\" >删除</a></td>\n" +
" </tr>";
//使用方法一个个添加也行,但是麻烦
}
function delTr(obj) {
var parentNode = obj.parentNode.parentNode.parentNode;
var deleteNode = obj.parentNode.parentNode;
parentNode.removeChild(deleteNode);
}
}
# 全选/全不选/反选/高亮
let inputs = document.getElementsByClassName("check-box");
//全选
document.getElementById("selectAll").onclick = function () {
for (let i in inputs) {
inputs[i].checked = true;
}
}
//全不选
document.getElementById("notSelect").onclick = function () {
for (let i in inputs) {
inputs[i].checked = false;
}
}
//反选
document.getElementById("reverseSelect").onclick = function () {
for (let i in inputs) {
inputs[i].checked = !inputs[i].checked;
}
}
//左上角选择
document.getElementById("ck1").onclick = function () {
for (let i in inputs){
inputs[i].checked = this.checked;
}
}
//表格行高亮
let trs = document.getElementsByTagName("tr");
for (let t in trs){
trs[t].onmouseover = function () {
this.style.backgroundColor = "gray";
}
trs[t].onmouseout = function () {
this.style.backgroundColor = "white";
}
}
# 表单校验
window.onload = function () {
//表单校验
document.getElementById("form").onsubmit = function () {
return checkUsername();//可添加密码校验
}
document.getElementById("username").onblur = checkUsername;//可添加密码校验
}
//用户名校验
function checkUsername() {
var username = document.getElementById("username").value;
var reg = /^\w{6,12}$/;
let flag = reg.test(username);
if (flag) {
document.getElementById("usernameSpan").innerHTML = "✔";
} else {
document.getElementById("usernameSpan").innerHTML = "用户名格式有误";
}
return flag;
}
//可添加密码校验等等
。。。。。
# 左右列表
- select、option、multiple、selected=true/false、appendChild()剪贴的length变化
var left = document.getElementById("left");
var leftlist = left.getElementsByTagName("option");
var right = document.getElementById("right");
var rightlist = right.getElementsByTagName("option");
var toRight = function () {
for (let i = 0; i < leftlist.length; i++) {
if (leftlist[i].selected) {
right.appendChild(leftlist[i]);
i--;
}
}
}
var allToRight = function () {
for (let i = 0; i < leftlist.length; i++) {
right.appendChild(leftlist[i]);
i--;
}
}
# 表格隔行换色(tBodies、rows)
//这样也可以获得行数
//var tbody = document.getElementsByTagName("tbody")[0];
//var rows = tbody.getElementsByTagName("tr").length;
var tb = document.getElementById("table1");
var rows = tb.tBodies[0].rows.length;
for (let i = 0; i < rows; i++) {
if (i % 2 === 0) {
tb.tBodies[0].rows[i].style.backgroundColor = "gray";
} else {
tb.tBodies[0].rows[i].style.backgroundColor = "yellow";
}
}
# 省市联动(this.value)
let arr = [['陕西', '西安', '商洛', '延安', '安康'],
['河北', '石家庄', '廊坊', '秦皇岛', '雄安'],
['广东', '深圳', '珠海', '广州', '不知道']];
document.getElementById("sheng").onchange = function () {
let option = document.getElementById("shi");//不能直接使用innerHTML来赋值
option.innerHTML = "";//每次改变时要清空
for (let i in arr) {
if (arr[i][0] === this.value) {
for (let j = 1; j < arr[i].length; j++) {
option.innerHTML += "<option>" + arr[i][j] + "</option>";
}
}
}
}