标签归档:DOM

DOM- 网页特效

1. 滚动事件和加载事件

1. 滚动事件scroll

  1. 当页面进行滚动时触发的事件

  2. 很多网页需要检测用户把页面滚动到某个区域后做一些处理, 比如固定导航栏,比如返回顶部

  3. 监听整个页面滚动给 window 或 document 加

  4. 监听某个元素的内部滚动直接给某个元素加即可

// 监听整个页面滚动
// 1. 滚动事件 监听整个页面滚动 固定导航/返回顶部
window.addEventListener('scroll', function () {
console.log(1)
})
let num1 = document.querySelector('.box')
num1.addEventListener('scroll', function () {
console.log(2)
})

2. 加载事件load

  1. 加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件

  2. 有些时候需要等页面资源全部处理完了做一些事情

  3. 老代码喜欢把 script 写在 head 中,这时候直接找 dom 元素找不到

  4. 注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件

监听页面所有资源加载完毕:

// 监听整个页面资源给 window 加
// 2. 加载事件 监听页面资源加载完毕才执行load事件
// 也可以针对别的资源绑定load事件
// 把js写在head上面 导致dom元素找不到 用load事件
let n1 = document.querySelector('.box')
window.addEventListener('load', function () {
    console.log(11)
})
​

3. 加载事件DOMContentLoaded

  1. 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表 、图像等完全加载

监听页面DOM加载完毕:

// 给 document 添加 DOMContentLoaded 事件
// 2. 加载事件 等HTML文档加载完后再加载 无需等样式 图片就可以加载
document.addEventListener('DOMContentLoaded', function () {
    console.log(3)
})
​

2. scroll家族

  1. 我们想要页面滚动一段距离,比如100px,就让某些元素显示隐藏, 就可以使用scroll 来检测页面滚动的距离~

  2. 获取宽高: 获取元素的内容总宽高(不包含滚动条)返回值不带单位

  3. scrollWidth和scrollHeight

获取位置:

  1. 获取元素内容往左、往上滚出去看不到的距离

  2. scrollLeft和scrollTop

  3. 这两个属性是可以修改的

// 1. scroll家族 (了解)
let num1 = document.querySelector('.box')
// 当前宽度 不包含滚动条
console.log(num1.scrollWidth)
// 内容高度
console.log(num1.scrollHeight)
​
// 2. 被卷去的头部和左侧
num1.addEventListener('scroll', function () {
    console.log(this.scrollTop)
})
​
开发中,我们经常检测页面滚动的距离,比如页面滚动100像素,就可以显示一个元素,或者固定一个元素
  1. document.documentElement HTML 文档返回对象为HTML元素

// 3. 检测页面滚动的距离
window.addEventListener('scroll', function () {
    // 返回HTML元素距离
    console.log(document.documentElement.scrollTop)
    // 可以给值/修改 但不要带单位
    document.documentElement.scrollTop = 200
})
​
  1. 被卷去的头部或者左侧用那个属性?是否可以读取和修改?

  1. 可以读取,也可以修改(赋值)

页面滚动显示返回顶部按钮
//需求:当页面滚动500像素,就显示返回顶部按钮,否则隐藏, 同时点击按钮,则返回顶部
//①:用到页面滚动事件
//②:检测页面滚动大于等于100像素,则显示按钮
//③:点击按钮,则让页面的scrollTop 重置为 0
<div class="content"></div>
<div class="backtop">
    <img src="./images/close2.png" alt="">
    <a href="javascript:;"></a>
</div>
let btn = document.querySelector('.backtop')
// 1. 页面滚动事件
window.addEventListener('scroll', function () {
    // 2. 页面检测滚动距离
    let num1 = document.documentElement.scrollTop
    // 3. 判断显示隐藏
    // 如果大于200 就显示 小于隐藏
    if (num1 >= 200) {
        btn.style.display = 'block'
    } else {
        btn.style.display = 'none'
    }
})
​
// 4. 点击链接返回顶部
btn.children[1].addEventListener('click', function () {
    document.documentElement.scrollTop = 0
})
​

