前言
- Web API :是一套操作 网页内容(DOM) 与 浏览器窗口(BOM) 的 对象 ;
- API:就是一些预定义好的方法,这些方法可以实现特定的功能,开发人员可以直接使用;
- Web API:浏览器提供了一套操作网页和浏览器的方法,通过这些方法可以轻松的操作元素和浏览器;
- 复杂数据类型 用 const 声明:复杂数据类型 放在 堆 里面,栈 里面存放的 地址 指向 堆 里面存放的 数据 ,变 的只是 堆 里面存放的 数据 ,存放数据的 地址 不变;
- 变量名 ➡ 栈地址 ➡ 堆数据;
- 解释:
const实际上指的并不是变量的值不得改动,
其实说的是变量指向的那个内存空间中保存的数据不得改变
简单数据类型是将值保存在栈中,所以用const声明简单数据类型时,值不得改变,相当于常量
而复杂数据类型是将引用地址保存在栈中,具体的值保存在堆中
那么用const声明复杂数据类型时,比如对象,数组时,只能保证的是这个地址是固定不变的
堆中保存的数据是不是可变的,就无法保证了
一、❗❗ DOM(文档对象模型)
Document Object Model
--- 文档对象模型;- 定义:是HTML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以在从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将 web 页面和程序语言连接起来。进而操作网页的内容,实现各种功能和部分特效。
1.1 DOM树 和 DOM对象
1.1.1 DOM树
- DOM树:一种树状结构,把页面标签按照树状结构排列好,结构更加清晰;
- 每个DOM对象中都有表示层级关系的属性,利用这些属性把所有的DOM对象联系在一起,就形成一个树状结构,称为DOM树;
- 作用:文档树直观的 体现了 标签与标签 之间 的 关系
1.1.2 DOM对象
- DOM对象 : 浏览器根据htm标签自动生成的JS对象;
- 浏览器把网页内容翻译成一个个的对象,把 网页内容 的 特征 翻译成 对象 的属性;
- document对象:是DOM里提供的一个对象(DOM里面最大的对象 )
- 它提供的属性和方法都是 用来访问 和 操作 网页内容的
1.2 获取DOM对象
-
打印对象:打印元素的时候,以对象的形式展现
jsconsole.dir(对象);
1.2.1 ❗❗ 根据CSS选择器来获取DOM元素
- 1️⃣ 选择匹配的 第一个 元素
-
语法 :
jsdocument.querySelector('css选择器')
-
代码展示:
jsconst li = document.querySelector('ul li')
-
参数 :小括号里面 包含 一个 或 多个 有效的css选择器 字符串(引号)
-
返回值 :
- css选择器 匹配的 第一个元素 ,一个 HTMLElement 对象
- ⚠ 如果 没有匹配 到元素就是 null
- ⚠ 注意:必须加引号
-
- 2️⃣ 选择匹配的 多个 元素
-
语法 :
jsdocument.querySelectorAll('css选择器')
-
代码展示:
jsconst lis = document.querySelectorAll('li') //NodeList[li, li, li]
-
参数 :小括号里面 包含 一个 或 多个 有效的CSS选择器 字符串
-
返回值 :
- CSS选择器匹配的 NodeList 对象集合
- 如果页面 不存在 这个 元素 ,得到的就是一个 空的伪数组
- 把 所有 匹配的 元素 放到 NodeList🟨伪数组🟨 里面 返回
- 有长度,有索引
- 没有push(),pop()等数组方法
- 想要得到里面的每一个对象,则需要遍历获得
-
1.2.2 获取HTML、body、head、title
js
document.documentElement --- html
document.body --- body
document.head --- head
document.title --- title
1.2.3 ❌其他获取元素的方式
-
1️⃣根据 id 获取元素
*jsdocument.getElementById('id名称')
- 注意:
- id名称不加 #
- 注意:
-
2️⃣根据 标签 获取 一类 元素
*jsdocument.getElementsByTagName('标签名称')
- 注意:
- getElementsByTagName
- 返回值:伪数组
- 注意:
-
3️⃣根据 类名 获取元素
*jsdocument.getElementsByClassName('类名')
- 注意:
- 类名不加 .
- getElementsByClassName
- 返回值:伪数组
- 注意:
1.3 操作元素内容
1.3.1 对象.innerText 属性
- 将 元素 文本内容 添加/更新 到 任意标签 位置
- 显示 纯文本 ,不解析标签
- 见代码展示
1.3.2 对象.innerHTML 属性
-
将 元素内容 添加/更新 到任意标签位置
- 包括标签、文本、注释
-
会解析标签,多标签建议使用模板字符串
-
⚠ 既要保留原来内容又要添加新内容,采用 字符串拼接 的方式
*jsinnerHTML += '要添加的文本'
-
见代码展示
代码展示:
js
<div class="box"> 天地不仁以万物为刍狗!!! </div>
<strong>
const box = document.querySelector('.box')
// 对象.innerText 属性
box.innerText = '扶我起来,我还能干!!!'
box.innerText = '<strong>扶我起来,我还能干!!!</strong>'
// 对象.innerHTML 属性
box.innerHTML = '扶我起来,我还能干!!!'
box.innerHTML = '<strong>扶我起来,我还能干!!!</strong>'
</strong>
- ⚠innerText 和 innerHTML 的区别
-
innerText
- 只能 获取 元素文本,无法 获取 标签
- ⚠ 在获取文本的时候,包含 子元素 的 文本
-
innerHTML
- 可以 获取对象里面的所有 文本+标签
-
代码展示:
js<body> <div> 123 <p>456 <span>789</span> </p> </div> <script> console.log(document.querySelector('div').innerText); console.log(document.querySelector('div').innerHTML); </script> </body>
-
1.3.3 获取表单元素文本
- 语法: 元素.value
- 获取 输入的字符长度 :元素.value.length
- ⚠ 获取 button 的文本依然使用 innerHTML(button双标签)
- 拓展:
- ⚠ 元素.value.trim() - 去除字符串 左右两侧 的空格
1.4 操作元素属性
1.4.1 操作 元素 属性
- 语法 :元素.属性 = '值'
-
代码展示:
js<img src="./images/1.webp" alt=""> //随机数函数 function getRandom(N, M) { return Math.floor(Math.random() * (M- N + 1)) + N } //获取图片对象 //img在html中是标签,在js中是对象 const pic = document.querySelector('img') // 修改对象的属性值 pic.src = `./images/${getRandom(1, 6) }.webp`
-
1.4.2 控制 样式 属性
-
1️⃣ 通过 style属性 操作css
-
语法 :元素.style.样式属性 = '值'
- 对于复杂的样式属性建议使用 小驼峰 命名法
- 生成的是 行内样式表 ,权重很高,只有 !important 能做掉它
- ⚠🔺 只写 属性
-
代码展示:
js// 获取对象(元素) const box = document.querySelector('div') // 修改样式属性 对象.style.样式属性 = '值' box.style.width = '400px' box.style.height = '100px' box.style.backgroundColor = 'red' box.style['background-color'] = 'green'
-
-
2️⃣ 通过 类名(className) 操作css
-
语法:元素.className = '类名'
- ⚠ 注意:会覆盖前面的类名 新值换旧值
- 想要原来的类名 -> 元素.className = '旧类名 新类名'
-
代码展示:
html<style> div { width: 200px; height: 200px; background-color: pink; } .active { width: 300px; height: 300px; background-color: hotpink; margin-left: 100px; } </style> <body> <div class="one"></div> <script> // 1.获取元素 // let box = document.querySelector('css选择器') let box = document.querySelector('div') // 2 给div添加类名 class 是个关键字,选用className替代它 // 新值换旧值,会覆盖原来的类名 box.className = 'active' // 用旧类名+新类名的形式覆盖原来的类名 box.className = 'one active' </script> </body>
-
-
❗3️⃣ 通过 classList 操作类 控制css
-
语法 :
- 追加 类:元素.classList.add('类名')
- 删除 类:元素.classList.remove('类名')
- 切换 类:元素.classList.toggle('类名')
- 如果有这个类名就是删掉,没有就追加
- 替换 类:元素.classList.replace('旧类名', '新类名')
- 两个参数,第一个是原来的类名,第二个参数是替换的类名
- 是否包含指定的 类:元素.classList.contains('类名')
- 判断是否包含指定的类名,返回值是布尔值 true / false
-
⚠ 注意:
- 类名 不加 点,并且 是 字符串
- 是 方法 ,注意加小括号
-
代码展示:
js// 获取对象 const box = document.querySelector('.one') // 追加类名 box.classList.add('two') box.classList.add('three') // 删除类名 box.classList.remove('three') // 切换类名 // 如果有这个类名就是删除,没有就是追加 box.classList.toggle('ab') box.classList.toggle('one') // 替换类名 // 将 旧类名box 替换成 新类名box1 box.classList.replace('box', 'box1') // 判断是否包含指定的类名 console.log(box.classList.contains('box')) // true
-
- classList 和 className区别
- classList 是 追加类名 ,将新类名追加到旧类名后面,不影响以前的类名
- className 是 覆盖类名 ,新类名 覆盖 旧类名,影响以前的类名
1.4.3❗❗ 操作 表单元素 属性
-
语法 :
- 获取 :元素.属性名
- 设置 :元素.属性名 = 新值
-
代码展示:获取表单里面的值
jsconst input = document.querySelector('.computer') console.log(input.value) input.value = '扶我起来,我还能干!!!'
-
⚠ 注意:对象.innerHTML 只能获取 普通元素 的 文本 ,获取 表单元素 的 文本 需要使用 对象.value
- ⚠ 注意: 对象.value 获得的文本是 包含 首尾 的 空白符
- 想要获得 有效的文本 需要使用 trim() 方法[对象.value.trim()],删除首尾的空白符
- ⚠注意:获取 button 的文本还是用 innerHTML
- ⚠ 注意: 对象.value 获得的文本是 包含 首尾 的 空白符
-
表单属性中添加就有效果,移除就没有效果,一律使用 布尔值 表示,如果为 true 代表 添加 了该 属性 ,如果是 false 代表 移除 该 属性
-
disabled(禁用)、checked(选中)
-
除了 ' ' , false , 0 , null , undefined ,NaN 其余的都是true,但是不建议写,建议写布尔值
-
代码展示:
js<input type="checkbox" value="" name=""> const input = document.querySelector('.computer') input.checked = true // 让复选框选中 input.checked = false // 让复选框不选中 input.disable = true // 禁用吗? - 禁用(true) input.disable = false // 禁用吗? - 不禁用(false默认值)
-
1.4.4 ❗❗ 自定义属性
- 属性
-
标准属性:标签天生自带的属性,可以直接使用 点语法 操作
-
自定义属性:
-
在h5中推出了专门的 data- 自定义属性
-
在标签上一律以 data- 开头(必须以 data- 开头)
-
在DOM对象上一律以 dataset 对象方式获取
-
dataset 是一个 自定义属性集合 ,包含 该标签内 的 所有 自定义属性
-
代码展示:
html<div data-id="1" data-spm="不知道">1</div> <div data-id="2">2</div> <div data-id="3">3</div> <div data-id="4">4</div> <div data-id="5">5</div> <script> // 获取元素 const one = document.querySelector('div') // one是一个HtmlElement对象 console.log(one) // dataset是一个对象集合 console.log(one.dataset) // 获取dataset对象里面的id属性 console.log(one.dataset.id) // 获取dataset对象里面的spm属性 console.log(one.dataset.spm) </script>
-
-
- ❌⛔ 拓展:
-
获取自己 瞎定义的属性
-
浏览器不会识别 瞎定义属性,并且它不会体现在DOM对象上
-
语法:
jsDOM对象.getAttribute(瞎定义属性名)
-
1.5 ❗❗ 定时器 - 间歇函数
- 定时器 = setInterval() + setTimeout()
- setInterval(函数, 间隔时间) (间歇函数):按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到clearInterval()被调用或窗口关闭
- 间歇函数可以根据时间自动重复执行某些代码
- setTimeout(函数, 延迟时间)(延时函数):在指定的毫秒数后调用函数或计算表达式 (Timeout - 超出)
- 定时器 里面的 第一个参数 是 回调函数
- 将一个函数作为参数传递给另外一个函数,这个函数就是回调函数
1.5.1 开启定时器
-
语法 :
js匿名函数:setInterval(函数, 间隔时间) // Interval - 间隔,间隙 具名函数:setInterval(函数名, 间隔时间)
-
作用 :每隔一段时间 回头调用函数(先隔段时间 ,再调用函数)
- 间隔时间 单位 是 毫秒(ms),不用写
- 不是立即调用函数,时间间隔 过后再去 调用函数
-
间歇函数返回值
- 表示 当前定时器 是 页面中 的 第几个 定时器,是一个 id数字 (数字型)(唯一的)
- 一个 间歇函数 只有 一个 返回值,并且是唯一
-
代码展示:
js// 匿名函数 setInterval(() => { console.log('扶我起来,我还能干!!!') }, 1000) // 具名函数 function fn() { console.log('扶我起来,我还能干!!!') } setInterval(fn, 1000) // fn() --- 执行这个函数,只执行一次 (fn()调用这个函数) // fn --- 每隔一段时间,回头去找fn这个函数(自动调用),再执行(fn是一个变量,代表这个函数) // 定时器的返回值,是数字型,是id // 声明一个变量,接收定时器的返回值 let n = setInterval(() => { console.log(1) }, 1000) console.log(n) // 1 function fn() { console.log('扶我起来,我还能干!!!') } let m = setInterval(fn, 1000) console.log(m) // 2
1.5.2 关闭定时器
-
语法 :
js// 匿名函数 let 变量名 = setInterval(函数, 时间间隔) // 具名函数 let 变量名 = setInterval(函数名, 时间间隔) clearInterval(变量)
-
代码展示:
js// 匿名函数 let n = setInterval(() => { console.log(11) }, 1000) // 具名函数 function fn() { console.log('扶我起来,我还能干!!!') } let m = setInterval(fn, 1000) // 关闭定时器 clearInterval(n) clearInterval(m)
二、❗❗ DOM事件基础
2.1 事件监听(绑定)
-
让程序检测是否有事件产生,一旦事件触发,就立即调用一个函数做出响应,也称为 绑定事件 / 注册事件
-
事件监听三要素:
- 事件源
- 事件类型
- 事件调用的函数(事件处理函数)
-
语法 :
js元素对象.addEventListener('事件类型', 要执行的函数)
-
⚠ 注意:事件类型 要加 引号
- L2 注册的 事件 不会 出现 覆盖
- L0 注册的事件会发生覆盖(后面的覆盖前面的)(同对象、同事件类型)
-
代码展示:
js// 获取元素 const btn = document.querySelector('button') // 事件监听-点击事件 btn.addEventListener('click', () => { alert('扶我起来,我还能干!!!') })
2.2 事件类型
2.2.1 鼠标事件
- 1️⃣ click - 鼠标点击
- 2️⃣ mouseenter - 鼠标经过
- 3️⃣ mouseleave - 鼠标离开
- 4️⃣ mousemove - 鼠标移动
- 5️⃣ dblclick - 鼠标左键双击
2.2.2 焦点事件
- 1️⃣ focus - 获得焦点
- 2️⃣ blur - 失去焦点
2.2.3 键盘事件
- 1️⃣ keydown - 键盘按下触发
- 2️⃣ keyup - 键盘抬起触发
- 注意: 用鼠标粘贴内容不会触发
2.2.4 文本事件
- 1️⃣ input - 用户输入事件
- 获取用户 输入文本 :对象.value
- 获取用户 输入文本 的 长度 :对象.value.length
- ⚠ 注意:
- 得到的 是 数字型
- ⚠ 包括 左右两侧 的 空格
- ⚠ 注意:
- 想要获得 有效 的 文本和长度 (不包括首尾的空白符)
- 有效文本: 对象.value.trim()
- 有效长度: 对象.value.trim().length
- trim() 方法:删除 字符串 首尾 空白符(空格、制表符、换行符等其他空白符)
- 不会 改变 原始字符串
- 不适用于null,undefined,Number类型
2.2.5 表单事件
- 1️⃣ submit - 提交事件
- 2️⃣ change - 失去焦点并且表单内容发生改变触发事件
- 3️⃣ 重置表单: form.reset()
2.2.6 光标的坐标
- 1️⃣ clientX 和 clientY
- 光标距相对于 浏览器 可视化窗口 左上角 的位置
- 鼠标在窗口中的位置
- 2️⃣ pageX 和 pageY
- 光标距离 文档流 左上角 的位置
- 鼠标在页面中的坐标
- 计算鼠标在某个盒子中的坐标:
- 鼠标到盒子顶部的距离 = 鼠标到页面顶部的距离 - 盒子顶部到页面顶部的距离
- 鼠标到盒子左侧的距离 = 鼠标到页面左侧的距离 - 盒子左侧到页面左侧的距离
- 3️⃣ offsetX 和 offsetY
- 光标距离 DOM元素 左上角 的位置
- 鼠标在标签中的位置
- ⚠🔺 拓展:利用 js 调用 事件
- 语法:元素.事件类型()
2.3 事件对象 - event
- 也是个对象,里面有事件触发时相关的信息
2.3.1 获取事件对象
-
⚠ 使用场景:
- 可以判断用户按下哪个键
- 可以判断鼠标点击了哪个元素,从而做相应的操作
-
语法:
- 在 事件绑定 的 回调函数 的 第一个参数 就是 事件对象
- 一般命名为 event、ev、e
jselement.addEventListener('事件类型', function (e) {})
-
在触发 DOM 上的某个事件时,会产生一个事件对象
-
event对象 包含与创建它的特定相关的和方法
2.3.2 事件对象常用属性
-
type :获取 当前的 事件类型
-
clientX / clientY :获取 光标 相对于 浏览器可视化窗口 左上角 的位置
-
offsetX / offsetY :获取 光标 相对于 当前DOM元素 左上角 的位置
-
pageX / pageY : 光标距离 文档流 左上角 的位置
-
key :
- 用户 按下 键盘键的值
- 现在不提倡使用keyCode
-
代码展示:
js元素.addEventListener('click', function (e) { console.log(e.key) console.log(e.type) })
2.4 环境对象
- 函数内部特殊的变量 this,代表当前函数运行时所处的环境
- 每个函0数 里面 都有 this
- 非严格模式
- this指向函数的调用者(普通函数里面 this -> window)
- 事件侦听里面,指向事件源
- 箭头函数没有this(箭头函数不会自己创建this,它只会沿用自己所在这条作用域链的上层作用域的this)
- 定时器里面this指向window
2.5 回调函数
- 官方:如果将函数A作为参数传递给函数B时,我们称函数A为 回调函数
- 把一个 函数 当作 参数 来 传递给 另外一个函数 的时候,这个函数就是 回调函数
三、❗❗ DOM事件进阶
3.1 事件流
3.1.1 事件流与两个阶段说明
- 事件流 = 事件捕获 + 事件目标 + 事件冒泡
- 事件流指的是:事件 完整 执行过程 中的 流动路径
- 过程:事件捕获 => 事件目标阶段 => 事件冒泡 整个完整的过程就是事件流
- 两个阶段:
- 捕获阶段:从父到子(从大到小)
- 冒泡阶段:从子到父(从小到大)
- 实际工作中都是使用 事件冒泡 为主
3.1.2 ❌ 事件捕获(了解)
- 概念:从DOM的 根元素 开始去执行对应的事件(从外到里)
- 事件捕获需要写对应代码才能看见效果
-
代码:
jsDOM.addEventListener(事件类型, 事件处理函数[, 是否使用捕获机制 = false])
- addEventListener第三个参数传入 true 代表是捕获阶段触发(很少使用)
- 若传入false代表冒泡阶段触发,默认就是false
- 若是用 L0(on事件类型) 事件监听,则只有冒泡阶段,没有捕获
-
3.1.3 事件冒泡
-
从子到父(从小到大)
-
概念:当一个元素触发事件后,会 依次 向上 调用 所有父级元素 的 同名事件(同种事件类型)
-
事件冒泡是默认存在的
-
事件冒泡的必要性
- 如果没有冒泡,给大盒子注册点击事件,点击的是里面的小盒子,会导致大盒子的点击无法执行
- 事件委托(委托给祖先元素)
-
L2事件监听第三个参数是false,或者默认都是冒泡
-
代码展示:
jsconst fa = document.querySelector('.father') const son = document.querySelector('.son') document.addEventListener('click', function () { alert('我是爷爷') }) fa.addEventListener('click', function () { alert('我是爸爸') }) son.addEventListener('click', function () { alert('我是儿子') }) // 事件冒泡:从子到父 // 弹出框的顺序依次是:儿子 -> 我是爸爸 -> 我是爷爷
3.1.4 阻止冒泡
-
语法:
js事件对象.stopPropagation() // 方法 停止传播 sp(快捷) e.stopPropagation() // 事件对象 - 回调函数的第一个参数
- 此方法可以阻断事件流动传播 ,不光在冒泡阶段有效,捕获阶段也有效
-
代码展示:
jsconst fa = document.querySelector('.father') const son = document.querySelector('.son') document.addEventListener('click', function () { alert('我是爷爷') }) fa.addEventListener('click', function () { alert('我是爸爸') }) son.addEventListener('click', function (e) { alert('我是儿子') // 阻止流动传播(阻止事件冒泡) // 在这一块卡住,不允许向上传播 e.stopPropagation() }) // 弹出框:我是儿子
-
阻止元素默认行为:
-
语法:
jse.preventDefault() // 方法 阻止默认 pd(快捷) // 阻止 链接跳转 // 阻止 表单提交(缺点:提交数据页面h)
-
代码展示:
html<body> <form action="http://www.itcast.cn"> <input type="submit" value="免费注册"> </form> <a href="http://www.baidu.com">百度一下</a> <script> // 获取元素 const a = document.querySelector('a') const form = document.querySelector('form') // 事件侦听-a-点击事件 a.addEventListener('click', function (e) { // 阻止a的默认行为-页面跳转 e.preventDefault() }) // 事件侦听-form-提交事件 form.addEventListener('submit', function (e) { // 阻止form的默认行为-表单的提交 e.preventDefault() }) </script> </body>
-
3.1.5 两种鼠标事件的区别
- ⚠ 注意:
- mouseover 和 mouseout 会 有 冒泡效果
- mouseenter 和 mouseleave 没有 冒泡效果(推荐)
3.1.6 解绑事件
-
1️⃣ L0事件解绑(on方式)
-
直接使用 null 覆盖就可以实现事件的解绑
-
代码展示:
jsbtn.onclick = function () { alert('点击了') } // L0事件移除解绑 btn.onclick = null
-
-
2️⃣ L2 事件解绑
-
语法:
jsremoveEventListener(事件类型, 函数名[, 获取捕获或冒泡阶段])
- ⚠ 中括号包裹的参数可以省略
- ⚠🔺 匿名函数 无法进行 事件解绑 操作
- ⚠ 解绑的时候必须是 同一个函数(两个函数体一样 的 匿名函数 不是 同一个函数)
-
代码展示:
js<script> // 获取元素 const btn = document.querySelector('button') // 声明函数 let fn = function (e) { alert(`事件解绑语法: 元素.removeEventListener(事件类型, 函数名) 匿名函数 无法进行 事件解绑 操作 ${e.target.tagName} `) } // 事件侦听-点击事件 btn.addEventListener('click', fn) // 事件解绑 btn.removeEventListener('click', fn) </script>
-
3.1.7 两种注册事件的区别
- 1️⃣ 传统on 注册(L0)
- 同一个对象,后面注册的事件会 覆盖 前面注册的事件(同一个事件)
- 直接使用 null 覆盖就可以实现事件的解绑
- 都是 冒泡阶段 执行的(只有冒泡没有捕获)
- 2️⃣ 事件监听 注册(L2)
- 语法:addEventListener(事件类型, 事件处理函数[ , 是否使用捕获 = false])
- 既能捕获也能冒泡
- 捕获 将第三个参数 改成 true
- 冒泡不用写,默认就是冒泡(false)
- 后面注册的事件 不会覆盖 前面注册的事件(同一个事件)
- 可以通过 第三个参数 去确定是在 冒泡阶段 或者 捕获阶段 执行的
- 必须使用 removeEventListener(事件类型, 事件处理函数[ , 获取捕获或者冒泡阶段])
- ⚠🔺 匿名函数无法解绑
- 语法:addEventListener(事件类型, 事件处理函数[ , 是否使用捕获 = false])
3.2 事件委托
-
优点:
- 减少注册次数
- 提高程序性能
- ⚠ 为未来元素预备事件(添加节点)
-
原理: 事件委托其实是利用 事件冒泡 的特点
- 给 父元素 注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
-
⚠ 注意: 事件触发元素嵌套关系很复杂就不可以使用事件委托
-
实现:
- 获得 真正 触发事件 的 元素(对象):事件对象.target
- 获得 真正 触发事件元素 的 标签名称:事件对象.target.tagName
-
代码展示:
html<body> <ul> <li>第1个孩子</li> <li>第2个孩子</li> <li>第3个孩子</li> <li>第4个孩子</li> <li>第5个孩子</li> <p>我不需要变色</p> </ul> <script> // 1.点击每个小li,当前li文字变色 // 按照事件委托的方式,委托给父级,事件写到父级身上 // 获取元素 const ul = document.querySelector('ul') // 事件绑定 ul.addEventListener('click', function (e) { // e:事件对象 // 得到一个事件对象 // console.log(e) // 得到被点击的元素 // console.log(e.target) // 得到被点击元素的标签名称 // 得到的标签名称是 大写的 字符串 // console.log(e.target.tagName) // 'LI' // 判断点击的是不是li,如果是li文字就变颜色 if (e.target.tagName === 'LI') { e.target.style.color = 'red' } }) </script> </body>
3.3 其他事件
3.3.1 页面加载事件
- ⚠ JavaScript 写在body上面,必须 使用 load 事件 或者 DOMContentLoaded事件
- 1️⃣ load 事件
- 等待页面 所有外部资源(外联CSS、外联JavaScript,图片......) 加载完毕 时,就回去执行回调函数
- 事件名: load(等待)
- 监听 整个页面 所有外部资源 加载完毕
-
⚠ 给 window 添加 load 事件
-
语法:
jswindow.addEventListener('load', function () { // 执行操作 })
-
代码展示:script标签在body标签上方
js<script> // 给 window 添加 页面加载事件(load) window.addEventListener('load', function () { // 获取元素 const btn = document.querySelector('button') // 事件侦听-点击事件 btn.addEventListener('click', function () { alert(` 页面加载事件 给 window 添加 load 事件 window.addEventListener('load', function() {}) `) }) }) </script> <body> <button>点击</button> </body>
-
⚠ 注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定 load事件
-
- 2️⃣ DOMContentLoaded 事件
- 当 初始的HTML文档(DOM节点) 被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待外部资源加载
- 事件名: DOMContentLoaded
- 监听页面 DOM节点 加载完毕
-
⚠ 给 document 添加 DOMContentLoaded 事件
-
语法:
jsdocument.addEventListener('DOMContentLoaded', function () { // 执行的操作 })
-
代码展示:
jsdocument.addEventListener('DOMContentLoaded', function () { // 获取元素 const btn = document.querySelector('button') // 事件侦听-点击事件 btn.addEventListener('click', function () { alert(` 页面加载事件 给 document 添加 DOMContentLoaded 事件 document.addEventListener('DOMContentLoaded', function() {}) `) }) })
-
3.3.2 元素滚动事件 - scroll
-
滚动条 滚动的时候 触发(⚠ 页面 必须有 滚动条 才能 触发 )
-
让 页面 具有 滑动效果 (不是瞬间到指定位置,而是缓慢滑动到指定位置)
*css/* 页面滑动 */ html { /* 让滚动条丝滑的滑动 */ /* 滚动-行为:平滑 */ scroll-behavior: smooth; }
-
-
让 html标签(页面最大的标签) 滚动
*jsdocument.documentElement.scrollTop // html被卷去的高度 window.pageYoffset // 页面滚出去的高度(页面在竖轴的偏移量) document.documentElement.scrollTop === window.pageYoffset
-
应用场景:固定导航栏、返回顶部
-
事件名: scroll
-
监听 整个页面 滚动
-
语法:
jswindow.addEventListener('scroll', function () { // 执行的操作 })
-
⚠ 注意:
- 给 window(常用) 或 document 添加 scroll 事件
- 监听 某个元素的内部 滚动 直接给 某个元素 加即可
-
代码展示:
-
-
获取位置
-
scrollTop (被卷去的头部) 和 scrollLeft (被卷去的左侧) (属性)
-
⚠🔺 读写属性(可以 读取 亦可以 赋值)
-
⚠ 获取到的是 数字 ,赋值的时候 不带单位
-
检测页面滚动的头部距离
*jsdocument.documentElement.scrollTop = 数字
jswindow.pageYoffset - 只读属性
-
获取 被卷去 的大小
-
获取 元素内容 往左、往上滚出去 看不到 的 距离
-
⚠ 得到的是:数字型 不带单位
-
尽量写在 scroll事件 里面
-
代码展示:
html<style> * { margin: 0; padding: 0; box-sizing: border-box; } body { height: 3000px; } div { display: none; margin: 100px auto; width: 470px; height: 150px; border: 1px solid #000; text-align: center; font-size: 20px; font-family: '隶书'; } .active { display: block; position: fixed; top: 0; left: 50%; transform: translateX(-50%); margin-top: 0; } </style> <body> <div> 世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!! 世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!! 世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!! 世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!! 世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!! 世间的悲喜皆不如我所愿,但苦于乐皆是恩赐!!! </div> <script> // 事件侦听-页面滚动事件-window window.addEventListener('scroll', function () { // 获取html元素 const html = document.documentElement // 获取div元素 const div = document.querySelector('div') // console.log(html.scrollTop); // 得到的是数字型 // scrollTop >= 300显示div并固定在可视区域顶部,小于300隐藏 if (html.scrollTop >= 300) { div.classList.add('active') } else { div.classList.remove('active') } }) </script> </body>
-
-
让页面 滚动到指定位置
-
1️⃣ 属性赋值
jsdocument.documentElement.scrollTop = 指定位置距离顶部的距离
-
2️⃣ 方法
window.scrollTo(x, y)
-
-
3.3.3 ❌ 页面尺寸事件 - resize(了解)
-
窗口尺寸改变 的时候 触发事件
-
事件类型: resize
-
语法:
jswindow.addEventListener('resize', function () { // 执行的代码 })
-
-
检测屏幕宽度
-
语法:
jswindow.addEventListener('resize', function () { let w = document.documentElement.clientWidth console.log(w) })
-
-
获取元素宽高 (属性)
- 获取元素的 可见部分 宽高(不包含border、margin、滚动条)
- clientWidth 和 clientHeight
- 得到的是 数字型
3.4 ❗❗ 元素的尺寸和位置
-
1️⃣ 获取 宽高: (属性)
- 获取元素 自身的宽高
- 内容 + padding + border
- offsetWidth 和 offsetHeight
- 获取到的是 数值
- ⚠ 获取的是 可视宽高,如果盒子是隐藏的,获取的结果是0
- 获取元素 自身的宽高
-
2️⃣ 🔻 获取 位置:
- ① 获取元素 距离自己 最近一级 定位 祖先元素 的 左、上 距离
- 带有 定位属性 的 祖先元素
- 如果都没有,就以文档左上角为准
- offsetLeft 和 offsetTop
- 相对于 页面 来说
- ⚠ 只读属性
- 获取的是可视宽高,若盒子隐藏,则获得的是0
- ② ❌ 元素.getBoundingClientRect() (了解)
-
返回元素的 大小 及其 相对于视口的位置
-
相对于 视口
-
代码展示:
jsconst div = document.querySelector('div') div.getBoundingClientRect()
-
- ① 获取元素 距离自己 最近一级 定位 祖先元素 的 左、上 距离
✅ 总结
属性 | 作用 | 说明 |
---|---|---|
scrollLeft 和 scrollTop | 被 卷去 的 头部 和 左侧 | 配合 页面滚动(scroll 事件) 来用,可读写 |
clientWidth 和 clientHeight | 获得 元素 的 宽度 和 高度 | 不包含border、margin、滚动条,用于js 获取元素大小 只读属性 |
offsetWidth 和 offsetHeight | 获得 元素 的 宽度 和 高度 | 包含border、padding、滚动条等,只读属性 |
offsetLeft 和 offsetTop | 获取元素距离 自己定位父元素 的左、上距离 | 获取 元素位置 的时候使用,只读属性 |
- scroll系列 、 client系列 、 offset系列
- scroll系列: 标签内部 内容 的大小,位置
- scrollTop / scrollLeft:表示标签真实内容相对于标签的位置
- ❌scrollWidth / scrollHeight:表示标签真实内容的大小(和标签本身的大小无关,是内容的宽高)
- client系列: 标签 容纳范围(border里面) 的大小、位置
- clientWidth / clientHeight:表示标签内容区域的大小
- ❌clientTop / clientLeft:表示标签内容区域的位置(几乎不用,仅仅表示上边框的高度,左边框的宽度)
- ✔🔻 offset系列: 标签本身 的大小、位置
- offsetWidth / offsetHeight:包含content + padding + border
- offsetTop / offsetLeft:最近一级 的 带有定位属性 的 祖先元素 的 相对位置(如果没有定位,那么就是相对于body)
- scroll系列: 标签内部 内容 的大小,位置
- 拓展:
-
添加css让页面滚动平滑
*csshtml { scroll-behavior: smooth; }
-
if单分支语句拓展:
*jsif (old) old.classList.remove('active')
jsold && old.classList.remove('active') - 逻辑与
jsold?.classList.remove('active') - 可选链
-
属性选择器
*jsdocument.querySelector('[data-name=new]') 自定义属性 的 属性值 可以 省略 双引号(不推荐)
-
四、❗❗ 日期对象
- 用来 表示时间 的 对象
- 作用: 得到 当前系统 的 时间
- 日期对象:Date构造函数的实例,记录了一个时间信息
4.1 实例化
- 实例化 :有 new 关键字的都是实例化(见 JS 高级)
4.1.1 得到当前时间
- 创建一个 时间对象 并 获取时间
-
语法:
jsconst 常量名 = new Date()
-
代码展示:
jsconst date = new Date() console.log(date) // Wed Aug 03 2022 20:37:52 GMT+0800 (中国标准时间) // 周三 八月 3号 年份 时间
-
4.1.2 指定时间
-
倒计时 的时候 使用
-
语法:
jsconst 常量名 = new Date('指定的时间')
-
⚠ 参数:
- 数字 : 月份是从 0 开始的
- 字符串 : 月份是正常的
-
代码展示:
jsconst date = new Date('2022-8-3 20:50:00') let h = date.getHours() console.log(h) // number console.log(date) console.log(typeof date) // object // Wed Aug 03 2022 20:50:00 GMT+0800 (中国标准时间)
4.2 日期对象方法
语法 | 作用 | 说明 |
---|---|---|
对象.getFullYear() | 获得 年份 | 获取 四位 年份 |
对象.getMonth() | 获得 月份 | 取值为 0 ~ 11 |
对象.getDate() | 获取 月份中的 某一天 | 不同月份取值不同 |
对象.getDay() | 获取 星期 | 取值为 0 ~ 6 |
对象.getHours() | 获取 小时 | 取值为 0 ~ 23 |
对象.getMinutes() | 获取 分钟 | 取值为 0 ~ 56 |
对象.getSeconds() | 获取 秒 | 取值为 0 ~ 59 |
对象.getMilliseconds() | 获取 毫秒 | 取值为 0~1000 |
- ⚠ 注意:
- 周日是一周的开始 -> 周日 = 0
- 当前月份 = 获取的月份 + 1
- ⚠ 得到的都是 数字型
4.3 时间的另一种写法
-
时间对象.toLocaleString() :年月日时分秒
-
时间对象.toLocaleDateString() :年月日
-
时间对象.toLocaleTimeString() :时分秒
-
代码展示:
js// 获得当前系统时间 const systemTime = new Date() // 从 获取的当前系统时间(systemTime)里找 // 获取年份 const year = systemTime.getFullYear() // 获得月份 const month = systemTime.getMonth() + 1 // 获取月份中的某一天 const date = systemTime.getDate() // 获取星期 const day = systemTime.getDay() // 获取小时 const hours = systemTime.getHours() // 获取分钟 const minutes = systemTime.getMinutes() // 获取秒 const seconds = systemTime.getSeconds() console.log(systemTime); console.log(`${year} 年 ${month} 月 ${date} 日 周${day} ${hours} 时 ${minutes} 分 ${seconds} 秒`) // Wed Aug 03 2022 21:14:56 GMT+0800 (中国标准时间) // 2022 年 8 月 3 日 周3 21 时 14 分 56 秒
-
格式化时间:
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } div { margin: 100px auto; width: 600px; height: 100px; border: 5px solid #969696; background-color: #d7d7d7; color: hsl(338, 100%, 50%); font-size: 44px; font-weight: 700; font-family: '华文隶书'; text-align: center; line-height: 100px; } </style> </head> <body> <div></div> <script> // 写法一: const div = document.querySelector('div') function getTime() { const date = new Date() let hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() let minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() let seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() return `当前时间:${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${hours}:${minutes}:${seconds}` } div.innerHTML = getTime() setInterval(function () { div.innerHTML = getTime() }, 1000) // 当前时间:2022-8-3 22:45:50 // 写法二:自动补0 /* // 定时器外面再写一次的原因:定时器隔1s再去执行,用外面的填补页面空白 div.innerHTML = date.toLocaleString() // div.innerHTML = date.toLocaleDateString() // div.innerHTML = date.toLocaleTimeString() setInterval(function () { const date = new Date() div.innerHTML = date.toLocaleString() // 2022/8/3 23:00:00 // div.innerHTML = date.toLocaleDateString() // 2022/8/3 // div.innerHTML = date.toLocaleTimeString() // 22:48:20 }, 1000) */ </script> </body> </html>
4.3 时间戳
-
使用场景:倒计时
-
时间戳: 是指1970年01月01日00时00分00秒起 至现在 的 毫秒数
-
注意:
-
时间戳 是 唯一的
-
⚠ 中国 在 东8区
jsconst date = +new Date('1970-01-01 00:00:00') / 1000 / 60 / 60 console.log(date) // -8
-
-
⚠🔻 算法 :
-
将来的时间戳 - 当前的时间戳 = 剩余时间毫秒数
-
剩余时间毫秒数 转换为 剩余时间的 日时分秒 就是 倒计时
-
展示:
将来时间戳 2000ms - 现在时间戳 1000ms = 1000ms 1000ms 转换时分秒就是 0小时0分1秒
-
-
三种获取时间戳的方法:
-
1️⃣ 使用 getTime() 方法
-
语法:
jsconst date = new Date() console.log(date.getTime()) // 1659539589145 毫秒数 // new Date().get.Time() 拓展: 时间对象.getTime() 和 时间对象.valueOf() 的到的结果一样 console.log(date.getTime() === date.valueOf()) // true
-
⚠ 注意:
- 必须 先 实例化
- ⚠ 可以返回 指定时间的时间戳
-
-
2️⃣ ✔简写 +new Date()
-
语法:
jsconsole.log(+new Date()) // 1659539732765 毫秒数
-
⚠ 注意:
- + -> 正号 (隐式转换)
- ⚠ 可以返回 指定时间的时间戳
-
代码展示:
jsconlose.log(+new Date('2022-10-1 07:30:00')) // 1664580600000 -- 指定时间的时间戳
-
-
-
3️⃣ 使用 Date.now()
-
语法:
jsconsole.log(Date.now()) // 1659540040487 毫秒数
-
⚠ 注意:
- 没有 实例化
- ⚠ 只能得到 当前的 时间戳
-
-
-
时间转换公式
- 通过 时间戳 得到是 毫秒,需要转换为秒在计算
- 转换公式:
- days: d = parseInt(总秒数 / 60 / 60 / 24)
- hours: h = parseInt(总秒数 / 60 / 60 % 24)
- minutes: m = parseInt(总秒数 / 60 % 60)
- seconds: s = parseInt(总秒数 % 60)
-
✔ 倒计时函数:
jsconst element = document.qurySelector('css选择器') function getCountTime(time) { // 得到当前的时间戳(毫秒) const now = +new Date() // 得到未来时间时间戳(毫秒) const last = +new Date(time) // 得到剩余的时间戳(毫秒) 并转换为 秒 const count = (last - now) / 1000 // 将 剩余秒数 -> 天、时、分、秒 let day = parseInt(count / 60 / 60 / 24) let hours = parseInt(count / 60 /60 % 24) // 补0 hours = hours < 10 ? '0' + hours : hours let minutes = parseInt(count / 60 % 60) // 补0 minutes = minutes < 10 ? '0' + minutes : minutes let seconds = parseInt(count % 60) // 补0 seconds = seconds < 10 ? '0' + seconds : seconds return `${day} 天 - ${hours}:${minutes}:${seconds}` } function getRemainingTime(element, time) { // 先执行一次:定时器过1s再去执行,会有1s的显示空白时间,让它限制性,填补空白,再让后面的覆盖 element.innerHTML = getCountTime(time) setInterval(function () { element.innerHTML = getCountTime(time) }, 1000) } getRemainingTime(div, '2022-10-1 00:00:00')
五、❗❗ 节点操作
- 浏览器 使用 对象 来 记录 网页内容
- 浏览器把网页内容翻译成一个个的对象,把 网页内容 的 特征 翻译成 对象 的 属性
- 这个对象就称为 DOM对象
- 网页内容的特征:
- 标签属性
- 标签内容
- 标签上下级
- ...
- 网页内容 、对象
- 网页内容: 标签、文本、注释
- DOM对象:标签(元素)节点、文本节点、注释节点
- 网页内容 和 DOM对象 一 一 对应
- DOM树
- 每个DOM对象中都有表示层级关系的属性,这些属性把所有DOM对象联系在一起,形成一个树状结构,称为DOM树
- DOM树 === 网页
5.1 DOM节点
- DOM节点: DOM树 里面 每一个内容 都称之为 节点
- 节点类型:
- 1️⃣ ❗✔元素节点:
- 所有的 标签
- html 是 根节点
- 2️⃣ 属性节点:
- 所有的属性
- 3️⃣ 文本节点:
- 所有的文本
- 1️⃣ ❗✔元素节点:
5.2 查找节点 - 属性
- 有效返回值 是一个 对象
- 无效返回值 - null
5.2.1 父节点
- 1️⃣ parentNode 属性
-
语法:
js子元素.parentNode
-
返回值:
- ⚠ DOM对象
- 最近一级 的父节点(亲爸爸),找不到 返回 null
-
代码展示:
js<div class="yeye"> <div class="dad"> <div class="baby">x</div> </div> </div> <script> const baby = document.querySelector('.baby') console.dir(bady) // div.bady -> DOM对象 console.dir(baby.parentNode) // div.dad -> DOM对象 console.dir(baby.parentNode.parentNode) // div.yeye -> DOM对象 </script>
-
关闭广告:
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .box { position: relative; width: 1000px; height: 200px; background-color: pink; margin: 100px auto; text-align: center; font-size: 50px; line-height: 200px; font-weight: 700; } .box1 { position: absolute; right: 20px; top: 10px; width: 20px; height: 20px; background-color: skyblue; text-align: center; line-height: 20px; font-size: 16px; cursor: pointer; } </style> </head> <body> <div class="box"> 我是广告 <div class="box1">X</div> </div> <div class="box"> 我是广告 <div class="box1">X</div> </div> <div class="box"> 我是广告 <div class="box1">X</div> </div> <script> // const smallBox = document.querySelectorAll('.box1') /* for (let i = 0; i < smallBox.length; i++) { smallBox[i].addEventListener('click', function () { this.parentNode.style.display = 'none' }) } */ // 事件委托 document.body.addEventListener('click', function (e) { if (e.target.className === 'box1') { e.target.parentNode.style.display = 'none' } }) </script> </body> </html>
-
5.2.2 子节点
- 1️⃣ ❌childNodes 属性
-
语法:
js父元素.childNodes
-
返回值: 获得 所有子节点 、包括文本节点(空格、行换)、注释节点等
-
- 2️⃣ ⚠🔻 children 属性
-
语法:
js父元素.children
-
⚠ 返回值: 伪数组 (要想得到里面的每一个节点还是要遍历
-
⚠ 注意:
- 仅获得 所有 元素节点(标签)
- 只选亲儿子,只不过是把亲儿子里面包含的所有节点(元素、文本、注释...)拿过来
-
代码展示:
js<ul> <li> 1 <p>6</p> <span>7</span> </li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> // 获取子节点 // 语法:父元素.children // 返回值:伪数组 // 仅 获得 所有 元素节点(标签) console.log(document.querySelector('ul').children); // 得到的是一个伪数组 </script>
-
5.2.3 兄弟节点
-
1️⃣ 下一个 兄弟节点
-
nextElementSibling 属性
-
语法:
js兄弟元素.nextElementSibling
-
⚠ 返回值:
- 有下一个兄弟节点,得到的就是下一个元素
- 没有 就是 null
-
-
2️⃣ 上一个 兄弟节点
-
previousElementSibling 属性
-
语法:
js兄弟元素.previousElementSibling
-
⚠ 返回值:
- 有上一个兄弟节点,得到就是上一个元素
- 没有 就是 null
-
-
代码展示:
js<ul> <li> 1 <p>6</p> <span>7</span> </li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> // 上一个兄弟节点 // 语法:兄弟元素.previousElementSibling // 下一个兄弟节点 // 语法:兄弟元素.nextElementSibling console.log(document.querySelector('ul li:nth-child(2)').nextElementSibling) </script>
5.3 增加节点
- 先 创建 再 追加
5.3.1 创建节点
-
语法:
jsdocument.createElement('标签名') // 文档.创建元素
-
创建的节点是一个正常的DOM对象
-
⚠ 注意:
jsdocument.createElement() -- 创建的是空标签
-
5.3.2 追加节点
-
1️⃣ 插入到 父元素 的 最后一个 子元素
-
语法:
js父元素.appendChild(要插入的元素) // 追加孩子
-
⚠ 注意: 做为 父元素 里面 的 最后一个 子元素
-
代码展示:⬇
-
-
2️⃣ 插入到 父元素 中 某个子元素 的 前面
-
语法:
js父元素.insertBefore(要插入的元素, 在哪个元素前面) // 插入在...之前
-
⚠ 注意: 插入到 父元素 里面 的 指定位置
-
代码展示:⬇
-
-
⚠ 注意: appendChild 和 insertBefore 如果插入的是页面上 已经存在 的标签,会有 剪切 效果(将已经存在的元素 从 原位置 剪切到 新位置)
-
代码展示:
html<style> div, li { font-size: 20px; text-align: center; line-height: 50px; } li:first-child { width: 150px; height: 50px; background-color: #b8f0e8; } li:last-child { width: 150px; height: 50px; background-color: #a6a6db; } div { width: 150px; height: 50px; background-color: #c0bfbf; } </style> <body> <ul> <li>我是老大</li> </ul> <script> // 增加节点(节点 -> 元素节点) // 1.创建节点 // 语法:document.createElement('标签名称') // 2.插入节点 // (1).作为父元素里面的最后一个子元素 // 语法:父元素.appendChild(要插入的元素) // (2).插入到父元素里面指定位置(插入到父元素里面某个子元素的前面) // 语法:父元素.insertBefore(要插入的元素, 在那个子元素前面) // 1.创建节点 const li = document.createElement('li') li.innerHTML = '我是老二' // 2.插入节点 // 2.1获取父元素 const ul = document.querySelector('ul') // 2.2作为父元素里面的最后一个子元素 ul.appendChild(li) // 1.创建节点 const div = document.createElement('div') div.innerHTML = '我是老大的大哥' // 2.插入节点 // 2.1获取父元素 const body = document.body // 2.2插入到父元素指定位置(插入到父元素里面指定元素前面) body.insertBefore(div, ul) // 将创建的节点始终插入到父元素的最前面 /* body.children // 包含body下所有的(亲)子节点伪数组 body.insertBefore(div, body.children[0]) */ </script> </body>
5.3.3 克隆节点
-
特殊情况 的 新增节点
-
应用场景:轮播图
-
步骤:
- 1️⃣ 复制 一个 原有 的 节点
- 2️⃣ 把 复制的节点 放入到 指定 的 元素内部
-
语法:
js元素.cloneNode(布尔值)
-
clondNode会克隆出一个跟原标签一样的标签(原标签上面有什么,克隆后的标签上面就有什么)(是两个元素,克隆成功后前后两个元素没有任何关系)
-
参数:
- true - 深克隆: 克隆时 包含 后代节点 一起克隆 (节点 -> 文本节点、注释节点等所有的节点)
- false - 浅克隆: 克隆时 不包含 后代节点、
- 默认值 为 false
-
代码展示:
js<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> const ul = document.querySelector('ul') // const newLi = ul.children[0].cloneNode(true) // newLi.innerHTML = 'newLi' // ul.appendChild(newLi) ul.insertBefore(ul.children[0].cloneNode(true), ul.children[11]) </script>
-
5.4 删除节点
-
在 JavaScript 原生DOM操作中,要 删除元素 ⚠ 必须 通过 父元素 删除
-
语法:
js父元素.removeChild(要删除的元素)
-
⚠ 注意:
- 如果 不存在 父子关系 则 删除 不成功
- 删除节点 和 隐藏节点(display: none;)有区别
- 删除节点:从DOM中删除节点
- 隐藏节点:只是在页面上不显示,DOM节点依然存在
-
✔ 补充:
-
语法: 自杀式z
js删除的元素.remove()
-
-
拓展:
-
替换节点:
-
语法:
jsparentNode.replaceChild(newChild, oldChild);
-
方法用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点
-
-
重绘 和 回流
- 重绘: 由于节点(元素)样式的改变并不会影响它在文档流中的位置和文档布局时,则是重绘
- 回流: 元素的尺寸、结构、布局等发生变化时,浏览器就会重新渲染部分或全部文档的过程称为回流
- 重绘不一定一起回流,但回流一定会引起重绘
- 简单理解,影响到了布局,就会有回流
六、❌ M端事件
- 常见的触屏事件(touch)
触屏 touch 事件 | 说明 |
---|---|
touchstart | 手指 触摸 到一个DOM元素时触发 |
touchmove | 手指在一个DOM元素上 滑动 时触发 |
touchend | 手指从一个DOM元素上 移开 时触发 |
七、❗ JS插件
- 熟悉官网,了解这个插件可以完成什么需求 https://www.swiper.com.cn/
- 看在线演示,找到符合自己需求的demo https://www.swiper.com.cn/demo/index.html
- 查看基本使用流程 https://www.swiper.com.cn/usage/index.html
- 查看APi文档,去配置自己的插件 https://www.swiper.com.cn/api/index.html
- 注意: 多个swiper同时使用的时候, 类名需要注意区分
- 使用步骤:
- 引入资源
- css文件
- js文件
- 导入代码
- 复制html结构
- 复制css样式
- 复制js行为
- 引入资源
八、❗❗ window对象
window(JS中的顶级对象) > BOM(浏览器对象模型) > DOM(页面文档对象模型)
8.1 BOM(浏览器对象模型)
- BOM (Browser Object Model)- 浏览器对象模型
- 由一些列相关的对象构成,并且每个对象都提供了很多方法和属性
- 浏览器的内容被翻译成了对象
- window 对象是一个 全局对象 ,也可以说是 JavaScript 中的 顶级对象
- 像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
- ⚠ 所有通过 var 定义在 全局作用域 中的 变量 、函数 都会变成 window对象 的 属性 和 方法
- ⚠ window对象下的属性和方法调用的时候可以 省略window
- DOM 和 BOM 区别:
8.2 定时器 - 延时函数
-
定时器 = 间歇函数(setInterval()) + 延时函数(setTimeout())
-
让代码 延迟 执行的函数 - setTimeout()
-
语法:
jssetTimeout(回调函数, 等待的毫秒数)
-
清除延时函数:
jslet timerId = serTimeout(回调函数, 等待的毫秒数) clearTimeout(timerId)
-
⚠ 注意:
- setTimeout 仅仅 只执行 一次 ,平时省略 window
- 延时函数需要等待,所以后面的代码先执行
- 每一次调用延时器都会 产生一个 新的 延时器
-
间歇函数 和 延时函数 的区别:
- 间歇函数:每隔一段时间就执行一次,除非手动清除
- 延时函数:执行一次
8.3 JS执行机制
- JS代码 从上到下 执行
- 单线程: 同一时间只能做一件事
- 所有的任务需要排队,前一个任务结束,才会执行后一个任务
8.3.1 同步 与 异步
- 1️⃣ 同步
- 前一个任务结束后再执行后一个任务,程序的执行顺序 和 任务的排列顺序 是 一致的
- 同步任务: 都在 主线程 执行栈 上执行
- 2️⃣ 异步
- 如果执行一个任务需要花费一定的时间,在执行这个任务的同时可以去执行别的任务
- 耗时 的都是 异步
- JS的 异步 是通过 回调函数 实现的
- 异步任务的三种类型
- 普通事件(click、mouseenter、mouseleave、......)
- 资源加载
- 定时器 (间歇函数(setInterval) + 延时函数(setTimeout))
- 异步任务 添加到 任务队列 (消息队列)中
- 同步 和 异步 的 本质 区别:
- 一条流水线上的 各个流程 执行顺序不同
- 3️⃣ 执行机制:
- ① 先执行 任务栈 中的 同步任务
- ② 异步任务 添加到 任务队列 里面
- 对 异步任务 进行 排序(根据每个异步任务所消耗的时间 )
- ③ 一旦 执行栈 里面的 所有 同步任务 执行完毕 ,系统 就会 按次序 读取 任务队列 中的 异步任务 ,于是 被读取 的 异步任务 结束 等待状态 ,进入 执行栈,开始执行。
8.3.2 事件循环 - event loop
- 由于 主线程 不断的 重复 获得任务、执行任务、再获取任务、再执行,所以这种机制被称为 事件循环(enevt loop)
- 事件循环: js执行代码时,会把同步任务添加到主线程执行栈中执行,把满足条件的异步任务推到任务队列排队等候执行,事件循环是一种轮询机制,当执行栈中的所有同步任务执行完毕之后,系统就会依次读取任务队列中的异步任务,异步任务结束等待状态,按照次序添加到执行栈中执行。
8.4 location 对象
- location 的 数据类型 是 对象 ,它 拆分 并 保存 了 URL地址 的 各个 组成 部分
- 常用 属性 和 方法:
-
1️⃣ ✔🔺 href: 属性 获取 完整的URL地址 ,对其 赋值时 用于 地址的跳转
*jsconst btn = document.querySelector('button'); btn.addEventListener('click', function () { location.href = 'https://www.baidu.com'; });
- 可以后退
-
2️⃣ search: 属性 获取地址中 携带的参数 ,符号 ? 后面部分
*jsconsole.log(location.search); // 字符串
-
3️⃣ hash: 属性 获取地址中的 哈希值 ,符号 # 后面部分
*jsconsole.log(location.hash); // 字符串
-
4️⃣ reload(是否使用缓存): 方法 用来 刷新 当前 新页面,传入参数 true 时表示 强制刷新 ,默认false使用缓存刷新
*jsconst btn = document.querySelector('.reload'); btn.addEventListener('click', function () { // F5 -> 刷新 //location.reload(); // F5+Ctrl -> 强制刷新 location.reload(true); });
-
5️⃣ replace(): 方法 页面跳转(覆盖旧地址)
*jsconst btn = document.querySelector('button'); btn.addEventListener('click', function () { location.replace('https://www.baidu.com'); });
-
⚠ href属性 和 replace()方法 实现页面跳转的区别:
- href属性: 保留 原地址 ,具有回退功能
- replace()方法: 覆盖 原地址 ,没有回退功能
-
8.5 navigator 对象
- navigator 的 数据类型 是 对象 ,该对象记录了 浏览器 自身的 相关信息
- 常用 属性 和 方法:
-
浏览器相关信息:navigator.userAgent
-
通过 userAgent 检测 浏览器 的 版本 及 平台
js// 检测userAgent(浏览器信息) !(function () { const userAgent = navigator.userAgent; // 验证是否为Android或iPhone const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/); const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/); // 如果是Android或iPhone,则跳转至移动站点 if (android || iphone) { location.href = 'http://m.itcast.cn'; } })();
-
8.6 history 对象
- histroy 的 数据类型 是 对象,主要管理历史记录,该对象与浏览器地址栏的操作相对应。
- 常用属性和方法:
-
back(): 可以 后退 功能
-
forward(): 前进 功能
-
go(参数): 前进 后退 功能
- 参数:
- 1: 前进 一个页面 (back())
- 0: 刷新页面(使用缓存刷新) (reload())
- -1: 后退 一个页面 (forward())
- 参数:
-
代码展示:
html<button>后退</button> <button>前进</button> <script> // 获取元素 const back = document.querySelector('button'); const forward = back.nextElementSibling; // 事件侦听-点击事件 back.addEventListener('click', function () { // 前进一步 history.go(1); }); forward.addEventListener('click', function () { // 后退一步 history.go(-1); }); </script>
-
九、❗❗ 本地存储
- 数据存储 在 用户 浏览器 中(硬盘)
- 设置、读取方便、甚至 页面刷新 不会丢失 数据
- 容量较大、sessionStprange 和 localStorage 约5M
- 为什么要将数据存储到本地存储里?
- 数据持久化(数据不丢失)
9.1 本地存储分类
9.1.1 localStorage
- 作用: 可以 将 数据 永久存储 在 本地 (用户电脑),除非手动清除 ,否则关闭页面 也会 存在
- 生命周期: 什么时候失效,什么时候死掉
- 特性:
- 可以多窗口(页面)共享 (同一浏览器 可以共享)(不能跨域(同一个域名)使用)
- 以 键值对 的形式 存储使用
- ⚠🔻 语法:
-
1️⃣ 存储/修改 数据:
jslocalStorage.setItem(key, value) // 设置每个小项,key和value要加引号,key和value可以是变量
-
有 这个键就是 修改 ,没有 就是 添加
-
代码展示:
js// 本地存储 - localStorage // 存储数据 - localStorage.setItem(key, value); // 要加引号 localStorage.setItem('uname', '邵秋华');
-
-
2️⃣ 获取 数据:
jslocalStorage.getItem(key) // 获取里面的项,key必须加引号
-
返回值:
- 有这个key,就返回对应的值
- 没有这个key,返回 null
-
代码展示:
js// 获取数据 - localStorage.getItem(key) // 要加引号 console.log(localStorage.getItem('uname')); // 邵秋华
-
-
3️⃣ 删除 某项数据:
jslocalStorage.removeItem(key) // 移除里面的项, key必须加引号
-
代码展示:
js// 删除本地存储 localStorage.removeItem('uname');
-
-
4️⃣ 清空 数据:
jslocalStorage.clear()
- 慎用
- 清空全部数据
-
- ⚠⚠ 注意:
-
⚠ 所有的 键 必须加 引号
-
有这个键就是修改,没有就是添加
-
⚠🔺 本地存储 只能存储 字符串 类型的数据
-
得到的值也是字符串型
-
如果value写的是数值型,存的时候会转换成字符型
-
代码展示:
jsconst arr = [1, 2, 3, 4]; arr.forEach((item, index) => { localStorage.setItem(`id:${index}`, item); console.log(localStorage.getItem(`id:${index}`)); // 1 2 3 4(字符串) console.log(typeof (localStorage.getItem(`id:${index}`)));// string });
-
9.1.2 sessionStprange
- 特性:
- 生命周期 为 关闭浏览器窗口
- 在同一个窗口 (页面)下 数据可以共享
- 以 键值对 的形式 使用
- 用法跟localStorage基本相同
- ⚠ localStorage 与 sessionStorage 的区别
- 他们的 作用 相同 ,但是 存储方式 不同,因此应用场景也不同
- localStorage 的数据可以 长期存储 ,关闭浏览器 数据 也 不会消失,除非 手动清除
- sessionStorage 的数据时是 临时存储 ,页面被关闭 ,存储在sessionStorage里的 数据 会被 清除
9.2 存储复杂数据类型
- 本地存储 只能存储 字符串,不能存储 复杂数据类型
- JSON:
- 属性和值都有引号,而且是双引号
- 一种字符串格式的名称
- 把 数组/对象 转换为结构为 "数组/对象" 的字符串
- 只能存:数字、字符串、对项
- 不能存null、undefined、函数
- ⚠ JSON.parse(转换数据):要转换的数据不是JSON格式的字符串
- 存储复杂数据类型步骤:
- 1️⃣ 将 复杂数据类型 ➡ JSON字符串
-
语法:
jsJSON.stringify(复杂数据类型)
-
代码展示:
js// 本地存储只能存储字符串,不能存储复杂数据类型 // 如果要存储复杂数据类型,需要将复杂数据类型转换成 JSON 字符串 // 语法:JSON.stringify(复杂数据类型); let obj = { uname: '邵秋华', age: 22, gender: '男', }; localStorage.setItem('obj', JSON.stringify(obj));
-
- 2️⃣ 将 JSON字符串 ➡ 复杂数据类型
-
语法:
jsJSON.parse(JSON字符串)
-
代码展示:
jsconsole.log(JSON.parse(localStorage.getItem('obj')));
-
- 1️⃣ 将 复杂数据类型 ➡ JSON字符串
- 存:
- 复杂数据类型 -> JSON.stringify() -> JSON字符串 -> 存到本地存储中
- 取:
- 从本地存储中取 -> JSON字符串 -> JSON.parse() -> 复杂数据类型
十、❗ 正则表达式
- 正则表达式 (Reular Expression):用于 匹配 🔺字符串 🔺 中 字符组合 的 模式 。
- 在 JavaScript 中,正则表达式 也是 对象(object )
- ⚠🔺 注意: 只能对 字符串 进行匹配
- 正则表达式的作用 :
- 1️⃣ 表单验证(匹配)
- 2️⃣ 过滤敏感词汇(替换)
- 3️⃣ 字符串中提取我们想要的部分(提取 ->-爬虫)
10.1 正则表达式的使用
-
1️⃣ 定义规则:
-
语法:
jsconst regObj = /表达式/ // 正则表达式不改变使用
jsconst regObj = new RegExp('表达式') // 正则表达式变化使用
-
⚠ 注意:
- // 正则表达式 的 字面量
- ⚠ // 中间写什么,就查找什么
- ⚠🔺 // 中间 不要乱加 空格
- 只要涉及到正则表达式不要乱加空格,最好用vs格式化
-
-
2️⃣ ✔检测查找是否匹配:
-
语法:
- test() :用来 查看 正则表达式 与 指定的字符串 是否匹配
jsregObj.test(被检测的字符串)
-
⚠ 返回值:
- 匹配 ➡ true
- 不匹配 ➡ false
- 规则在前面,被检测的就是用户输入的内容
-
注意:
-
-
代码展示:
js// 正则表达式 // 正则表达式使用 // 1)定义规则 // 语法:const 变量名(regObj) = /表达式/; // 注意:正则表达式的字面量中间 不要乱加空格 // 字面量中间些什么就匹配什么(不要乱加空格) // 2)是否匹配 // 语法:regObj(字面量).test(被检测的字符串); const reg = /前端/; const str = '我在学习前端,希望学完高薪就业!!!'; console.log(reg.test(str)); // true // 注意 const reg = / 前端 /; const str = '我在学习前端,希望学完高薪就业!!!'; console.log(reg.test(str)); // false // 注意 console.log(/哈/.test('哈')); // true console.log(/哈/.test('哈哈')); // true console.log(/哈/.test('二哈')); // true
-
3️⃣ ⭕检索符合规则的字符串:
-
语法:
- exec() :在一个 指定字符串 中执行一个 搜索匹配
jsregObj.exec(被检测字符串)
-
返回值:
- 匹配 ➡ 数组
- 不匹配 ➡ null
-
-
代码展示:
jsconst reg = /前端/; const str = '我在学习前端,希望学完高薪就业!!!'; console.log(reg.exec(str));
-
正则表达式检测查找 test()方法 和 exec()方法 有什么区别?
- text(): 用于判断是否有符合规则的字符串,返回的是一个布尔值,找到 返回 true ,没找到 返回 false;
- exec(): 用于检索(查找)符合规格的字符串,找到 返回 数组 ,没找到 为 null
10.2 ❗ 元字符
-
字符
- 普通字符
- 大多数的字符仅能够描述它们本身(字母数字)
- 普通字符 只能够 匹配 字符串中 与 它们 相同的字符
- 元字符
- 是一些 具有 特殊含义 的 字符
- 优点: 极大提高了 灵活性 和 强大的匹配功能
- 普通字符
-
⚠🔻 边界符、量词、字符类 组合使用
-
1️⃣ 边界符
-
表示位置,开头和结尾,必须用什么开头,用什么结尾
-
用来提示字符所处的位置
*边界符 说明 ^ 表示匹配 行首 的文本(以谁开始) $ 表示匹配 行尾 的文本(以谁结束) -
注意:
- ⚠ ^ $ 在一起,表示 必须是 精确匹配
-
代码展示:
jsconsole.log(/哈/.test('哈')); // true // 字符串的内容 和 规则相等 console.log(/哈/.test('哈哈')); // true console.log(/哈/.test('二哈')); // true console.log(/^哈/.test('哈')); // true console.log(/^哈/.test('哈哈')); // true console.log(/^哈/.test('二哈')); // flase console.log(/^哈$/.test('哈')); // true console.log(/^哈$/.test('哈哈')); // false -- 精确匹配(字符串的内容、长度必须和规则相等) console.log(/^哈$/.test('二哈')); // flase
-
-
-
2️⃣ 量词
- 表示重复次数
- 设定 某个模式 的 出现 次数
量词 说明 ***** 重复 零次 或 多次 >= 0 + 重复 一次 或 多次 >=1 ? 重复 零次 或 一次 {n} 重复 n次 {n,} 重复 n次 或 更多次 >= n {n,m} 重复 n 到 m 次 n <= 次数 <= m - ⚠🔺注意:
- 🔺n,m🔻 之间 🔺没有空格🔻
- 离量词 最近的(量词的左边) 重复,别的不重复
-
3️⃣ 字符类
-
① [] - 匹配字符集合
-
被检测的数据 只要能和 规则 匹配到 任意🔺一个🔻字符 就是 true,否则就是false
-
代码展示:
js后面的字符串只要包含abc中任意一个字符,都返回true console.log(/[abc]/.test('andy')); // true console.log(/[abc]/.test('baby')); // true console.log(/[abc]/.test('cry')); // true console.log(/[abc]/.test('die')); // false
-
精确匹配: 被检测的数据 🔺只能 🔻 和 规则 匹配 🔺一个🔻 字符 (n选1),要想多个匹配须和量词配合使用
jsconsole.log(/^[abc]$/.test('a')); // true console.log(/^[abc]$/.test('b')); // true console.log(/^[abc]$/.test('c')); // true console.log(/^[abc]$/.test('ab')); // false console.log(/^[abc]{1,}$/.test('abc')); // true
-
-
② - 连字符
- 使用连字符 - 表示一个 范围
- [a-z] : 表示 a~z 26个英文字母都可以
- [a-zA-Z] : 表示大小写都可以
- [0-9] : 表示 0~9 都可以
js[\u4e00-\u9fa5] 匹配汉字
-
代码展示:
js/^[1-9][0-9]{4,}$/ // 第一个数字:1~9;从第二位开始:0~9;可以重复>=4
-
③ ^ - 取反符号
- [] 里 加上 ^ 取反符号
- [^a-z] :匹配除了小写字母以外的字符
- ⚠ 注意: 写到 [] 里面
-
④ . 匹配 除了换行符之外的任何单位
-
⑤ 预定义类 :某些常见模式的简写方法
*预定义 说明 \d 匹配 0-9之间 的 任一数字,相当于[0-9] \D 匹配所有 0-9以外 的 字符,相当于[ ^0-9] \w 匹配任意的 字母、数字和下划线,相当于[A-Za-z0-9_] \W 除所有字母、数字和下划线以外的字符,相当于[ ^A-Za-z0-9_] \s 匹配空格(包括换行符、制表符、空格符等),相等于[\t\r\n\v\f] \S 匹配非空格的字符,相当于[ ^\t\r\n\v\f] ```js 日期:^\d{4}-\d{1,2}-\d{1,2}$ ```
-
⑥ () 使用小括号将字符包成一个整体
-
⑦ | 或
-
-
特殊符号 写到 [] 里的最后面
10.3 修饰符
-
修饰符 约束 正则表达式的某细节 行为 ,如是否区分大小写、是否支持多行匹配
-
语法:
js/表达式/修饰符
- i: (ignore)正则匹配时 不区分 大小写
- g: (global)匹配 所有 满足正则表达式 的 结果 (全局匹配)
- m: 执行多行匹配
- 代码展示:⬇
-
replace - 替换
-
语法:
js字符串.replace(/正则表达式/, '替换文本')
-
返回值: 替换好的字符串
-
代码展示:⬇
-
替换多个:
js字符串.replace(/正则表达式/g, '替换文本')
- 代码展示:⬇
-
✔ 替换多个 并且 不区分大小写:
js字符串.replace(/正则表达式/ig, '替换文本') 字符串.replace(/正则表达式/gi, '替换文本')
- ⚠🔺 g i 不区分 前后
- 代码展示:⬇
-
替换多个 并且 不区分大小写: (用正则表达式里面的 或 )
js字符串.replace(/正则表达式|正则表达式/, '替换文本')
- ⚠🔺 或(|) 两侧 不要加 空格
- 如果没有小括号,就是将正则表达式分成多份
- 代码展示:⬇
-
代码展示:
js// 修饰符:约束正则表达式的细节行为 // 语法: /正则表达式/修饰符 // i(不区分大小写) + g(匹配所有满足正则表达式的结果) // i console.log(/^java$/.test('JAVA')); // false console.log(/^java$/i.test('JAVA')); // true console.log(/^java$/i.test('JavA')); // true // 替换 - replace // 语法:字符串.replace(/正则表达式/, '替换文本') const str = 'java是一门编程语言,学完JAVA工资很高'; // 替换一个 const re1 = str.replace(/java/, '前端'); console.log(re1); // '前端是一门编程语言,学完JAVA工资很高' // 替换多个 - g const re2 = str.replace(/java/ig, '前端'); console.log(re2); // '前端是一门编程语言,学完前端工资很高' // 替换多个 - 或(|) (正则表达式里的或)(|两侧不要加空格) const re3 = str.replace(/java|JAVA/g, '前端'); console.log(re3); // '前端是一门编程语言,学完前端工资很高'
-
-
拓展:
- change - 事件
- 当鼠标离开表单,并且表单值发生变化触发
- change - 事件