# DOM
# 一、API、WebAPI 和 DOM 树
# 1. API、WebAPI
API:是给程序员提供的一种工具,帮我们实现某种功能(接口的方式实现)。
Web API:是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)。针对浏览器做交互效果。
Web API一般都有输入输出(函数的传参和返回值),Web API很多都是方法(函数) 如: alert('弹出')
# 2. DOM
文档对象模型:(Document Object Model,简称DOM),
是 W3C 组织推荐的处理可扩展标记语言(HTML或XML)的标准编程接口。
通过 DOM接口 可以改变网页内容、结果和样式。
一个页面就是一个文档,DOM 中使用 document 表示。
# 3. DOM 树
元素:页面中的所有标签都是元素,DOM 中使用 element 表示。
节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示。
DOM 把以上内容都看做是 对象。
# 二、获取元素
# 1. 通过 getElementById ID 获取元素
⑴ getElementById() 可以获取带有 ID 的元素对象。 get 获得 element 元素 by 通过 驼峰命名法 ⑵ 参数 id 是大小写敏感的字符串 ⑶ 返回值:返回一个匹配到 ID 的 DOM Element 对象。若在当前 Document 下没有找到,则返回 null。
var timer = document.getElementById('time');
console.log(timer);
console.log(typeof timer); // object
⑷ console.dir() 打印我们返回的元素对象 更好的查看里面的属性 和 方法
console.dir(timer);
# 2. 通过 getElementByTagName 标签名获取元素
- 知否知否,应是等你好久
- hello
使用 getElementByTagName() 方法可以返回带有指定标签的对象的集合。 ⑴ 返回的是 获取过来的元素对象的集合 以伪数组的形式存储的
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]);
⑵ 想要依次打印里面的元素对象可以采取遍历的方式
for (var i = 0; i < lis.length; i++){
console.log(lis[i]);
}
⑶ 如果页面中只有一个li 返回的还是伪数组的形式 ⑷ 如果页面没有数组 返回的是空的伪数组形式 (长度为0) ⑸ 还可以获取某个元素(父元素)内部所有指定标签的子元素
// element.getElementsByTagName('标签名');
// 注意:父元素必须是单个对象(必须指明是哪一个元素对象).获取的时候不包括父元素自己。
var ol = document.getElementsById('ol');
console.log(ol.getElementsByTagName('li'));
# 3. 通过 HTML5 新增的方法获取元素
⑴ document.getElementsByClassName('类名'); 根据类名返回元素对象集合
var boxs = document.getElementsByClassName('box');
console.log(boxs);
⑵ document.querySelector('选择器') 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 类选择器(.box) ID 选择器(#nav)
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav');
console.log(nav);
var li = document.querySelector('li');
console.log(li);
⑶ document.querySelectorAll('选择器') 返回指定选择器的所有元素对象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
# 4. 获取 body 和 html 元素
⑴ 获取 body 元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
⑵ 获取 html 元素
var htmlEle = document.documentElement;
console.log(htmlEle);
# 三、事件三要素和执行过程
# 1. 事件三要素
// 点击一个按钮,弹出对话框
// 1. 事件是有三部分组成: ①事件源 ②事件类型 ③事件处理程序
//⑴ 事件源 事件被触发的对象 谁(按钮)
var btn = document.getElementById('btn');
//⑵ 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
//⑶ 事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function() {
alert('点秋香');
}
# 2. 事件执行过程
执行事件步骤
// ①获取事件源
var div = document.querySelector('div');
// ②注册事件(绑定事件)
// div.onclick
// ③添加事件处理程序(采取函数赋值形式)
div.onclick = function() {
console.log('我被选中了');
}
# 四、操作元素
# 1. 操作元素-修改元素内容
<p>123</p>
元素可以不用添加事件
var p = document.querySelector('p');
p.innerHTML = getDate();
# 2. innerText 和 innerHTML 的区别
⑴ innerText 不识别 HTML 标签 非标准 去除空格和换行
var div = document.querySelector('div');
// div.innerText = '<strong>今天是:</strong> 2021';
⑵ innerHTML W3C标准 保留空格和换行
div.innerHTML = '<strong>今天是: </strong> 2021';
这两个属性都是可读写的 可以获取元素里面的内容
var p = document.querySelector('p');
console.log(p.innerText);
console.log(p.innerHTML);
# 3. 常用元素的属性操作
<button id="dlrb">迪丽热巴</button>
<img src="../img/dilireba.jpg" alt="">
var dlrb = document.getElementById('dlrb');
var img = document.querySelector('img');
dlrb.onclick = function() {
img.src = '../img/dilireba.jpg';
img.title = '迪丽热巴';
}
# 4. 操作元素-修改表单属性
表单里面的值 文字内容是通过 value 来修改的
input.value = '被点击了';
# 5. 操作元素-修改样式属性
⑴ element.style 行内样式操作 ⑵ element.className 类名样式操作 注意: ① js 里面的样式采取驼峰命名法 比如:fontSize、backgroundColor ② js 修改style 样式操作,产生的是行内样式, js 权重比较高
this.style.backgroundColor = 'pink'; // 改背景颜色
this.style.width = '300px';
# 五、获得、失去焦点和鼠标事件
# 1. 获得焦点事件 onfocus
text.onfocus = function () {
// 得到了焦点
console.log(this.value);
if (this.value === '手机') {
this.value = '';
}
# 2. 失去焦点事件 onblur
text.onblur = function () {
// 失去了焦点
if (this.value === '') {
this.value = '手机';
}
// 失去焦点 文字颜色变浅
this.style.color = '#999';
}
# 3. 使用 class Name 修改元素样式
⑴ 使用 element.style 获得修改元素样式 如果样式比较少 或者 功能简单的情况下使用
var test = document.querySelector('div');
test.onclick = function() {
⑵ 我们可以通过修改元素的className 更改元素的样式 适合于样式较多或者功能复杂的情况
// 让我们当前元素的类名改为了 change
this.className = 'change';
⑶ 如果想要保留原先的类名, 多类名选择器
this.className = 'first change';
# 4. 鼠标经过事件 onmouseover
trs[i].onmouseover = function() {
this.className = 'bg';
}
# 5. 鼠标离开事件 onmouseout
trs[i].onmouseout = function() {
this.className = '';
}
# 六、自定义属性
# 1. 设置移除自定义属性
- 获取属性值: (1) element.属性 获取内置属性值(元素本身自带的属性值)
console.log(div.id);
(2) element.getAttribute('属性'); 主要获得自定义的属性(标准) 程序员自定义的属性
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
- 设置元素属性: (1) element.属性 = '值';
div.id = 'test';
div.className = 'navs';
(2) element.setAttribute('属性', '值'); 主要针对于自定义属性
div.setAttribute('index', '2');
div.setAttribute('class', 'footer'); // class比较特殊,这里不是className
- 移除属性 removeAttribute(属性)
div.removeAttribute('index');
# 2. H5 自定义属性
H5 新增的获取自定义属性的方法 只获取date- 开头的 dataset 是一个集合里面存放了所有以data开头的自定义属性
console.log(div.dataset);
console.log(div.dataset.index);
如果自定义属性里面有多个 - 连接的单词,获取时用驼峰命名法
console.log(div.dataset.listName);
# 七、父子、兄弟节点
# 1. 节点操作之父节点:.parentNode
一般,节点拥有nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)这三个基本属性。 元素节点 nodeType 为1 属性节点 nodeType 为2 文本节点 nodeType 为3(文本节点包含文字、空格、换行等)
父节点 parentNode
var erweima = document.querySelector('.erweima');
得到的是离元素最近的父级节点(亲父亲) 如果找不到父节点就返回 null
console.log(erweima.parentNode);
# 2. 操作节点之子节点:.childNodes \ .children
DOM 提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
⑴ 子节点 childNodes获取所有的子节点 包含元素节点 文本节点等
console.log(ul.childNodes);
⑵ 子节点 children 获取所有的子元素节点 开发常用
console.log(ul.children);
# 3. 节点操作之子节点第一个元素和最后一个元素
var ol = document.querySelector('ol');
⑴ fristChild 第一个子节点 不管是文本节点还是元素节点
console.log(ol.firstChild);
console.log(ol.lastChild);
⑵ firstElementChild 返回第一个子元素节点 支持ie9以上
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
⑶ 实际开发的写法 无兼容性问题
console.log(ol.children[0]);
console.log(ol.children.length - 1);
# 4. 节点操作之兄弟节点
var div = document.querySelector('div'); ⑴ nextSibling 下一个兄弟节点 包含元素节点和文本节点等
console.log(div.nextSibling); // #text
⑵ previousSibling
console.log(div.previousSibling); // #text
⑶ nextElementSibling 得到下一个兄弟元素节点
console.log(div.nextElementSibling); // span
⑷ previousElementSibling
console.log(div.previousElementSibling); // null
# 5. 节点操作之创建和添加节点
⑴ 创建节点元素节点
var li = document.createElement('li');
⑵ 后面添加节点 node.appendChild(child) node父级 child子级 后面追加元素 类似于数组中的 push
var ul = document.querySelector('ul');
ul.appendChild(li);
⑶ 前面添加节点 node.insertBefore(child, 指定元素)
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
⑷ 想给页面添加一个新的元素;1.创建元素 2.添加元素
# 6. 删除节点: .removeChild(child)
⑴ 获取元素
var ul =document.querySelector('ul');
var btn = document.querySelector('button');
⑵ 删除元素(删除父级中的一个子节点) node.removeChild(child) ⑶ 点击删除按钮依次删除里面的元素
btn.onclick = function() {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
# 7. 节点操作之复制节点(克隆节点)
var ul = document.querySelector('ul');
⑴ node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签 不复制内容 ⑵ node.cloneNode(true); 括号为true 深拷贝 复制标签也复制内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
# 八、innerHTML 和 createElement 效率对比
⑴ document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致野蛮全部重绘 ⑵ innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘 ⑶ innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂 ⑷ createElement() 创建多个元素效率稍低一点点,但是结构更清晰
innerHTML (采取数组的形式拼接) 创建元素
var inner = document.querySelector('.innner');
var arr = [];
for (var i = 0; i <= 50; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// document.createElement() 创建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 50; i++) {
var a = document.createElement('a');
create.appendChild(a);
}