3. offset家族

  1. 使用场景: 前面案例滚动多少距离,都是我们自己算的,最好是页面 滚动到某个元素,就可以做某些事

  2. 简单说,就是通过js的方式,得到元素在页面中的位置 这样我们可以做,页面滚动到这个位置,就可以返回 顶部的小盒子显示…

获取宽高:
  1. 获取元素的自身宽高、包含元素自身设置的宽高、padding、border, offsetWidth和offsetHeight

// 1. offset家族 宽高 (了解)
let num1 = document.querySelector('.box')
// 盒子大小 = 盒子本身宽高 + padding + border
// 盒子多大 offset就多大
console.log(num1.offsetWidth)
console.log(num1.offsetHeight)
​
获取位置:
  1. 获取元素距离自己定位父级元素的左、上距离

  2. offsetLeft和offsetTop 注意是只读属性

// 2. 位置以带定位的父级 如果没有就以左上角为准
console.log(num1.offsetTop)
console.log(num1.offsetLeft)
​
仿京东固定导航栏案例
//当页面滚动到秒杀模块,导航栏自动滑入,否则滑出
//①:用到页面滚动事件
//②:检测页面滚动大于等于 秒杀模块的位置 则滑入,否则滑出
<div class="header">我是顶部导航栏</div>
<div class="content">
    <div class="sk">秒杀模块</div>
</div>
<div class="backtop">
    <img src="./images/close2.png" alt="">
    <a href="javascript:;"></a>
</div>
<script>
let box = document.querySelector('.sk')
let head = document.querySelector('.header')
// 1.页面滚动事件
window.addEventListener('scroll', function () {
// 2.检测页面滚动距离 >= 秒杀模块的offsetTop 则划入
    if (document.documentElement.scrollTop >= box.offsetTop) {
// 3.如果大于则显示 小于则-80px
        head.style.top = '0px'
    } else {
        head.style.top = '-80px'
    }
})
</script>
电梯导航案例
<!--需求:点击可以页面调到指定效果
①:点击当前 小导航,当前添加active,其余移除active
②:得到对应 内容 的 offsetTop值
③:让页面的 scrollTop 走到 对应 内容 的 offsetTop-->
<div class="aside">
    <div class="item active">男装/女装</div>
    <div class="item">儿童服装/游乐园</div>
    <div class="item">电子产品</div>
    <div class="item">电影/美食</div>
</div>
<div class="content">
    <div class="neirong content1">男装/女装</div>
    <div class="neirong content2">儿童服装/游乐园</div>
    <div class="neirong content3">电子产品</div>
    <div class="neirong content4">电影/美食</div>
</div>
<script>
let btn = document.querySelectorAll('.item')
let btn1 = document.querySelectorAll('.neirong')
// 1. 点击谁谁添加类
for (let num1 = 0; num1 < btn.length; num1++) {
    btn[num1].addEventListener('click', function () {
        document.querySelector('.aside .active').classList.remove('active')
        this.classList.add('active')
        // 2. 右侧内容跟随走动
        // 让页面滚动对应offsettop值位置
        document.documentElement.scrollTop = btn1[num1].offsetTop
    })
}
</script>

4. client家族

  1. 获取宽高:获取元素的可见部分宽高(不包含边框,滚动条等), clientWidth和clientHeight

  2. 获取位置: 获取左边框和上边框宽度, clientLeft和clientTop 注意是只读属性

let num1 = document.querySelector('.box')
// 可见区域的宽高 不包含滚动条 边框...
console.log(num1.clientWidth)
console.log(num1.clientHeight)
// 3. client TOP/Left (了解) 就是边框的宽高
console.log(num1.clientTop)
console.log(num1.clientLeft)
​
会在窗口尺寸改变的时候触发事件:resize
// 2. resize事件 当窗口变化时触发的事件
window.addEventListener('resize', function () {
    // 检测屏幕宽度
    console.log(document.documentElement.clientWidth)
    // 检测页面的宽度不同而改变颜色
    let num2 = document.documentElement.clientWidth
    if (num2 >= 1000) {
        document.body.style.backgroundColor = 'skyblue'
    } else if (num2 >= 850) {
        document.body.style.backgroundColor = 'pink'
    } else {
        document.body.style.backgroundColor = 'green'
    }
})
​

