# 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。

2022-1-13

var timer = document.getElementById('time');
console.log(timer);
console.log(typeof timer);   // object

⑷ console.dir() 打印我们返回的元素对象 更好的查看里面的属性 和 方法

console.dir(timer);

# 2. 通过 getElementByTagName 标签名获取元素

  • 知否知否,应是等你好久
  1. 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 新增的方法获取元素

盒子1
盒子2

⑴ 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. 事件执行过程

123

执行事件步骤

// ①获取事件源 
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. 获取属性值: (1) element.属性 获取内置属性值(元素本身自带的属性值)
console.log(div.id);

(2) element.getAttribute('属性'); 主要获得自定义的属性(标准) 程序员自定义的属性

console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
  1. 设置元素属性: (1) element.属性 = '值';
div.id = 'test';
div.className = 'navs';

(2) element.setAttribute('属性', '值'); 主要针对于自定义属性

div.setAttribute('index', '2');
div.setAttribute('class', 'footer');  // class比较特殊,这里不是className
  1. 移除属性 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);
}