笔记十、JavaScript——用 JS 去操作浏览器 和 页面中的 HTML 元素(DOM)

402 阅读11分钟

用 JS 去操作浏览器 和 页面中的 HTML 元素(DOM)

1. DOM的基本概念

文档对象模型,其实就是操作 html 中标签的一些能力 比如:

  • 获取一个元素(标签)
  • 移除一个元素
  • 创建一个元素
  • 向页面添加一个元素
  • 给元素绑定一些事件
  • 获取元素的属性
  • 给元素添加一些css样式
  • 。。。 DOM 的核心 就是 document 对象

document 对象是 JS 内置的一个对象, 里边存储着专门用来操作元素的各种方法

DOM: 页面中的标签, 我们通过 JS 获取到以后, 就把这个对象叫做 DOM对象(DOM节点)

2. 获取元素

  1. 获取非常规元素
  • document.documentElement
  • document.head
  • document.body
// 1. html 标签
console.log(document.documentElement)
// 2. head 标签
console.log(document.head)
// 3. body 标签
console.log(document.body)
  1. 获取常规元素
  • 2.1 通过 ID 名获取标签 语法: document.getElementById('ID名')
  • 2.2 通过 class 名获取标签
    • 语法: document.getElementsByClassName('class名')
    • 注意: 因为页面中可能会有多个元素的 class 相同, 所以获取到的是一组元素,获取到后会把元素放在一个长得很像数组一样的 数据结构内, 但它并不是数组,我们管这种数据结构叫做 伪数组
    • 伪数组: 长得很像数组, 也是通过索引排列, 但是没有数组的方法
  • 2.3 通过标签名获取
    • 语法: document.getElementsByTagName('标签名')
    • 注意: 获取到的也是一个长得很像数组一样的数据结构, 其实就是获取到了一个伪数组,想要准确的获取到标签元素, 我们需要通过索引来帮助我们拿到
  • 2.4 按照选择器的形式来获取元素
    • 2.4.1 querySelector 这个方法允许我们像写 css 的时候的选择器一样获取标签
      • 注意: 这个方法只能获取到一个元素, 就是满足条件的第一个元素
      • 语法: document.querySelector('选择器')
    • 2.4.2 querySelectorAll, 该方法与 querySelector 选择器类似, 只不过会将所有满足条件的元素都获取到,也是放在一个伪数组内
      • 语法: document.querySelectorAll('选择器')

<div id="box">我是 ID 名为 box 的 div 标签</div>
<div class="box_cla">我是 class 为 box_cla 的 div 标签1</div>
<div class="box_cla">我是 class 为 box_cla 的 div 标签2</div>
<div class="box_cla">我是 class 为 box_cla 的 div 标签3</div>


// 2.1 获取到页面中 ID 为 box 的标签
var box = document.getElementById('box')
// console.log(box)  //<div id="box">我是 ID 名为 box 的 div 标签</div>

// 2.2 获取到页面中 class 名为 box_cla 的标签
var box_cla = document.getElementsByClassName('box_cla')
console.log(box_cla) //[div.box_cla,div.box_cla,div.box_cla]
// console.log(box_cla[0])
// console.log(box_cla[1])
// console.log(box_cla[2])

// 2.3 获取到页面中 标签名为 div 的标签
var divs = document.getElementsByTagName('div')
console.log(divs)
//[div#box, div.box_cla, div.box_cla, div.box_cla, box: div#box]

// 2.4.1 按照选择器的形式获取标签
var box2 = document.querySelector('.box_cla')
console.log(box2)
var box3 = document.querySelector('div')
console.log(box3)


// 2.4.2 
var box4 = document.querySelectorAll('.box_cla')
var box5 = document.querySelectorAll('div')

console.log(box4)
console.log(box5)

3. 操作属性

我们获取到元素以后, 可以直接操作 DOM 的属性, 然后直接把效果展示在页面

  1. 元素.innerHTML
  • 获取元素内部的 HTML 结构
  • 我们也可以直接给这个属性重新赋值, 达到修改页面的效果
  1. 元素.innerText
  • 获取元素内部的文本 (只能获取到文本, 获取不到 html 标签)
  • 我们也可以直接给这个属性重新赋值, 达到修改页面的效果