5. 三大家族的区别

offset家族

  1. 获取元素自身大小:包括自身设置的宽高、padding、border

  1. 获取元素距离定位父级的左和上距离 只读属性

scroll家族

  1. 获取元素内容的总大小

  1. 获取元素向左向上滚出去看不见的距离 可读写属性

client家族

  1. 获取元素可见区域的大小

  1. 获取元素左、上边框距离 只读属性 

6. 轮播图案例

需求①:小图标鼠标经过事件

需求② :大图片跟随变化

需求③:右侧按钮播放效果

需求④:解决一个BUG

需求⑤:左侧按钮播放效果

需求⑥: 因为左侧按钮和右侧按钮里面有大量相同的操作,可以抽取封装一个函数 common

需求⑦:开启定时器需求

需求⑧: 鼠标经过停止定时器 (清除定时器) 鼠标离开开启定时器 (开启定时器) 

<div class="main">
    <div class="slides">
        <ul>
            <li class="active"><a href="#"><img src="./images/b_01.jpg" alt="第1张图的描述信息"></a></li>
            <li><a href="#"><img src="./images/b_02.jpg" alt="第2张图的描述信息"></a></li>
        </ul>
        <div class="extra">
            <h3>第1张图的描述信息</h3>
            <a class="prev" href="javascript:;"></a>
            <a class="next" href="javascript:;"></a>
        </div>
    </div>
    <div class="indicator">
        <ul>
            <li class="active">
                <img src="images/s_01.jpg">
                <span class="mask"></span>
                <span class="border"></span>
            </li>
            <li>
                <img src="images/s_02.jpg">
                <span class="mask"></span>
                <span class="border"></span>
            </li>
        </ul>
    </div>
</div>
let xl = document.querySelectorAll('.indicator li')
let dl = document.querySelectorAll('.slides ul li')
let text = document.querySelector('.extra h3')
let btn = document.querySelector('.next')
let btn1 = document.querySelector('.prev')
let main = document.querySelector('.main')
for (let num1 = 0; num1 < xl.length; num1++) {
    // 1.鼠标经过小图片变高亮
    xl[num1].addEventListener('mouseenter', function () {
        document.querySelector('.indicator .active').classList.remove('active')
        this.classList.add('active')
    // 2. 鼠标经过当前小图片后大图片变化
    // 利用opacity实现淡入淡出效果
        document.querySelector('.slides .active').classList.remove('active')
        dl[num1].classList.add('active')
    // 3. 鼠标经过图片 文字改变
        text.innerHTML = `第${num1 + 1}张图的描述信息`
​
    // 6. 解决Bug 如果鼠标经过后 再次点击播放会乱序
    // 让index重新赋值为 当前鼠标经过索引号
        index = num1
    })
}
​
// 4. 右侧按钮点击事件
// 全局变化量变量 不断自增 控制器/给左右按钮同时使用
let index = 0
btn.addEventListener('click', function () {
    index++  // 变量点击后自增
​
    // 1. 解决点击最后一张后报错 等于10之后index为0
    if (index == 10) {
        index = 0
    }
    // 2. // 10 10 余 0
    // index = index % 10 
    fn()
})
​
// 5.左侧按钮点击事件
btn1.addEventListener('click', function () {
    index--
    if (index < 0) {
        index = 9
    }
    // 10 + -1 = 9 % 10 余 1
    // index = (10 + index) % xl.length
    fn()
})
​
// 6. 因为左右按钮有大量相同代码 可以封装成函数 然后调用
function fn() {
    // 选出 index 大/小图片 排它思想
    document.querySelector('.indicator .active').classList.remove('active')
    xl[index].classList.add('active')
    document.querySelector('.slides .active').classList.remove('active')
    dl[index].classList.add('active')
    text.innerHTML = `第${index + 1}张图的描述信息`
}
​
// 7. 开启轮播定时器
let timer = setInterval(function () {
// 自动调用右侧按钮点击事件
    btn.click()
}, 800)
​
// 如果不清除 点击哪个就不会停止
// 8.鼠标经过清除定时器
main.addEventListener('mouseenter', function () {
    clearInterval(timer)
})
​
// 9. 鼠标经过开启定时器
main.addEventListener('mouseleave', function () {
// 直接再开启一个定时器 不要重新赋值了
    timer = setInterval(function () {
        btn.click()
    }, 800)
})
​

 

