DOM和BOM对象的基本内容
DOM对象
基本概念
DOM(Document Object Model——文档对象模型)是用来呈现以及与任意 HTML 或 XML文档交互的API
DOM是将整个 HTML 文档的每一个标签元素视为一个对象,这个对象下包含了许多的属性和方法,通过操作这些属性或者调用这些方法实现对 HTML 的动态更新,为实现网页特效以及用户交互提供技术支撑。
简言之 DOM 是用来动态修改 HTML 的,其目的是开发网页特效及用户交互。
DOM 树
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>标题</title>
</head>
<body>
文本
<a href="">链接名</a>
<div id="" class="">文本</div>
</body>
</html>
如下图所示,将 HTML 文档以树状结构直观的表现出来,我们称之为文档树或 DOM 树,文档树直观的体现了标签与标签之间的关系。
DOM 节点
节点是文档树的组成部分,每一个节点都是一个 DOM 对象,主要分为元素节点、属性节点、文本节点等。
- 【元素节点】其实就是 HTML 标签,如上图中
head
、div
、body
等都属于元素节点。 - 【属性节点】是指 HTML 标签中的属性,如上图中
a
标签的href
属性、div
标签的class
属性。 - 【文本节点】是指 HTML 标签的文字内容,如
title
标签中的文字。 - 【根节点】特指
html
标签。 - 其它…
DOM对象
浏览器根据html标签生成的 JS对象
所有的标签属性都可以在这个对象上面找到
修改这个对象的属性会自动映射到标签身上
DOM的核心思想
把网页内容当做对象来处理
document
document
是 JavaScript 内置的专门用于 DOM 的对象,该对象包含了若干的属性和方法,document
是学习 DOM 的核心。
<script>
// document 是内置的对象
// console.log(typeof document);
// 1. 通过 document 获取根节点
console.log(document.documentElement); // 对应 html 标签
// 2. 通过 document 节取 body 节点
console.log(document.body); // 对应 body 标签
// 3. 通过 document.write 方法向网页输出内容
document.write('Hello World!');
</script>
上述列举了 document
对象的部分属性和方法,我们先对 document
有一个整体的认识。
获取操作DOM对象
获取DOM对象
1、document.querySelector()
- 包含一个或多个有效的CSS选择器字符串
- CSS选择器匹配的第一个元素,一个 HTMLElement对象,如果没有匹配到,则返回null
2、document.querySelectorAll()
- 包含一个或多个有效的CSS选择器字符串
- 获取满足条件的元素集合,返回一个为数组
3、document.getElementById()
- 根据id获取一个元素
4、document.getElementsByTagName()
- 根据标签获取一类元素
5、document.getElementsByClassName()
- 根据类名获取元素
…
<body>
<h3>查找元素类型节点</h3>
<p>从整个 DOM 树中查找 DOM 节点</p>
<ul>
<li>元素</li>
<li>元素</li>
<li>元素</li>
<li>元素</li>
</ul>
<script>
const p = document.querySelector('p') // 获取第一个p元素
const lis = document.querySelectorAll('li') // 获取第一个p元素
</script>
</body>
任意 DOM 对象都包含 nodeType 属性,用来检检测节点类型
操作元素内容
通过修改 DOM 的文本内容,动态改变网页的内容。
innerText
将文本内容添加/更新到任意标签位置,文本中包含的标签不会被解析。
<script>
const p = document.querySelector('p')
p.innerText = '我是内容!'
</script>
innerHTML
将文本内容添加/更新到任意标签位置,文本中包含的标签会被解析。
<script>
const p = document.querySelector('p')
p.innerHTML = '我是内容!'
p.innerHTML = '<h4>我是内容!</h4>'
</script>
如果文本内容中包含 html
标签时推荐使用 innerHTML
,否则建议使用 innerText
属性。
操作元素属性
有三种方式可以实现对属性的修改:
常用属性修改
直接能过属性名修改,最简洁的语法
<script>
// 1. 获取 img 对应的 DOM 元素
const img = document.querySelector('img')
// 2. 修改属性
img.src = './images/lion.webp'
img.width = 400;
img.alt = '图片不见了...'
</script>
控制样式属性
又包含3种方式:
1、通过style属性修改
通过修改行内样式 style
属性,实现对样式的动态修改。
通过元素节点获得的 style
属性本身的数据类型也是对象
<body>
<div class="box">随便一些文本内容</div>
<script>
// 获取 DOM 节点
const box = document.querySelector('.box')
box.style.color = 'red'
box.style.width = '300px'
box.style.backgroundColor = 'pink'
</script>
</body>
任何标签都有 style
属性,通过 style
属性可以动态更改网页标签的样式
如要遇到 css
属性中包含字符 -
时,要将 -
去掉并将其后面的字母改成大写,如 background-color
要写成 box.style.backgroundColor
2、通过className操作CSS
如果修改的样式比较多,直接通过style属性修改比较繁琐,我们可以通过借助于css类名的形式。
<style>
div {
background-color: aqua;
color: red;
}
</style>
<body>
<div class="box">文本内容</div>
<script>
const box = document.querySelector('.box')
box.className = 'div'
</script>
</body>
使用className会出现覆盖,新添加的类会覆盖掉原先声明的类
3、通过classList操作类控制CSS
为了解决className 容易覆盖以前的类名,我们可以通过classList方式追加和删除类名
<style>
div {
width: 200px;
height: 200px;
background-color: red;
}
.active {
width: 300px;
height: 300px;
background-color: yellow;
}
</style>
<body>
<div class="box"></div>
<script>
// 获取元素
const box = document.querySelector('div')
// add: 添加,追加
box.classList.add('active')
// remove: 移除类
box.classList.remove('box')
// 切换类: 有就删除,没有就添加,类似取反
box.classList.toggle('box')
// contains: 判断是否有某个类,返回bool
box.classList.contains('active')
</script>
</body>
操作表单元素属性
修改表单的属性
- 获取: DOM对象.属性名
- 设置: DOM对象.属性名= 值
<body>
<input type="text" value="请输入">
<button disabled>按钮</button>
<input type="checkbox" name="" id="" class="agree">
<script>
//获取元素
const input = document.querySelector('input')
//取值或者设置值
console.log(input.value)
input.value = '小米手机'
input.type = 'password'
//启用按钮,disabled属性可以禁用按钮
const btn = document.querySelector('button')
btn.disabled = false
//勾选复选框
const checkbox = document.querySelector('.agree')
checkbox.checked = false
</script>
</body>
自定义属性
标准属性:
标签天生自带的属性 比如class id title等, 可以直接使用对象点语法操作
自定义属性:
在标签上一律以data-开头
在DOM对象上一律以dataset对象方式获取
<body>
<div data-id="1"> 自定义属性 </div>
<script>
//获取元素
let div = document.querySelector('div')
//获取自定义属性值
console.log(div.dataset.id)
</script>
</body>
事件
事件是在编程时系统内发生的动作或者发生的事情
用来描述程序的行为或状态的,一旦行为或状态发生改变,便立即调用一个函数。
用户使用鼠标点击网页中的一个按钮
事件监听
结合 DOM 使用,需要为 DOM 对象添加事件监听,等待事件发生(触发)时,便立即调用一个函数。
事件监听版本
DOM L0
事件源.on事件 = function() { }
DOM L2
事件源.addEventListener(事件, 事件处理函数)
区别:on方式会被覆盖,addEventListener方式可绑定多次,拥有事件更多特性,推荐使用
addEventListener
是 DOM 对象专门用来添加事件监听的方法,它的两个参数分别为事件类型和事件回调
<body>
<button id="btn">按钮</button>
<script>
//获取 button 对象
const btn = document.querySelector('#btn')
//添加事件监听,事件类型为点击,只要用户点击了按钮,事件便触发了
btn.addEventListener('click', function () {
console.log('事件被触发...')
})
</script>
</body>
完成事件监听步骤:
- 获取 DOM 元素
- 通过
addEventListener
方法为 DOM 节点添加事件监听 - 等待事件触发,如用户点击了某个按钮时便会触发相对应的事件类型
- 事件触发后,相对应的回调函数会被执行
事件处理程序
addEventListener
的第2个参数是函数
这个函数会在事件被触发时立即被调用,在这个函数中可以编写逻辑的代码
<body>
<p class='text'>我是p</p>
<button id="btn">按钮</button>
<script>
const btn = document.querySelector('#btn')
// 双击事件类型
btn.addEventListener('dblclick', function () {
console.log('事件被触发...')
const text = document.querySelector('.text')
// 改变 p 标签的文字颜色
text.style.color = 'red'
// 改变 p 标签的文本内容
text.style.fontSize = '20px'
})
</script>
</body>
事件类型
将众多的事件类型分类可分为:鼠标事件、键盘事件、表单事件、焦点事件等
1、鼠标事件
鼠标事件是指跟鼠标操作相关的事件,如单击、双击、移动等。
click 点击
dblclick 双击
mouseenter 监听鼠标是否移入 DOM 元素
mouseleave 监听鼠标是否移出 DOM 元素
注意点:鼠标经过事件
mouseover 和 mouseout 会有冒泡效果
mouseenter 和 mouseleave 没有冒泡效果 (推荐)
<style>
.box {
width: 200px;
height: 200px;
background: aqua;
}
</style>
<body>
<div class="box"></div>
<script>
let box = document.querySelector('.box')
box.addEventListener('mouseenter',function() {
box.style.background = 'pink'
})
box.addEventListener('mouseleave',function() {
box.style.background = 'aqua'
})
</script>
</body>
2、键盘事件
keydown 键盘按下触发
keyup 键盘抬起触发
<body>
<input type="text">
<script>
const input = document.querySelector('input');
input.addEventListener('keydown', function(){
console.log('keydown')
})
input.addEventListener('keyup', function(){
console.log('keyup')
})
input.addEventListener('input', function(){
console.log(input.value)
})
</script>
</body>
3、焦点事件
focus 获得焦点
blur 失去焦点
<body>
<input type="text">
<script>
const input = document.querySelector('input')
input.addEventListener('focus', function(){
input.value = '获得焦点'
})
input.addEventListener('blur', function(){
input.value = '失去焦点'
})
</script>
</body>
4、文本框输入事件
input 文本输入触发
<body>
<input type='text'>
<script>
document.querySelector('input').addEventListener('input', function() {
//输入内容的长度
console.log(tx.value.length)
})
</script>
</body>
5、change事件
给input注册 change 事件,只有在值被修改并且失去焦点后触发
值未被修改,失去焦点后也不会触发
事件对象
任意事件类型被触发时与事件相关的信息会被以对象的形式记录下来,我们称这个对象为事件对象。
鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box')
box.addEventListener('click', function (e) {
// 事件回调函数的第1个参数即所谓的事件对象
console.log(e)
})
</script>
</body>
事件回调函数的第1个参数即所谓的事件对象,通常习惯性的将这个对数命名为 event
、ev
、ev
事件对象中包含了许多有用的信息:
ev.type
当前事件的类型ev.clientX/Y
光标相对浏览器窗口的位置ev.offsetX/Y
光标相于当前 DOM 元素的位置key
用户按下键盘的值,已经不推荐使用keycode- …
注:在事件回调函数内部通过 window.event 同样可以获取事件对象。
环境对象
指的是函数内部特殊的变量 this ,它代表着当前函数运行时所处的环境
函数的调用方式不同,this 指代的对象也不同
const test = {
prop: 42,
func: function () {
return this.prop;
},
};
console.log(test.func());
// Expected output: 42
---------------------------------------------------------------
function getThis() {
return this;
}
const obj1 = { name: "obj1" };
const obj2 = { name: "obj2" };
obj1.getThis = getThis;
obj2.getThis = getThis;
console.log(obj1.getThis()); // { name: 'obj1', getThis: [Function: getThis] }
console.log(obj2.getThis()); // { name: 'obj2', getThis: [Function: getThis] }
注意:
this
本质上是一个变量,数据类型为对象- 函数的调用方式不同
this
变量的值也不同 - 谁调用
this
就是谁 - 函数直接调用时实际上
window.sayHi()
所以this
的值为window
回调函数
如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数。
// 声明 foo 函数
function foo(arg) {
console.log(arg);
}
// 普通的值做为参数
foo(10);
foo('hello world!');
foo(['html', 'css', 'javascript']);
function bar() {
console.log('函数也能当参数...');
}
// 函数也可以做为参数
foo(bar);
//函数 bar 做参数传给了foo函数,bar就是所谓的回调函数了
//间歇函数setInterval也用到回调函数
function fn() {
console.log('我是回调函数...');
}
// 调用定时器
setInterval(fn, 1000);
// 调用定时器,匿名函数做为参数
setInterval(function () {
console.log('我是回调函数...');
}, 1000);
回调函数本质还是函数,只不过把它当成参数使用
使用匿名函数做为回调函数比较常见
事件流
事件流指的是事件完整执行过程中的流动路径
假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段
、冒泡阶段
捕获阶段是从父到子,冒泡阶段是从子到父
实际工作都是使用事件冒泡为主
捕获和冒泡
从DOM的根元素开始去执行对应的事件 (从外到里)
事件流只会在父子元素具有相同事件类型时才会产生影响
addEventListener第三个参数:
true 代表是捕获阶段触发(很少使用)
若传入false代表冒泡阶段触发,默认就是false
注意:用 L0 事件监听,则只有冒泡阶段,没有捕获
<body>
<p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
<div class="outer">
<div class="inner">
<div class="child"></div>
</div>
</div>
<script>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer');
const inner = document.querySelector('.inner');
const child = document.querySelector('.child');
// 外层的盒子添加事件
outer.addEventListener('click', function () {
console.log('outer...')
}, true)
// 中间的盒子添加事件
inner.addEventListener('click', function () {
console.log('inner...')
}, true)
// 内层的盒子添加事件
child.addEventListener('click', function () {
console.log('child...')
}, true)
</script>
</body>
当单击事件触发时,其祖先元素的单击事件也相继触发
当某个元素的事件被触发时,事件总是会先经过其祖先才能到达当前元素,然后再由当前元素向祖先传递,事件在流动的过程中遇到相同的事件便会被触发。
如果事件是在捕获阶段执行的,我们称为捕获模式,它会先执行父盒子事件再去执行子盒子事件。
如果事件是在冒泡阶段执行的,我们称为冒泡模式,它会先执行子盒子事件再去执行父盒子事件,默认是冒泡模式。
阻止冒泡
因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素
若想把事件就限制在当前元素内,就需要阻止事件冒泡
事件对象.stopPropagation()
<body>
<p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
<div class="outer">
<div class="inner">
<div class="child"></div>
</div>
</div>
<script>
// 获取嵌套的3个节点
const outer = document.querySelector('.outer');
const inner = document.querySelector('.inner');
const child = document.querySelector('.child');
// 外层的盒子添加事件
outer.addEventListener('click', function (e) {
alert('outer...')
// e.stopPropagation()
})
// 中间的盒子添加事件
inner.addEventListener('click', function (e) {
alert('inner...')
// e.stopPropagation()
})
// 内层的盒子添加事件
child.addEventListener('click', function (e) {
alert('child...')
//阻止流动传播 事件对象.stopPropagation()
e.stopPropagation()
})
</script>
</body>
解绑事件
on事件解绑方式,直接使用null覆盖偶就可以实现事件的解绑
//绑定
btn.onclick = function () {
alert('点击了')
}
//解绑
btn.onclick = null
addEventListener方式,必须使用:
removeEventListener(事件类型, 事件处理函数, [获取捕获或者冒泡阶段])
匿名函数无法解绑
function fn() {
alert('点击了')
}
//绑定
btn.addEventListener('click', fn)
//解绑
btn.removeEventListener('click', fn)
事件委托
事件委托是利用事件流的特征解决一些现实开发需求的知识技巧,主要的作用是提升程序效率。
大量的事件监听是比较耗费性能的,如下代码所示
<script>
// 假设页面中有 10000 个 button 元素
const buttons = document.querySelectorAll('table button');
for(let i = 0; i <= buttons.length; i++) {
// 为 10000 个 button 元素添加了事件
buttons.addEventListener('click', function () {
// 省略具体执行逻辑...
})
}
</script>
利用事件流的特征,可以对上述的代码进行优化,事件的的冒泡模式总是会将事件流向其父元素的,如果父元素监听了相同的事件类型,那么父元素的事件就会被触发并执行,正是利用这一特征对上述代码进行优化,如下代码所示
<script>
// 假设页面中有 10000 个 button 元素
const buttons = document.querySelectorAll('table button');
// 假设上述的 10000 个 buttom 元素共同的祖先元素是 table
const parents = document.querySelector('table');
parents.addEventListener('click', function () {
console.log('点击任意子元素都会触发事件...');
})
</script>
我们的最终目的是保证只有点击 button 子元素才去执行事件的回调函数,如何判断用户点击是哪一个子元素呢?
事件对象中的属性 target
或 srcElement
属性表示真正触发事件的元素,它是一个元素类型的节点。
<script>
// 假设页面中有 10000 个 button 元素
const buttons = document.querySelectorAll('table button')
// 假设上述的 10000 个 buttom 元素共同的祖先元素是 table
const parents = document.querySelector('table')
parents.addEventListener('click', function (e) {
//获取点击到的子类元素e.target
console.log(e.target);
// 只有button元素才会真正去执行逻辑,通过e.target.tagName获取点击的元素标签
if(e.target.tagName === 'BUTTON') {
// 执行的逻辑
}
})
</script>
只对祖先元素添加事件监听,相比给每个元素添加事件监听,减少了注册次数,提高了程序性能
阻止默认属性
<body>
<a href="http://www.baidu.com">百度一下</a>
<script>
const a = document.querySelector('a')
a.addEventListener('click', function(e) {
//阻止默认行为,默认是跳转,现在无法跳转
e.preventDefault()
})
</script>
</body>
其他事件
页面加载事件
加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件
有些时候需要等页面资源全部加载完毕再进行一些操作
事件名:load
监听页面所有资源加载完毕:
window.addEventListener('load', function() {
// xxxxx
})
//还有一种,等待文档元素加载完毕
document.addEventListener('DOMContentLoaded', function() {
//
})
元素滚动事件
滚动条在滚动的时候持续触发的事件:scroll
获取位置:scrollLeft和scrollTop属性
数字类型,不带单位
可读取,也可赋值
window.addEventListener('scroll', function() {
// 获取html元素:document.documentElement
console.log(document.documentElement.scrollTop) //滚动了多少像素,返回的数字,不带单位
})
scrollTo()同样可以将内容滚动到指定的坐标
元素.scrollTo(x, y)
//让页面滚动到y轴1000像素
window.scrollTo(0, 1000)
页面尺寸事件
会在窗口尺寸改变的时候触发事件:resize
获取元素的可见部分宽高,不包括边框:clientWidth和clientHeight
window.addEventListener('resize', function() {
// xxxxx
})
元素尺寸与位置
1、获取元素的自身宽高、包含元素自身设置的宽高、padding、border
offsetWidth和offsetHeight
获取出来的是数值,方便计算
注意: 获取的是可视宽高, 如果盒子是隐藏的,获取的结果是0
2、获取元素距离自己定位父级元素的左、上距离
offsetLeft和offsetTop,只读属性
父级带定位时,距离父级的距离
父级不带定位,就依次往上找,直到body
3、元素尺寸位置
相当于视口的位置,也就是当前的可见屏幕
element.getBoundingClientRect()
<body>
<div></div>
<script>
const div = document.querySelector('div')
console.log(div.getBoundingClientRect())
</script>
</body>
滚动条滑动效果
用户点击电梯导航时,过渡到相应页面的效果
不加属性是直接跳转,没有过渡效果
增加属性,让滚动条丝滑的滑动
html {
scroll-behavior: smooth;
}
日期对象
日期对象:用来表示时间的对象
作用:可以得到当前系统时间
ECMAScript 中内置了获取系统时间的对象 Date,使用 Date 时与之前学习的内置对象 console 和 Math 不同,它需要借助 new 关键字才能使用。
//获取当前时间
const date = new Date()
//获取指定时间
const date = new Date('2023-11-24 18:00:00')
常用方法
const date = new Date();
//调用时间对象方法,通过方法分别获取年、月、日,时、分、秒
const year = date.getFullYear(); // 四位年份
const month = date.getMonth(); // 0 ~ 11
/*
getFullYear 获取四位年份
getMonth 获取月份,取值为 0 ~ 11
getDate 获取月份中的每一天,不同月份取值也不相同
getDay 获取星期,取值为 0 ~ 6
getHours 获取小时,取值为 0 ~ 23
getMinutes 获取分钟,取值为 0 ~ 59
getSeconds 获取秒,取值为 0 ~ 59
*/
时间戳
时间戳是指1970年01月01日00时00分00秒起至现在的总秒数或毫秒数,它是一种特殊的计量时间的方式。
ECMAScript 中时间戳是以毫秒计的。
如果计算倒计时效果,前面方法无法直接计算,需要借助于时间戳完成
获得时间戳方法:
//1、通过getTime()方法
const date = new Date()
console.log(date.getTime())
//2、new Date()可以得到当前时间,要想转为数字形式,前面加个+
console.log(+new Date())
//3、使用Date.now(),无需实例化
console.log(Date.now())
//前两种还可以返回指定时间戳,Date.now()只能返回当前时间
DOM节点
DOM树里的每一个内容都称之为节点
节点类型:
- 元素节点:所以的标签,比如body、div等,html是根节点
- 属性节点:所有的属性,比如href、id等
- 文本节点:文本内容
- 其他
重点在元素节点
查找节点
DOM 树中的任意节点都不是孤立存在的,它们要么是父子关系,要么是兄弟关系
我们可以依据节点之间的关系查找节点
通过元素节点查找
父节点查找
- 子类对象.parentNode:返回最近一级的父节点,没有则返回null
子节点查找
- 父类对象.childNodes:获得所有子节点、包括文本节点(空格、换行)、注释节点等
- 父类对象.children:仅获得所有元素节点,返回的是一个伪数组
兄弟节点查找
- 兄弟对象.nextElementSibling
- 兄弟对象.previousElementSibling
<body>
<div class="grandfather">
<div class="father">
<div class="son"></div>
<div class="sonTwo"></div>
</div>
</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
//父节点查找
const son = document.querySelector('.son')
console.log(son)
console.log(son.parentNode)//father
console.log(son.parentNode.parentNode)//grandfather
//子节点查找
const father = document.querySelector('.father')
console.log(father)
console.log(father.children)//son,sonTwo
// 兄弟节点操作
const lis = document.querySelectorAll('ul li')
// 对所有的 li 节点添加事件监听
for(let i = 0; i < lis.length; i++) {
lis[i].addEventListener('click', function () {
// 前一个节点
console.log(this.previousElementSibling)
// 下一下节点
console.log(this.nextElementSibling)
})
}
</script>
</body>
增加节点
在已有的 DOM 节点中插入新的 DOM 节点时
两个关键因素:
1、得到新的 DOM 节点
- document.createElement(‘标签’)
- 元素.cloneNode(布尔值):默认false,克隆时不包含后代节点,为true则反之
2、选择添加的位置
- 父元素.append(要追加的元素/字符串)
- 父元素.appendChild(要追加的元素)
- 父元素.insertBefore(要追加的元素, 在哪个元素前面)
<body>
<div class="grandfather">
<div class="father">
<div class="son"></div>
<div class="sonTwo"></div>
</div>
</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
//创建节点
const div = document.createElement('div')
div.innerHTML = '我是div'
//追加到父元素最后一个子元素
document.body.appendChild(div)
son.appendChild(div)
//追加到父元素某个子元素前面
const father = document.querySelector('.father')
father.insertBefore(div, father.children[0]);
//克隆节点
const sonClone = father.children[0].cloneNode(true)
father.appendChild(sonClone)
</script>
</body>
删除节点
若一个节点在页面中已不需要时,可以删除它
在JavaScript原生DOM操作中,要删除元素必须通过父元素删除
如不存在父子关系则删除不成功
- 父类对象.removeChild(要删除的元素)
<body>
<box>
<p>我是p</p>
</box>
<script>
//删除节点
const div = document.querySelector('div')
div.removeChild(div.children[0])
</script>
</body>
移动端事件
<body>
<div style="height: 200px;
width: 200px;
background: aqua;"></div>
<script>
const div = document.querySelector('div')
div.addEventListener('touchstart', function(e) {
console.log('触摸事件');
})
div.addEventListener('touchend', function(e) {
console.log('离开');
})
div.addEventListener('touchmove', function(e) {
console.log('持续触摸');
})
</script>
</body>
swiper插件
Swiper(Swiper master)是目前应用较广泛的移动端网页触摸内容滑动js插件
常用的功能性代码,都可以在swiper上找到
在网页查找到需要的功能模块,复制粘贴,再在swiper这个对象中修改需要得属性
比如:
var swiper = new Swiper(".mySwiper", {
//小圆点
pagination: {
el: ".swiper-pagination",
},
//自动播放
autoplay: {
delay: 1000,//1秒切换一次
disableOnInteraction: false, //触摸后自动播放
},
//键盘控制
keyboard: {
enabled: true,
onlyInViewport: true,
},
});
项目演示
* {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
color: #721c24;
}
h1 {
text-align: center;
color: #333;
margin: 20px 0;
}
table {
margin: 0 auto;
width: 800px;
border-collapse: collapse;
color: black;
}
th {
padding: 10px;
background: #efffcf;
font-size: 20px;
font-weight: 400;
}
td,
th {
border: 1px solid #efffcf;
}
td {
padding: 10px;
color: #666;
text-align: center;
font-size: 16px;
}
tbody tr {
background: #fff;
}
tbody tr:hover {
background: #64900b;
}
.info {
width: 900px;
margin: 50px auto;
text-align: center;
}
.info input,
.info select {
width: 80px;
height: 27px;
outline: none;
border-radius: 5px;
border: 1px solid black;
padding-left: 5px;
box-sizing: border-box;
margin-right: 15px;
}
.info button {
width: 60px;
height: 27px;
background-color: black;
outline: none;
border: 0;
color: #fff;
cursor: pointer;
border-radius: 5px;
}
.info .age {
width: 50px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>学生信息管理</title>
<link rel="stylesheet" href="css/index.css" />
</head>
<body>
<h1>新增</h1>
<form class="info" autocomplete="off">
姓名:<input type="text" class="uname" name="uname" />
年龄:<input type="text" class="age" name="age" />
性别:
<select name="gender" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
专业:<input type="text" class="speciality" name="speciality" />
户籍:<select name="city" class="city">
<option value="江西">江西</option>
<option value="浙江">浙江</option>
<option value="福建">福建</option>
<option value="湖南">湖南</option>
<option value="湖北">湖北</option>
<option value="广东">广东</option>
</select>
<button class="add">录入</button>
</form>
<h1>学生信息</h1>
<table>
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>专业</th>
<th>户籍</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//声明一个空数组
const arr = []
const tbody = document.querySelector('tbody')
const name = document.querySelectorAll('[name]')
const uname = document.querySelector('.uname')
const age = document.querySelector('.age')
const gender = document.querySelector('.gender')
const speciality = document.querySelector('.speciality')
const city = document.querySelector('.city')
//点击添加模块
const info = document.querySelector('.info')
info.addEventListener('submit', function (e) {
//阻止默认提交事件
e.preventDefault()
//为空不添加
for (let i=0; i<name.length; i++) {
if (name[i].value === '') {
alert('请填写完整')
return
}
}
//创建对象
const obj = {
stuId: arr.length +1,
uname: uname.value,
age: age.value,
gender: gender.value,
speciality: speciality.value,
city: city.value
}
// console.log(obj)
//追加给数组
arr.push(obj)
//清空填写框
this.reset()
//渲染数据
render(arr)
})
//渲染数据
function render() {
//清空页面数据
tbody.innerHTML = ''
//打印数据到页面
for (let i=0; i<arr.length; i++) {
tr = document.createElement("tr")
tr.innerHTML =
`<tr>
<td>${arr[i].stuId}</td>
<td>${arr[i].uname}</td>
<td>${arr[i].age}</td>
<td>${arr[i].gender}</td>
<td>${arr[i].speciality}</td>
<td>${arr[i].city}</td>
<td>
<a href="javascript:" data-id='${i}'>删除</a>
</td>
</tr> `
//追加数据到尾部
tbody.appendChild(tr)
}
}
//删除数据
tbody.addEventListener('click', function(e){
// console.log('11')
if (e.target.tagName == 'A') {
// console.log(e.target.dataset.id)
arr.splice(e.target.dataset.id, 1)
//删除后渲染页面
render()
}
})
</script>
</body>
</html>
BOM对象
BOM (Browser Object Model ) 是浏览器对象模型
window对象是一个全局对象,也可以说是JavaScript中的顶级对象
像document、alert()、console.log()这些都是window的属性,基本BOM的属性和方法都是window的
所有通过var定义在全局作用域中的变量、函数都会变成window对象的属性和方法
window对象下的属性和方法调用的时候可以省略window
JS执行机制
JavaScript 是一个单线程的脚本语言,同一时间只能做一件事
比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除
如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉
HTML5提出了Web Worker标准来解决这个问题,利用多核CPU的计算能力,允许JavaScript脚本创建多线程
JS中引入了同步和异步
- 同步任务:指的是在主线程上排队执行的任务,前一个任务执行完毕,才能执行后一个任务。
- 异步任务:指的是不进入主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
同步任务
同步任务都在主线程上执行,形成一个执行栈(execution context stack)
异步任务
主线程之外,还存在一个"任务队列"(task queue)。异步任务运行出结果,就在"任务队列"中放置一个事件
异步的任务会进入Event Table并注册函数,异步事情完成时,Event Table会将这个函数移入Event Queue
异步任务包含宏任务(macrotask )和微任务(microtask )
Event Loop事件循环
当主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
js引擎的monitoring process会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数
这个过程循环往复,就是所谓的事件循环
只要记住Event Loop是javascript的执行机制
简单流程图
计时事件
间歇函数
window.setInterval(func, milliseconds)
setInterval
是 JavaScript 中内置的函数,它的作用是间隔固定的时间自动重复执行另一个函数,也叫定时器函数。
setInterval返回一个正整数,这个数字是他自己的编号
关闭定时器clearInterval(定时器编号)
<script>
// 定义一个普通函数
function fun() {
console.log('不知疲倦的执行下去....')
}
//使用 setInterval 调用 repeat 函数,间隔1秒,重复调用
let n = setInterval(fun, 1000)
//关闭定时器
clearInterval(n)
</script>
延时函数
window.setTimeout(func, milliseconds)
setTimeout
同样是JavaScript 内置的一个函数,用来让代码延迟执行的
setTimeout 仅仅只执行一次,所以可以理解为就是把一段代码延迟执行, 平时省略window
延时函数需要等待,所以后面的代码先执行,且同样返回一个正整数
<script>
// 开启延迟函数
let timerId = setTimeout(function () {
console.log('我只执行一次')
}, 1000)
//延迟函数返回的还是一个正整数数字,表示延迟函数的编号
console.log(timerId)
//关闭延迟函数
clearTimeout(timerId)
</script>
弹窗事件
可以在 JavaScript 中创建三种消息框:警告框、确认框、提示框
警示框:
window.alert("sometext")
警告框经常用于确保用户可以得到某些信息
当警告框出现后,用户需要点击确定按钮才能继续进行操作
确认框:
window.confirm("sometext")
确认框通常用于验证是否接受用户操作,返回布尔类型
当确认框弹出时,用户可以点击 “确认” 或者 “取消” 来确定用户操作
当你点击 “确认”, 确认框返回 true, 如果点击 “取消”, 确认框返回 false
提示框:
window.prompt("sometext","defaultvalue")
提示框经常用于提示用户在进入页面前输入某个值
当提示框出现后,用户需要输入某个值,然后点击确认或取消按钮才能继续操纵
如果用户点击确认,那么返回值为输入的值。如果用户点击取消,那么返回值为 null
本地存储
随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常
性在本地存储大量的数据,HTML5规范提出了相关解决方案。
将数据存储在用户浏览器中
设置、读取方便、甚至页面刷新不丢失数据
容量较大,sessionStorage和localStorage约 5M 左右
localStorage
可以将数据永久存储在本地(用户的电脑), 除非手动删除,否则关闭页面也会存在
以键值对的形式存储,并且存储的是字符串
语法
存储:localStorage.setItem(key, value)
读取:localStorage.getItem(key)
删除:localStorage.removeItem(key)
1、存储基本类型
// 本地存储 - localstorage 存储的是字符串
// 1. 存储
localStorage.setItem('age', 18)
// 2. 获取
console.log(typeof localStorage.getItem('age'))
// 3. 删除
localStorage.removeItem('age')
2、存储复杂类型
由本地只能存储字符串,无法存储复杂数据类型.
需要将复杂数据类型转换成 JSON字符串,在存储到本地
再从本地拿去数据,由JSON转换成对象
语法:
JSON.stringify(复杂数据类型)
JSON.parse(JSON字符串)
// 本地存储复杂数据类型
const student = {
name: '小宁',
age: 19
}
// 1. 把对象转换为JSON字符串 JSON.stringify
localStorage.setItem('student', JSON.stringify(student))
// console.log(typeof localStorage.getItem('student'))
// 2. 把JSON字符串转换为对象 JSON.parse
console.log(JSON.parse(localStorage.getItem('student')))
sessionStorage
用法跟localStorage基本相同
区别:当页面浏览器被关闭时,存储在 sessionStorage 的数据会被清除
语法
存储:sessionStorage.setItem(key,value)
获取:sessionStorage.getItem(key)
删除:sessionStorage.removeItem(key)
其它Window对象
location对象
location (地址) 它拆分并保存了 URL 地址的各个组成部分, 它是一个对象
属性/方法 | 说明 |
---|---|
href | 属性,获取完整的 URL 地址,赋值时用于地址的跳转 |
search | 属性,获取地址中携带的参数,符号 ?后面部分 |
hash | 属性,获取地址中的啥希值,符号 # 后面部分 |
reload() | 方法,用来刷新当前页面,传入参数 true 时表示强制刷新 |
<body>
<form>
<input type="text" name="search"> <button>搜索</button>
</form>
<a href="#/music">音乐</a>
<a href="#/download">下载</a>
<button class="reload">刷新页面</button>
<script>
// location 对象
// 1. href属性 (重点) 得到完整地址
console.log(location.href)
//赋值是跳转到新地址
location.href = 'http://www.itcast.cn'
// 2. search属性 得到 ? 后面的地址
console.log(location.search) // ?pwd=1234&&username=123
// 3. hash属性 得到 # 后面的地址
console.log(location.hash)
// 4. reload 方法 刷新页面
const btn = document.querySelector('.reload')
btn.addEventListener('click', function () {
// location.reload() // 页面刷新
location.reload(true) // 强制页面刷新 ctrl+f5
})
</script>
</body>
navigator对象
navigator的数据类型是对象,该对象下记录了浏览器自身的相关信息
常用对象方法:
- 通过 userAgent 检测浏览器的版本及平台
// 检测 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://www.baidu.com'
}})();
histroy对象
history 的数据类型是对象,主要管理历史记录, 该对象与浏览器地址栏的操作相对应,如前进、后退、历史记
录等
对象方法
- back():可以后退功能
- forward():前进功能
- go(参数):参数为1前进,参数为-1表后退
history对象一般在实际开发中比较少用,但是会在一些OA 办公系统中见到
<body>
<button class="back">←后退</button>
<button class="forward">前进→</button>
<script>
// 1.前进
const forward = document.querySelector('.forward')
forward.addEventListener('click', function () {
// history.forward()
history.go(1)
})
// 2.后退
const back = document.querySelector('.back')
back.addEventListener('click', function () {
history.back()
// history.go(-1)
})
</script>
</body>
正则表达式
正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对
象
使用场景:
- 例如验证表单:手机号表单要求用户只能输入11位的数字 (匹配)
- 过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等
基本使用
语法
const reg = /表达式/
- 其中
/ /
是正则表达式字面量 - 正则表达式也是对象
使用正则
test()方法,用来查看正则表达式与指定的字符串是否匹配
- 如果正则表达式与指定的字符串匹配 ,返回true,否则false
exec() 方法,在一个指定字符串中执行一个搜索匹配
- 如果匹配成功,exec() 方法返回一个数组,否则返回null
<body>
<script>
// 正则表达式的基本使用
const str = 'web前端开发'
// 定义规则
const reg = /web/
//使用test()
console.log(reg.test(str)) //如果符合规则匹配上则返回true
console.log(reg.test('go开发')) //如果不符合规则匹配上则返回 false
//使用exec()
console.log(reg.test(str)) //返回一个数组,没有则返回null
</script>
</body>
元字符
- 普通字符:
- 大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。
- 普通字符只能够匹配字符串中与它们相同的字符。
- 比如,规定用户只能输入英文26个英文字母,普通字符的话 /[abcdefghijklmnopqrstuvwxyz]/
- 元字符(特殊字符)
- 是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
- 比如,规定用户只能输入英文26个英文字母,换成元字符写法: /[a-z]/
边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
^ | 表示匹配行首的文本(以谁开始) |
---|---|
$ | 表示匹配行尾的文本(以谁结束) |
/*
1、边界符
边界符:用来匹配字符串的开始和结束
^ 匹配字符串的开始
$ 匹配字符串的结束
同时使用^和$,且只有一个字符,就表示精确匹配
*/
console.log(/^蜀/.test('蜀道难'))//true
console.log(/道$/.test('蜀道难'))//false
//精确匹配
console.log(/^蜀$/.test('蜀'))//true
console.log(/^蜀$/.test('蜀道'))//false
量词
量词用来 设定某个模式出现的次数
量词 | 说明 |
---|---|
* | 重复零次或多次 |
+ | 重复一次或多 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或多次 |
{n,m} | 重复n到m次 |
console.log(/^蜀$/.test('蜀'))//true
console.log(/^蜀*$/.test('蜀'))//true
console.log(/^蜀+$/.test('蜀'))//true
console.log(/^蜀+$/.test('蜀道'))//false
console.log(/^蜀?$/.test('蜀'))//true
console.log(/^蜀?$/.test(''))//true
console.log(/^蜀{2}$/.test('蜀蜀'))//true
console.log(/^蜀{2}$/.test('蜀'))//false
console.log(/^蜀{2,}$/.test('蜀蜀'))//true
console.log(/^蜀{2,}$/.test('蜀蜀蜀'))//true
console.log(/^蜀{2,4}$/.test('蜀蜀蜀'))//true
console.log(/^蜀{2,4}$/.test('蜀蜀蜀蜀'))//true
console.log(/^蜀{2,4}$/.test('蜀蜀蜀蜀蜀蜀'))//false
字符类
字符类:用来匹配一组字符
[abc] 匹配a、b、c中的任意一个,只选一个
[^abc] 匹配除了a、b、c中的任意一个
[a-z] 匹配a到z之间的任意一个字符
[0-9] 匹配0到9之间的任意一个数字
. 匹配除换行符以外的任意一个字符
预定义:
\d 匹配0到9之间的任意一个数字
\D 匹配除了0到9之间的任意一个数字
\w 匹配任意一个字母或数字或下划线
\W 匹配除了字母或数字或下划线以外的任意一个字符
\s 匹配任意一个空格
\S 匹配除了空格以外的任意一个字符
console.log(/^[abc]$/.test('a'))//true
console.log(/^[abc]$/.test('b'))//true
console.log(/^[abc]$/.test('ab'))//false
console.log(/^[abc]{2}$/.test('ab'))//true
console.log(/^[a-z]$/.test('a'))//true
console.log(/^[a-z]{2}$/.test('ab'))//true
console.log(/^[0-9]$/.test('1'))//true
console.log(/^[0-9a-zA-z]$/.test('1'))//true
console.log(/^[0-9a-zA-z]$/.test('A'))//true
console.log(/^[^a-z]$/.test('a'))//false
console.log(/^[^a-z]$/.test('A'))//true
console.log(/^.$/.test('A'))//true
console.log(/^[a-zA-Z0-9_]$/.test('_'))//true
修饰符
修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等
语法:/表达式/修饰符
1、i:忽略大小写
2、g:全局匹配,全部替换掉
3、m:多行匹配
console.log(/a/i.test('A'))//true
console.log(/a/i.test('a'))//true
console.log(/a/i.test('Aa'))//true
console.log(/a/i.test('AaA'))//true
console.log(/a/g.test('AaA'))//true
替换
replace 替换方法,可以完成字符的替换
语法:字符串.replace(/正则表达式/, ‘替换的文本’)
const str = '南拳和北腿'
const re = str.replace(/南|北/g, '东')
console.log(re)//东拳和东腿