4. 元素属性

  1. 获取元素的某些属性
  • 语法: 元素.getAttribute('要查询的属性名')
  • 返回值: 查询到属性时返回对应的属性值, 没有查询到时直接返回 null
  1. 修改元素的某些属性
  • 语法: 元素.setAttribute('对应的属性名', '对应的属性值')
  • 注意: 如果元素没有对应的属性名, 那么相当于是新增一个属性
  1. 删除元素的某些属性 语法: 元素.removeAttribute('要删除的属性名')
<div class="box" a="QF001"></div>


// 0. 获取元素
// var oDiv = document.querySelector('.box')
var oDiv =document.getElementsByClassName('box')[0]

//1. 获取元素的某些属性
console.log(oDiv.getAttribute('a')) //QF001
console.log(oDiv.getAttribute('class')) //box
console.log(oDiv.getAttribute('b')) //null

//2. 修改元素的某些属性
oDiv.setAttribute('a', 'QF999')
oDiv.setAttribute('b', 'qwer')

//3. 删除元素的某些属性
oDiv.removeAttribute('class')

5. h5 自定义属性

  • data- 表示该属性是一个自定义属性
  • data- 后边的内容才是属性名, 当前案例中属性名为a, 不是 data-a
  • = 后边的内容是属性值 - 每一个 元素/DOM节点 天生自带一个属性, 叫做 dataset, 是一个类似对象的数据结构
<div data-a="100"></div>

// 0. 获取标签
var oDiv = document.querySelector('div')

// 1. 访问元素的 dataset 属性       查询
console.log(oDiv.dataset.a) // 100

// 2. 增加一个 h5 自定义属性
oDiv.dataset.age = 18   // 标签中没有这个自定义属性, 所以是新增
oDiv.dataset.a = 'QF666'    // 标签中有这个自定义属性, 相当于做了修改操作

// 3. 删除
delete oDiv.dataset.a

6. 获取元素样式

  • 语法: 元素.style.某个属性
  • 注意:
  1. 我们也可以给这个语法重新赋值, 达到修改元素样式的效果 (修改的是行内的样式)
  2. 这种语法获取到的元素样式, 只能获取到行内样式
  3. 获取非行内样式
  • 语法: window.getComputedStyle(元素).要查询的css属性
  • 注意: 这种方式获取到的属性 是只读的
    • 只读: 能获取到, 但是不允许修改
<style>
.box {
    width: 100px;
    height: 100px;
    /* background-color: skyblue; */
}
</style>

<div class="box" style="background-color: red;"></div>

 // 0. 获取元素
var oDiv = document.querySelector('.box')

// 1. 获取元素样式
console.log(oDiv.style.width) //返回啥也没有,空白
console.log(oDiv.style.height)
// onsole.log(oDiv.style.background-color)    // 直接这样写相当于写了一个 oDiv.style.background - color, 这是一个错误写法
console.log(oDiv.style['background-color']) // 中括号语法
console.log(oDiv.style.backgroundColor) // 驼峰命名

// 2. 设置元素样式
oDiv.style.width = 666 + 'px'
oDiv.style.backgroundColor = 'red'

//3. 获取非行内样式
console.log(window.getComputedStyle(oDiv).width)//100px
console.log(window.getComputedStyle(oDiv).backgroundColor)
// window.getComputedStyle(oDiv).width = 800 + 'px' // 不允许修改, 会有报错

7. className专门用来操作元素的 类名

  1. 语法: 元素.className 我们也可以给他重新赋值, 来达到修改元素的类名
<div class="box" style="background-color: red;"></div>

oDiv.className = 'new_box'
console.log(oDiv.className)//new_box
  1. 元素.classList
// 0. 获取元素
var oDiv = document.querySelector('.box')
// console.log(oDiv.className)
// oDiv.className = 'qwer'

// 2.1 获取
console.log(oDiv.classList)
//['box', 'new_box', value: 'box new_box']

// 2.2 新增
oDiv.classList.add('qwer')

// 2.3 删除
oDiv.classList.remove('new_box')