DOM节点类型——12种DOM节点类型

前面的话

DOM是javascript操作网页的接口,全称为文档对象模型(Document Object Model)。它的作用是将网页转为一个javascript对象,从而可以使用javascript对网页进行各种操作(比如增删内容)。浏览器会根据DOM模型,将HTML文档解析成一系列的节点,再由这些节点组成一个树状结构。DOM的最小组成单位叫做节点(node),文档的树形结构(DOM树)由12种类型的节点组成。

总括

一般地,节点至少拥有nodeType、nodeName和nodeValue这三个基本属性。节点类型不同,这三个属性的值也不相同

nodeType

nodeType属性返回节点类型的常数值。不同的类型对应不同的常数值,12种类型分别对应1到12的常数值

元素节点              Node.ELEMENT_NODE(1)
属性节点              Node.ATTRIBUTE_NODE(2)
文本节点              Node.TEXT_NODE(3)
CDATA节点              Node.CDATA_SECTION_NODE(4)
实体引用名称节点       Node.ENTRY_REFERENCE_NODE(5)
实体名称节点          Node.ENTITY_NODE(6)
处理指令节点          Node.PROCESSING_INSTRUCTION_NODE(7)
注释节点              Node.COMMENT_NODE(8)
文档节点              Node.DOCUMENT_NODE(9)
文档类型节点          Node.DOCUMENT_TYPE_NODE(10)
文档片段节点          Node.DOCUMENT_FRAGMENT_NODE(11)
DTD声明节点            Node.NOTATION_NODE(12)

DOM定义了一个Node接口,这个接口在javascript中是作为Node类型实现的,而在IE8-浏览器中的所有DOM对象都是以COM对象的形式实现的。所以,IE8-浏览器并不支持Node对象的写法

//在标准浏览器下返回1,而在IE8-浏览器中报错,提示Node未定义
console.log(Node.ELEMENT_NODE);//1

nodeName

nodeName属性返回节点的名称

nodeValue

nodeValue属性返回或设置当前节点的值,格式为字符串

接下来,将按照节点类型的常数值对应顺序,从1到12进行详细说明

 

元素节点

元素节点element对应网页的HTML标签元素。元素节点的节点类型nodeType值是1,节点名称nodeName值是大写的标签名,nodeValue值是null

以body元素为例

// 1 'BODY' null
console.log(document.body.nodeType,document.body.nodeName,document.body.nodeValue)
console.log(Node.ELEMENT_NODE === 1);//true

 

特性节点

元素特性节点attribute对应网页中HTML标签的属性,它只存在于元素的attributes属性中,并不是DOM文档树的一部分。特性节点的节点类型nodeType值是2,节点名称nodeName值是属性名,nodeValue值是属性值

现在,div元素有id=”test”的属性

<div id="test"></div>
<script>
var attr = test.attributes.id;
//2 'id' 'test'
console.log(attr.nodeType,attr.nodeName,attr.nodeValue)
console.log(Node.ATTRIBUTE_NODE === 2);//true    
</script>

 

文本节点

文本节点text代表网页中的HTML标签内容。文本节点的节点类型nodeType值是3,节点名称nodeName值是’#text’,nodeValue值是标签内容值