8. DOM 节点

  1. 元素节点(标签) 通过 getElementBy... 获取到的都是元素节点

  2. 文本节点(标签内的文字) 通过 getAttribute 获取到的都是属性节点

  3. 属性节点(标签上的属性)

通过 getAttribute

9. 获取子节点

  1. 获取某一节点下 所有的 子一级 节点, 获取到的是一个伪数组
    • 语法: 元素.childNodes
  2. 获取某一节点下 所有的 子一节 元素节点 获取到的是一个伪数组
    • 语法: 元素.children
  3. 获取某一节点下子一级的 第一个节点
    • 语法: 元素.firstChild
  4. 获取某一节点下子一级的 最`一个节点
    • 语法: 元素.lastChild
  5. 获取某一节点下子一级的 第一个元素节点
    • 语法: 元素.firstElementChild
  6. 获取某一节点下子一级的 最后一个元素节点
    • 语法: 元素.lastElementChild
<div>
    <p>你好</p>
    <span>测试文本</span>
    <h1>JS 是世界上最优美的语言</h1>
</div>


// 0. 获取元素
var oDiv = document.querySelector('div')

// 1. childNodes
console.log(oDiv.childNodes)
//[text, p, text, span, text, h1, text]
/**
 *  拿到的是一个伪数组, 里边有 7 个节点
 *      [0]: text  从 <div> 一直到 <p> 中间有一个换行和一堆空格     这是一个文本节点
 *      [1]: p      这个就是 p 标签, 他是第二个节点, 这是一个 元素节点
 *      [2]: text   从 </p> 一直到 <span> 中间有一个换行和一堆空格  这是一个文本节点
 *      ....
*/

// 2. children
console.log(oDiv.children)  // 这里只有 div 内部的标签[p, span, h1]

// 3. firstChild
console.log(oDiv.firstChild)    // #text

// 4. lastChild
console.log(oDiv.lastChild) // #text

// 5. firstElementChild
console.log(oDiv.firstElementChild)

// 6. lastElementChild
console.log(oDiv.lastElementChild)

10. 获取兄弟节点

  1. 获取对应的 下一个兄弟节点
  • 语法: 元素.nextSibling
  1. 获取对应的 上一个兄弟节点
  • 语法: 元素.previousSibling
  1. 获取对应的 下一个兄弟元素节点
  • 语法: 元素.nextElementSibling
  1. 获取对应的 上一个兄弟元素节点
  • 语法: 元素.previousElementSibling
<div>
    <p>你好</p>
    <span>测试文本</span>
    <h1>JS 是世界上最优美的语言</h1>
</div>


// 0. 获取元素
var oSpan = document.querySelector('span')

// 1. nextSibling
console.log(oSpan.nextSibling)  // #text

// 2. previousSibling
console.log(oSpan.previousSibling)  // #text

// 3. nextElementSibling
console.log(oSpan.nextElementSibling)   // h1

// 4. previousElementSibling
console.log(oSpan.previousElem
entSibling)   // p

11. 获取父节点与属性节点

  1. 父节点
  • 语法: 元素.parentNode
  1. 获取元素的所有属性节点
  • 语法: 元素.attributes
<div>
    <p>你好</p>
    <span>测试文本</span>
    <h1 id="h1_box" class="h1_box_cla" test="QF001" num="100">JS 是世界上最优美的语言</h1>
</div>
// 0. 获取节点1
var oH = document.querySelector('h1')

// 1. parentNode
console.log(oH.parentNode)

// 2. attributes
console.log(oH.attributes)
//{0: id, 1: class, 2: test, 3: num, id: id, class: class, test: test, num: num, length: 4}
console.log(oH.attributes[0])
//id="h1_box" 

12. 节点属性

  1. nodeType 节点类型
  • 节点中的一个属性 nodeType 能够区分当前节点是什么类型
  • 1 -> 元素节点
  • 2 -> 属性节点
  • 3 -> 文本节点
  1. nodeName 节点名称
  • 元素节点 -> 大写的标签名 (LI / UL / DIV)
  • 属性节点 -> text (属性名)
  • 文本节点 -> #text
  1. nodeValue 节点的值
  • 元素节点 -> 没有 nodeValue 也就会输出 null
  • 属性节点 -> 对应的属性值
  • 文本节点 -> 对应的文本内容
<ul text="我是 UL 的一个属性">
    <li>你好</li>
</ul>

// 0. 获取元素
var oUl = document.querySelector('ul')
//<ul text="我是 UL 的一个属性">...</ul>

// 1. 元素节点
var eleNode = oUl.firstElementChild
//<li>...</li>

// 2. 属性节点
var attrNode = oUl.attributes[0]
//text="我是 UL 的一个属性"

// 3. 文本节点
var textNode = oUl.firstChild
//#text

// 1. nodeType
console.log('元素节点: ', eleNode.nodeType)
console.log('属性节点: ', attrNode.nodeType)
console.log('文本节点: ', textNode.nodeType)
/*元素节点:  1
属性节点:  2
文本节点:  3
*/

// 2. nodeName
console.log('元素节点: ', eleNode.nodeName)
console.log('属性节点: ', attrNode.nodeName)
console.log('文本节点: ', textNode.nodeName)

/*元素节点:  LI
属性节点:  text
文本节点:  #text
*/

// 3. nodeValue
console.log('元素节点: ', eleNode.nodeValue)
console.log('属性节点: ', attrNode.nodeValue)
console.log('文本节点: ', textNode.nodeValue)
/*
元素节点:  null
属性节点:  我是 UL 的一个属性
文本节点: 
*/

13. 操作 DOM 节点(常规意义上 '增删改查')

在向页面增加一个节点, 首先, 你应该先 有一个节点

  • 操作分类:

1. 在 JS 中创建一个节点

  • 语法: document.createElement('要创建的标签名')

2. 向页面增加一个节点

  • 语法1: 元素.appendChild(要添加的节点)
    • 作用: 向元素的末尾追加一个节点
  • 语法2: 元素.insertBefore(要插入的节点, 插入到那个节点的前面)
    • 注意: 两个参数都是必填项,第二个参数传递正常节点时, 代表插入到这个节点的前面,第二个参数传递的是 null 时, 表示插入到 "元素" 的末尾
<div class="box">
    <p>我是通过 HTML 手写出来的 P 标签</p>
</div>


// 0. 获取元素
var myDiv = document.getElementsByClassName('box')[0]
var oP = document.querySelector('p')

// 1.1 创建一个元素节点
var oDiv = document.createElement('div')
var oSpan = document.createElement('span')

// 1.2 创建一个文本节点  (了解)
var oText = document.createTextNode('我是通过 JS 创建出来的文本节点')

// 1.3 将刚才创建的文本节点, 添加到元素节点内   元素.appendChild(要添加的节点)
oDiv.appendChild(oText)
oSpan.innerText = '我是通过 innerText 直接赋值的字符串'

// 2. 向页面中增加一个节点
// 2.1 元素.appendChild(要添加的节点)
myDiv.appendChild(oDiv)
myDiv.appendChild(oSpan)

// 2.2 元素.insertBefore(要插入的节点, 插入到那个节点的前面)
myDiv.insertBefore(oDiv, oP)    // 将我们通过 JS 创建的 div 标签, 插入到页面的 P 标签前边
myDiv.insertBefore(oSpan, null) // 第二个参数传递 null 代表插入到 '元素' 的末尾

3. 删除页面某一个节点

  • 语法1: 父节点.removeChild('要删除的子节点')
  • 语法2: 节点.remove()

4.修改页面的某一个节点

  • 语法: 父节点.replaceChild('新节点', '旧节点/要被修改的节点')
  • 作用: 将页面中的某一个节点 做一个替换

5.获取页面的某一个节点

之前获取元素的方法

6.克隆一个节点 (把一个节点复制出一个一摸一样的)

  • 语法: 节点.cloneNode(参数)
  • 参数:
    • 默认是 false, 表示不克隆后代节点
    • 选填是 true, 表示克隆后代节点
<div class="box">
    <p>我是第一个 P 标签</p>
    <p>我是第二个 P 标签</p>
</div>

// 0. 获取节点
var box = document.querySelector('.box')
var oP = document.querySelector('p')    // 满足条件的第一个 p 标签

// 3. 删除页面某一个节点
box.removeChild(oP)
//box.remove()

// 4. 修改页面的某一个节点
/var oSpan = document.createElement('span')  // 创建一个 span 标签
oSpan.innerText = '我是通过 JS 创建出来的 SPAN 标签'    // 给 span 标签添加文字
box.replaceChild(oSpan, oP) // 用刚刚创建出来的 span 标签, 替换 原本的 p 标签

// 6. 克隆一个节点
//var cloneP = oP.cloneNode() // 克隆出来一个和 oP 这个节点 一摸一样的 新节点      不包含后代节点
var cloneP = oP.cloneNode(true) // 克隆出来一个和 oP 这个节点 一摸一样的 新节点     包含后代节点
box.appendChild(cloneP)
console.log(box)

/**
 *  box.appendChild(oP) 
 * 
 *      错误理解: 将 oP 这个节点, 添加到 box 的末尾, 然后页面就有 3 个 P标签了
 * 
 *      正确理解: 将 oP 这个节点, 添加到 box 的末尾
 *                  因为 DOM 节点在页面中只会具有一个(核心)
 *                  所以这一步相当于将 原本排列在 box 内部第一个的 p 标签, 移动到了 box 内部的 最后一个
*/

14. 获取非行内样式(了解)

  • 语法: window.getComputedStyle(元素).要查询的CSS属性名
  • IE 的语法: 元素.currentStyle.要查询的CSS属性名 (了解)

15.获取元素偏移量

获取元素在页面上相对参考父级的左边和上边的距离 (要求会背, 因为后续会有项目, 需要使用)

参考父级:其实就是假设 你要给一个元素 '绝对定位', 他是根据谁来进行定位, 那么这个元素的偏移量参考父级就是谁

  1. 元素.offsetParent 获取元素的相对父级
  2. 元素.offsetLeft 获取元素距离左边的距离
  3. 元素.offsetTop 获取元素距离顶部的距离
//html:
<div class="box1">
    <div class="box2"></div>
</div>

//css:
<style>
    * {
        padding: 0;
        margin: 0;
    }
    .box1 {
        width: 400px;
        height: 400px;
        background-color: pink;
        position: relative;
        top: 20px;
        left: 20px;
    }
    .box2 {
        width: 100px;
        height: 100px;
        background-color: skyblue;
        position: absolute;
        left: 100px;
        top: 200px;
    }
</style>

// 0. 获取元素
var box2 = document.querySelector('.box2')

// 1. 元素.offsetParent
console.log(box2.offsetParent)

// 2. 元素.offsetLeft
console.log('offsetLeft', box2.offsetLeft)

// 3. 元素.offsetTop
console.log('offsetTop', box2.offsetTop)

16. 获取元素尺寸与浏览器窗口尺寸

1. 获取元素尺寸 (元素的占地面积)

  • 语法1: 元素.offsetWidth 元素.offsetHeight
  • 语法2: 元素.clientWidth 元素.clientHeight
  • 区别:
  • offsetXXX -> 实际的宽度/高度 + padding + border
  • clientXXX -> 实际的宽度/高度 + padding
<style>
    * {
        padding: 0;
        margin: 0;
    }

    div {
        width: 500px;
        height: 6000px;
        background-color: pink;
        padding: 50px;
        border: 10px solid black;
        margin: 50px;
    }
</style>

<div></div>

// 1. offsetXXX
console.log('oDiv.offsetWidth', oDiv.offsetWidth)
console.log('oDiv.offsetHeight', oDiv.offsetHeight)

console.log('手动分割线===================')

// 2. clientXXX
console.log('oDiv.clientWidht', oDiv.clientWidth)
console.log('oDiv.clientHeight', oDiv.clientHeight)

获取元素尺寸.jpg

2. 获取浏览器窗口尺寸

  1. window.innerXXX -> 计算的时候 会包含浏览器的滚动条
  2. document.documentElement.clientXXX -> 计算的时候 不会计算滚动条 (只计算浏览器的可视区域)