现在,div元素内容为’测试’

<div id="test">测试</div>
<script>
var txt = test.firstChild;
//3 '#text' '测试'
console.log(txt.nodeType,txt.nodeName,txt.nodeValue)
console.log(Node.TEXT_NODE === 3);//true    
</script>

 

CDATA节点

CDATASection类型只针对基于XML的文档,只出现在XML文档中,表示的是CDATA区域,格式一般为

<![CDATA[
]]>

该类型节点的节点类型nodeType的值为4,节点名称nodeName的值为’#cdata-section’,nodevalue的值是CDATA区域中的内容

 

实体引用名称节点

实体是一个声明,指定了在XML中取代内容或标记而使用的名称。 实体包含两个部分, 首先,必须使用实体声明将名称绑定到替换内容。 实体声明是使用 <!ENTITY name “value”> 语法在文档类型定义(DTD)或XML架构中创建的。其次,在实体声明中定义的名称随后将在 XML 中使用。 在XML中使用时,该名称称为实体引用。

实体引用名称节点entry_reference的节点类型nodeType的值为5,节点名称nodeName的值为实体引用的名称,nodeValue的值为null

//实体名称
<!ENTITY publisher "Microsoft Press">
//实体名称引用
<pubinfo>Published by &publisher;</pubinfo>

 

实体名称节点

上面已经详细解释过,就不再赘述

该节点的节点类型nodeType的值为6,节点名称nodeName的值为实体名称,nodeValue的值为null

 

处理指令节点

处理指令节点ProcessingInstruction的节点类型nodeType的值为7,节点名称nodeName的值为target,nodeValue的值为entire content excluding the target

 

注释节点

注释节点comment表示网页中的HTML注释。注释节点的节点类型nodeType的值为8,节点名称nodeName的值为’#comment’,nodeValue的值为注释的内容

现在,在id为myDiv的div元素中存在一个<!– 我是注释内容 –>

<div id="myDiv"><!-- 我是注释内容 --></div>
<script>
var com = myDiv.firstChild;
//8 '#comment' '我是注释内容'
console.log(com.nodeType,com.nodeName,com.nodeValue)
console.log(Node.COMMENT_NODE === 8);//true    
</script>

 

文档节点

文档节点document表示HTML文档,也称为根节点,指向document对象。文档节点的节点类型nodeType的值为9,节点名称nodeName的值为’#document’,nodeValue的值为null

<script>
//9 "#document" null
console.log(document.nodeType,document.nodeName,document.nodeValue)
console.log(Node.DOCUMENT_NODE === 9);//true    
</script>

 

文档类型节点

文档类型节点DocumentType包含着与文档的doctype有关的所有信息。文档类型节点的节点类型nodeType的值为10,节点名称nodeName的值为doctype的名称,nodeValue的值为null

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var nodeDocumentType = document.firstChild;
//10 "html" null
console.log(nodeDocumentType.nodeType,nodeDocumentType.nodeName,nodeDocumentType.nodeValue);
console.log(Node.DOCUMENT_TYPE_NODE === 10);
</script>
</body>
</html>

 

文档片段节点

文档片段节点DocumentFragment在文档中没有对应的标记,是一种轻量级的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。该节点的节点类型nodeType的值为11,节点名称nodeName的值为’#document-fragment’,nodeValue的值为null

<script>
var nodeDocumentFragment = document.createDocumentFragment();    
//11 "#document-fragment" null
console.log(nodeDocumentFragment.nodeType,nodeDocumentFragment.nodeName,nodeDocumentFragment.nodeValue);
console.log(Node.DOCUMENT_FRAGMENT_NODE === 11);//true
</script>

 

DTD声明节点

DTD声明节点notation代表DTD中声明的符号。该节点的节点类型nodeType的值为12,节点名称nodeName的值为符号名称,nodeValue的值为null

 

最后

在这12种DOM节点类型中,有一些适用于XML文档,有一些是不常用的类型。