web前端知识总结三(js)
文章目录
js基础
ECMAScript部分
变量
字面量
[]数组字面量
1000数字字面量
{}对象字面量
输入 prompt()
输出 alert document.write console.log
声明变量
let var
变量的本质:是程序在内存中申请的一块用来存放数据的小空间
规则:
不能使用关键字
只能用下划线、字母、数字、$组成,且数字不能开头
字母严格区分大小写
规范:驼峰命名
var声明
可以先赋值,在声明 不合理
var声明过得变量可以重复声明 不合理
变量提示、全局变量、没有块级作用域
let为了解决var的一些问题,统一使用let
数据类型
基本数字类型:
number,string,boolean、undefined、null
js 是弱数据类型,变量到底属于那种类型,只有赋值后才能确认
模板字符串
let age=81
document。write('啊实打实${age-10}');
undefined 表示没有赋值
null表示赋值了内容为空
检查数据类型
typeof
隐式转换
+号两边有一个是字符串,会把另一个转换成字符串
除了+ 其他会把数据转换成数字类型
缺点 转换不明确
+号作为正好转换number
显示转换
数字类型
Number()转换数字类型 失败为NaN 也是数字类型
parseInt()保留整数
parseFloat(数据)保留小数
字符串型
string()
js操作符
算术运算符
±*/%
赋值运算符
= += -= *= /= %=
一元运算符
正负号 只有一个数字
++i 自加后赋值
i++ 先赋值后加1
比较运算符
>< >= <= == === !==
字符串比较,是比较的字符对应的ascll码
逻辑运算符
&& 左边为false就短路
|| 左边为true就短路
!
运算符优先级
小括号》一元运算符》算术运算符》关系运算符》相等运算符》逻辑运算符 先&&后||》赋值运算符》逗号
流程控制
表达式 3+4
语句 alert()
分支语句
if分支
三元运算符
条件?满足条件执行的代码:不满足执行的代码
switch语句
switch():
case 1:break;
case 2:continue;
default:
while循环
数组
数组添加
arr.push()
arr.unshift() 前面追加元素
数组删除
arr.pop() 删除最后一个
arr.shift() 删除第一个
arr.splice(操作的下标,删除的个数)
document.write(‘<div calss="box">’);
函数
函数的声明
function getName(x,y){
如果调用的的时候,没有传递实参,则默认为0
x=x||0;
y=y||0;
}
驼峰命名 前缀为动词
let re = function getResult(){
return 20;
}
调用
re()
return
在函数体中使用return关键字能将内部的执行结果交给函数外部使用
return后面的代码不会在被执行,会立即结束当前函数
函数可以没有return,这种情况默认返回为undefined
let re = function getResult(x,y){
return 20,30;
}
document.write(${re[0]},${re[1]})
作用域
程序代码中的所用到的名字不总是有效和可用的,限定这个名字的可用性的代码范围就是作用域。
提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
全局作用域
全局有效
作用与所有代码执行的环境,或者一个独立的js文件
局部作用域
局部有效
作用于函数内的代码环境,也成为函数函数作用域。
块级作用域
由{}包括 if语句和for语句里面的 {}等
变量的作用域
全局变量 全局能用
局部作用域下 局部变量
变量有个坑,特殊情况:如果函数内或者块级作用域,变量没有声明,直接使用,也当全局变量看,强烈不推荐
但有一种情况,函数内部的形参可以看做是局部变量。
function fn(x,y){
console.log(x,y);
}
fn(1,2)
作用域链
内部函数可以访问外部函数变量的机制,用链式查找决定那些数据能被内部函数访问,就称作作用域链
let num=10
function fn(){
let num=20
console.log(num)
}
fn()
就近原则 输出20
匿名函数
function(){}
将匿名函数赋值给一个变量,并且通过变量名称进行调用,称函数表达式
let fn=function(){}
调用 fn()
立即执行函数
(function(){console.log(111)})();
(function(){console.log(111)}());
不需要调用,立即执行
let num=10;
(function(){
防止变量污染
let num=20;
}());
多个立即函数之间加分号;不然会报错
函数传参小技巧
function fn(x=0,y=0){
console.log(x+y);
}
fn()
fn(3,5)
对象
无序的数据集合
声明对象
let 对象名={
属性名:属性值;
方法名:匿名函数
mtv:function(s){
console.log(s)}
}
属性访问:person.name person[‘name’]
调用方法:person.mtv(‘无间道’)
对象操作
修改对象属性值
obj.age=81
console.log(obj)
添加属性
obj.sex=‘男’
去对象里找这个值,如果没有则新增这个属性
删除属性
delete obj.name
遍历对象
for (let k in obj){
console.log(k) 属性名
console.log(obj[k]) 属性值
}
数组对象
let students=[
{name:asd,age:13,sad:213},
{name:asd,age:13,sad:213},
{name:asd,age:13,sad:213}
]
遍历数组对象
for(let i=0;i<students.length;i++){
console.log(students[i].name);
console.log(students[i].age);
document.write(
‘
<tr>
<td>${i+1}</td>
<td>${students[i].name}</td>
<td>${students[i].age}</td>
</tr>
’)
}
内置对象
Math
Math.PI
Math.random()随机数 [0-1)
Math.ceil() 向上取整
Math.floor() 向下取整
Math.round() 四舍五入
Math.max()找最大值
Math.min()找最小值
Math.pow()幂运算
Math.abs()绝对值
封装随机函数
function getRandom(min,max){
return Math.floor(Math.random()*(max-min+1))+min;
}
术语
关键字
let var function if else switch case break
保留字
int short long char
标识符=变量名 函数名
表达式 10+3 age>=18
值类型 string number boolean undefined null
引用类型 复杂数据类型,在存储时变量中储存的仅仅是地址,因此叫做引用数据类型,通过new 关键字创建的对象 object array date
栈 可以储存简单数据,自动分别存放函数的参数值、局部变量的值
堆 可以储存复杂数据 (对象),程序员不释放,由垃圾回收机制回收
复杂数据,栈里存储地址,根据地址在堆里找数据
数据类型的存储方式
let num1=10
let num2=num1
num2=20
console.log(num1)
输出10
num1和num2不影响
简单数据类型存储的是值
对象引用数据类型 栈里存储的是地址
let obj1={
age:10
}
let obj2=obj1
obj2.age=20
console.log(obj1)
输出20
obj2和obj1指向相同的堆
Web Api
DOM
DOM 文档对象模型 作用:使用js操作html和浏览器 操作网页内容 实现用户交互
BOM浏览器对象模型
DOM树
又称文档树
直观的体现了标签与标签之间的关系
DOM对象
document对象
访问和操作网页内容的 document.write()
元素节点 属性节点 文本节点
元素对象代表着一个 HTML 元素。
document 对象属性
属性 | 描述 |
---|---|
body | 提供对 元素的直接访问。对于定义了框架集的文档,该属性引用最外层的 。 |
cookie | 设置或返回与当前文档有关的所有 cookie。 |
domain | 返回当前文档的域名。 |
lastModified | 返回文档被最后修改的日期和时间。 |
referrer | 返回载入当前文档的文档的 URL。 |
title | 返回当前文档的标题。 |
URL | 返回当前文档的 URL。 |
element.className | 设置或返回元素的class属性 |
Document 对象方法
方法 | 描述 |
---|---|
close() | 关闭用 document.open() 方法打开的输出流,并显示选定的数据。 |
element.getAttribute() | 返回指定元素的属性值 |
element.getAttributeNode() | 返回指定属性节点 |
getElementById() | 返回对拥有指定 id 的第一个对象的引用。 |
getElementsByName() | 返回带有指定名称的对象集合。 |
getElementsByTagName() | 返回带有指定标签名的对象集合。 |
element. getElementsByClassName() | 返回文档中所有指定类名的元素集合,作为 NodeList 对象。 |
open() | 打开一个流,以收集来自任何 document.write() 或 document.writeln() 方法的输出。 |
write() | 向文档写 HTML 表达式 或 JavaScript 代码。 |
writeln() | 等同于 write() 方法,不同的是在每个表达式之后写一个换行符。 |
element.focus() | 设置文档或元素获取焦点 |
element.appendChild() | 为元素添加一个新的子元素 |
element.addEventListener() | 向指定元素添加事件句柄 |
element.hasAttribute() | 如果元素中存在指定的属性返回 true,否则返回false。 |
element.hasChildNodes() | 返回一个元素是否具有任何子元素 |
element.hasFocus() | 返回布尔值,检测文档或元素是否获取焦点 |
element.toString() | 一个元素转换成字符串 |
element.insertBefore() | 现有的子元素之前插入一个新的子元素 |
element.isEqualNode() | 检查两个元素是否相等 |
element.isSameNode() | 检查两个元素所有有相同节点。 |
element.querySelector() | 返回匹配指定 CSS 选择器元素的第一个子元素 |
document.querySelectorAll() | 返回匹配指定 CSS 选择器元素的所有子元素节点列表 |
element.removeAttribute() | 从元素中删除指定的属性 |
element.removeAttributeNode() | 删除指定属性节点并返回移除后的节点。 |
element.removeChild() | 删除一个子元素 |
element.removeEventListener() | 移除由 addEventListener() 方法添加的事件句柄 |
element.replaceChild() | 替换一个子元素 |
element.setAttributeNode() | 设置或者改变指定属性节点。 |
element.setIdAttribute() | |
element.setIdAttributeNode() |
Document 对象集合
集合 | 描述 |
---|---|
[all] | 提供对文档中所有 HTML 元素的访问。 |
[anchors] | 返回对文档中所有 Anchor 对象的引用。 |
applets | 返回对文档中所有 Applet 对象的引用。 |
[forms] | 返回对文档中所有 Form 对象引用。 |
[images] | 返回对文档中所有 Image 对象引用。 |
[links] | 返回对文档中所有 Area 和 Link 对象引用。 |
获取DOM对象
选择匹配的第一个元素
document.querySelector('css选择器'); (ul li:last-child)
参数:包含一个或多个有效的css选择器
返回值:css选择器匹配的第一个元素,一个HTMLELement对象 :<div class="tree"></div>
如果没有匹配到返回null
选择匹配的多个元素
document.querySelectorAll('css选择器');
参数:包含一个或多个有效的css选择器字符串
document.querySelectorAll('ul li');
必须是字符串,也就是必须加引号
设置/修改DOM元素内容
document.write()
将文本内容追加到</body>前面的位置
文本中包含的标签会被解析
对象.innerText属性
将文本内容添加/更新到任意标签位置
文本内的标签不会被解析
let box=document.querySelectot('div');
box.innerText='<strong>有点意思</strong>'
对象.innerHtml属性
将文本内容添加/更新到任意标签位置
文本内的标签会被解析
设置/修改DOM元素属性
对象.属性=值
let pic=document.querySelector('img');
pic.src='./images/${num}.jpg'
pic.title='这是一个图片'
设置/修改DOM元素样式属性
元素.className=’active'
修改元素类名,会覆盖原有类名
通过classList操作控制css
为了解决覆盖类名,使用classlist
let box==document.querySelector('div');
元素.classList.add('类名') 添加类名
元素.classList.remove('类名') 移除类名
元素.classList.toggle('类名') 切换类名:有就删除,没有就添加
修改元素样式属性style
document.body.style.backgroundImage=url('./images/desktop.jpg')
document.body.style+样式属性
设置/修改表单元素属性
let input==document.querySelector('input');
input.value='小米'
input.type=‘password’
let button==document.querySelector('button');
button.disable = false
let checkbox==document.querySelector('checkbox');
checkbox.checked=true
HTML DOM Element 对象
childNodes返回元素的一个子节点的数组 | attributes 返回一个元素的属性数组 |
---|---|
element.children | 返回元素的子元素的集合 |
element.classList | 返回元素的类名,作为 DOMTokenList 对象。 |
element.className | 设置或返回元素的class属性 |
element.clientTop | 表示一个元素的顶部边框的宽度,以像素表示。 |
element.clientLeft | 表示一个元素的左边框的宽度,以像素表示。 |
element.clientHeight | 在页面上返回内容的可视高度(高度包含内边距(padding),不包含边框(border),外边距(margin)和滚动条) |
element.clientWidth | 在页面上返回内容的可视宽度(宽度包含内边距(padding),不包含边框(border),外边距(margin)和滚动条) |
element.dir | 设置或返回一个元素中的文本方向 |
element.firstChild | 返回元素的第一个子节点 |
element.id | 设置或者返回元素的 id。 |
element.innerHTML | 设置或者返回元素的内容。 |
element.contentEditable | 设置或返回元素的内容是否可编辑 |
element.classList | 返回元素的类名,作为 DOMTokenList 对象。 |
element.lastChild | 返回最后一个子节点 |
element.lastElementChild | 返回指定元素的最后一个子元素 |
element.nextSibling | 返回该元素紧跟的一个节点 |
element.nextElementSibling | 返回指定元素之后的下一个兄弟元素(相同节点树层中的下一个元素节点)。 |
element.nodeValue | 返回元素的节点值 |
element.offsetHeight | 返回任何一个元素的高度包括边框(border)和内边距(padding),但不包含外边距(margin) |
element.offsetWidth | 返回元素的宽度,包括边框(border)和内边距(padding),但不包含外边距(margin) |
element.offsetLeft | 返回当前元素的相对水平偏移位置的偏移容器 |
element.offsetParent | 返回元素的偏移容器 |
element.parentNode | 返回元素的父节点 |
element.previousSibling | 返回某个元素紧接之前元素 |
element.previousElementSibling | 返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。 |
element.scrollLeft | 返回当前视图中的实际元素的左边缘和左边缘之间的距离 |
element.scrollTop | 返回当前视图中的实际元素的顶部边缘和顶部边缘之间的距离 |
element.scrollWidth | 返回元素的整个宽度(包括带滚动条的隐蔽的地方) |
element.style | 设置或返回元素的样式属性 |
element.tabIndex | 设置或返回元素的标签顺序。 |
element.tagName | 作为一个字符串返回某个元素的标记名(大写) |
element.textContent | 设置或返回一个节点和它的文本内容 |
nodelist.length | 返回节点列表的节点数目。 |
element.value | 元素的内容 |
查找父节点childNodes
document.getElementById("item1").parentNode;
返回元素子节点的 NodeList childNodes
document.body.childNodes;
兄弟节点nextSibling 、previousSibling
document.getElementById("item1").nextSibling;
返回位于相同节点树层级的下一个节点。
document.getElementById("item2").previousSibling;
属性返回同一树层级中指定节点的前一个节点。
创建新节点createElement
var node=document.createElement("LI");
var textnode=document.createTextNode("Water");
node.appendChild(textnode);
document.getElementById("myList").appendChild(node);
向元素添加新的子节点,作为最后一个子节点。
var newItem=document.createElement("LI")
var textnode=document.createTextNode("Water") 把文本添加在li标签里,在添加在节点前
newItem.appendChild(textnode)
var list=document.getElementById("myList")
list.insertBefore(newItem,list.childNodes[0]);
var node=document.getElementById("myList2").lastChild;
var list=document.getElementById("myList1");
list.insertBefore(node,list.childNodes[0]);
在指定的已有的子节点之前插入新节点。 添加在开头
克隆节点cloneNode
var node=document.getElementById("myList2").lastChild.cloneNode(true);
document.getElementById("myList1").appendChild(node);
把一个列表项从一个列表复制到另一个:
删除子节点removeChild
var list=document.getElementById("myList");
list.removeChild(list.childNodes[0]);
如不存在父子关系则删除不成功
删除和隐藏有区别,隐藏节点还是存在
返回指定属性名的属性值
document.getElementsByTagName("a")[0].getAttribute("target");
定时器
this指向的window
开启定时器
setInterval(函数,间隔时间);
作用:每隔一段时间调用这个函数
时间单位是毫秒
function re(){
console.log("赛道年"):
}
setInterval(re,1000);
setInterval(function(){
console.log("赛道年"):
},1000);
关闭定时器
function re(){
console.log("赛道年"):
}
let timer=setInterval(re,1000);
清除定时器
clearInterval(timer);
倒计时例子
例子一
// 1. 获取元素 button
let btn = document.querySelector('.btn')
// 2. 计算逻辑
// 2.1 我们需要一个变量 用来计数
let i = 6
// 2.2 开启定时器 间歇函数 timer 定时器的序号id
let timer = setInterval(function () {
i--
btn.innerHTML = `我已经阅读用户协议(${i})`
if (i === 0) {
// 不走了,清除定时器
clearInterval(timer)
// 开启按钮
btn.disabled = false
// 更换文字
btn.innerHTML = '我同意该协议啦'
}
}, 1000)
例子二
et data = [
{
imgSrc: 'images/b01.jpg',
title: '挑战云歌单,欢迎你来'
},
{
imgSrc: 'images/b02.jpg',
title: '田园日记,上演上京记'
},];
// 1. 获取元素 图片 和 h3
let pic = document.querySelector('.pic')
let text = document.querySelector('.text')
// i 记录图片的张数
let i = 0
// 2.开启定时器
setInterval(function () {
i++
// 修改图片的src属性
// console.log(data[i].imgSrc)
pic.src = data[i].imgSrc
// 修改文字内容
text.innerHTML = data[i].title
// 无缝衔接
if (i === data.length - 1) {
i = -1
}
// i === 8 ? i = -1 : i
}, 1000)
事件
元素.addEventlistener(‘事件‘,执行函数)
事件:click mouseover
element.addEventListener(event, function, useCapture);
第一个参数是事件的类型 (如 “click” 或 “mousedown”).
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。
// 数据数组
let arr = ['马超', '黄忠', '赵云', '关羽', '张飞']
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
// 1. 获取元素 两个按钮 + div
// 一定不要忘记加点 因为里面写css类选择器
let start = document.querySelector('.start')
let end = document.querySelector('.end')
let qs = document.querySelector('.qs')
// timer 要是全局变量
let timer = 0
// random 要是全局变量
let random = 0
// 2. 给开始按钮注册事件
start.admousedEventListener('click', function () {
// 随机抽数据--- 快速不断的抽取 间歇函数定时器
timer = setInterval(function () {
random = getRandom(0, arr.length - 1)
qs.innerHTML = arr[random]
}, 25)
// 如果到了最后一个,就禁用两个按钮
if (arr.length === 1) {
// console.log('没了')
// start.disabled = true
// end.disabled = true
start.disabled = end.disabled = true
}
})
// 3. 给结束按钮注册事件 本质是停止定时器
end.addEventListener('click', function () {
// 停止定时器
clearInterval(timer)
// 删除数组元素
arr.splice(random, 1)
// console.log(arr)
})
事件类型
事件 | 描述 |
---|---|
onchange | HTML 元素改变 |
onclick | 用户点击 HTML 元素 |
onmouseover | 鼠标指针移动到指定的元素上时发生 |
onmouseout | 用户从一个 HTML 元素上移开鼠标时发生 |
onkeydown | 用户按下键盘按键 |
onload | 浏览器已完成页面的加载 |
原先使用
<button onclick="displayDate()">现在的时间是?</button>
鼠标事件
click mouseenter mouseleave mouseover mouseout
焦点事件
focus blur
键盘事件
keydown keyup
文本事件
input
全选反选案例
// 1. 获取元素 全选 和 ck 小复选框
let all = document.querySelector('#checkAll')
let cks = document.querySelectorAll('.ck')
let span = document.querySelector('span')
// 2. 事件监听 全选按钮
all.addEventListener('click', function () {
// console.log(all.checked) // true false
// 我们需要做的就是把 all.checked 给下面三个小按钮
// 因为三个按钮在伪数组里面,我们需要遍历的方式,挨着取出来,依次给值
for (let i = 0; i < cks.length; i++) {
cks[i].checked = all.checked
}
// 当我们的全选按钮处于选中状态,则可以改为取消
if (all.checked) {
// console.log('要改')
span.innerHTML = '取消'
} else {
span.innerHTML = '全选'
}
})
// 3. 小按钮的做法 同时给多个元素绑定相同事件
for (let i = 0; i < cks.length; i++) {
// 绑定事件
cks[i].addEventListener('click', function () {
// console.log(11)
// 只要点击任何一个小按钮,都要遍历所有的小按钮
for (let j = 0; j < cks.length; j++) {
// 都来看看是不是有人没有选中
if (cks[j].checked === false) {
// 如果有false 则退出循环 结束函数
all.checked = false
span.innerHTML = '全选'
return
}
}
// 当我们的循环结束,如果代码走到这里,说明没有false,都被选中了,则全选按钮要选中
all.checked = true
span.innerHTML = '取消'
})
}
购物车加减案例
// 1. 获取元素 三个
let total = document.querySelector('#total')
let add = document.querySelector('#add')
let reduce = document.querySelector('#reduce')
// 2. 点击加号 事件侦听
add.addEventListener('click', function () {
// console.log(typeof total.value)
// total.value = total.value + 1
// i++ 隐式转换
// i = i + 1
total.value++
reduce.disabled = false
})
// 3. 点击减号 事件侦听
reduce.addEventListener('click', function () {
total.value--
if (total.value <= 1) {
reduce.disabled = true
}
})
高阶函数
回调函数
如果将函数A做为参数传递给函数B时,我们称函数A为回调函数
本质还是函数,只不过当参数使用
使用匿名函数常见
let num = 10
//函数表达式
let fn = function () { }
btn.onclick = function () { }
// 高阶函数 函数的高级用法,把函数当值来看看
// 回调函数
// setInterval(function(){}, 1000)
function fn() { }
setInterval(fn, 1000)
// 此时 fn 就是回调函数 回头去调用的函数
box.addEventListener('click', fun)
function fun() {
}
环境对象
指函数内部特殊的变量this,代表着当前函数运行时所在的环境
// 环境对象 this 他就是个对象
function fn() {
console.log(this)
}
// fn()
window.fn()
window调用了这个函数
let btn = document.querySelector('button')
btn.addEventListener('click', function () {
console.log(typeof this)
// 因为btn 调用了这个函数,所以 this 指向btn
})
函数的调用方式不同,this指代的对象也不同
谁调用,this就是谁
排他思想
<body>
<button>第1个</button><button>第2个</button><button>第3个</button><button>第4个</button><button>第5个</button>
<script>
let btns = document.querySelectorAll('button')
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
// this.classList.add('pink')
// 干掉所有人
for (let j = 0; j < btns.length; j++) {
btns[j].classList.remove('pink')
}
// 复活我自己
this.classList.add('pink')
})
}
</script>
</body>
升级
<body>
<button class="pink">第1个</button><button>第2个</button><button>第3个</button><button>第4个</button><button>第5个</button>
<script>
let btns = document.querySelectorAll('button')
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
// this.classList.add('pink')
// // 干掉所有人
// for (let j = 0; j < btns.length; j++) {
// btns[j].classList.remove('pink')
// }
// 我只需要找出那个唯一的 pink类,删除
document.querySelector('.pink').classList.remove('pink')
// 我的
this.classList.add('pink')
})
}
</script>
tab栏案例
<body>
<div class="wrapper">
<ul class="tab">
<li class="tab-item active">国际大牌<span>◆</span></li>
<li class="tab-item">国妆名牌<span>◆</span></li>
<li class="tab-item">清洁用品<span>◆</span></li>
<li class="tab-item">男士精品</li>
</ul>
<div class="products">
<div class="main active">
<a href="###"><img src="imgs/guojidapai.jpg" alt="" /></a>
</div>
<div class="main">
<a href="###"><img src="imgs/guozhuangmingpin.jpg" alt="" /></a>
</div>
<div class="main">
<a href="###"><img src="imgs/qingjieyongpin.jpg" alt="" /></a>
</div>
<div class="main">
<a href="###"><img src="imgs/nanshijingpin.jpg" alt="" /></a>
</div>
</div>
</div>
<script>
// 0. 获取元素
// 得到所有的小li
let lis = document.querySelectorAll('.tab .tab-item') //tab下面的tab-item
let divs = document.querySelectorAll('.products .main')
// 1. 头部tab栏切换模块
// 1.1 先给4个小li添加点击事件
for (let i = 0; i < lis.length; i++) {
lis[i].addEventListener('click', function () {
// console.log(11)
// 找到以前的active 类,移除掉
document.querySelector('.tab .active').classList.remove('active')
// 当前的元素添加
this.classList.add('active')
// 2. 底部显示隐藏模块 一定要写到点击事件的里面
document.querySelector('.products .active').classList.remove('active')
// div对应序号的那个加上active
divs[i].classList.add('active')
})
}
</script>
</body>
节点操作
DOM树里每一个内容都称之为节点
元素节点 body div html
属性节点 href 所有属性
文本节点 所有文本
父节点查找
子元素.parentNode
找不到返回NULL
能返回父节点的class
关闭多个二维码
// 1. 获取元素 关闭按钮
let close_btn = document.querySelectorAll('.close')
// 2. 绑定多个点击事件给close
for (let i = 0; i < close_btn.length; i++) {
close_btn[i].addEventListener('click', function () {
// 3. 关闭当前的那个二维码 点击谁,就关闭谁的爸爸
this.parentNode.style.visibility = 'hidden'
})
}
获取子节点
父元素.children 返回标签名数组 [li,li,li,li,li]
父元素.childNodes 所有子节点
查找兄弟节点
nextElementSibling 下一个兄弟节点
previousElementSibling 上一个兄弟节点
增加节点
// 二毛 ul.children[1]
// 1. 创建新的标签节点
// let div = document.createElement('div')
// div.className = 'current'
let ul = document.querySelector('ul')
let li = document.createElement('li')
li.innerHTML = '我是xiao ming'
// 2. 追加节点 父元素.appendChild(子元素) 后面追加
// ul.appendChild(li)
// 3. 追加节点 父元素.insertBefore(子元素, 放到那个元素的前面)
ul.insertBefore(li, ul.children[0])
克隆节点
删除节点
// 需求,点击按钮,删除小li
let btn = document.querySelector('button')
let ul = document.querySelector('ul')
btn.addEventListener('click', function () {
// 删除的语法 父元素.removeChild(子元素)
ul.removeChild(ul.children[0])
})
从父元素删除
时间对象
let date =new date()
let arr=[]
let arr=new Array()
let obj=[]
let obj=new Object()
获取指定时间
let date=new date('1949-10-1 18:30:00')
// new 实例化 时间对象
// 小括号为空可以得到当前的时间
let date = new Date()
console.log(date.getFullYear())
console.log(date.getMonth() + 1)
console.log(date.getDate())
// 时分秒
console.log(date.getHours())
console.log(date.getMinutes())
console.log(date.getSeconds())
// 星期几
console.log(date.getDay())
显示时间
let arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
let div = document.querySelector('div')
// 先调用,就省去了1秒的空白期
getTime()
setInterval(getTime, 1000)
function getTime() {
// 1. 实例化时间对象 一定写到定时器里面才可以额
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth() + 1
let date1 = date.getDate()
let hour = date.getHours()
let min = date.getMinutes()
let sec = date.getSeconds()
let day = date.getDay()
div.innerHTML = `今天是: ${year}年${month}月${date1}日 ${hour}:${min}:${sec} ${arr[day]}`
}
时间戳
// 时间戳是总的毫秒数 是独一无二的
// 计算倒计时: 核心思想:
// 将来时间 9.1 12:00 有一个时间戳 2000000
// 现在的时间 8.29 15:00 有一个时间戳 1000000
// 可以利用将来的时间戳 减去 现在的时间戳 就是剩余的时间毫秒数
// 转换为时分秒就是剩余的时间了
// 1. getTime()
// let date = new Date()
// console.log(date.getTime())
// 2. +new Date()
console.log(+new Date()) // 当前的时间戳
console.log(+new Date('2021-8-30 12:00:00')) // 指定时间的时间戳
// 3. 只能得到当前的
// console.log(Date.now())
倒计时
let hour = document.querySelector('#hour')
let minutes = document.querySelector('#minutes')
let scond = document.querySelector('#scond')
time()
setInterval(time, 1000)
function time() {
// 1. 得到现在的时间戳
let now = +new Date()
// 2. 得到指定时间的时间戳
let last = +new Date('2021-8-29 18:30:00')
// 3. (计算剩余的毫秒数) / 1000 === 剩余的秒数
let count = (last - now) / 1000
// console.log(count)
// 4. 转换为时分秒
// h = parseInt(总秒数 / 60 / 60 % 24) // 计算小时
let h = parseInt(count / 60 / 60 % 24)
h = h < 10 ? '0' + h : h
// m = parseInt(总秒数 / 60 % 60); // 计算分数
let m = parseInt(count / 60 % 60)
m = m < 10 ? '0' + m : m
// s = parseInt(总秒数 % 60); // 计算当前秒数
let s = parseInt(count % 60);
s = s < 10 ? '0' + s : s
// console.log(h, m, s)
hour.innerHTML = h
minutes.innerHTML = m
scond.innerHTML = s
}
li.innerHTML = `
<div class="info">
<img class="userpic" src=${dataArr[random].imgSrc}>
<span class="username">${dataArr[random].uname}</span>
<p class="send-time"> ${new Date().toLocaleString()} </p>
</div>
<div class="content">${textarea.value}</div>
<span class="the_del">X</span>
’
let del = li.querySelector('.the_del')
del.addEventListener('click', function () {
// 删除操作 点击的是X 删除的小li 父元素.removeChild(子元素)
ul.removeChild(li)
})
重绘和回流
浏览器如何进行页面渲染的?
解析html,生成dom树
同时解析css,生成样式规则
根据dom树和样式规则,生成渲染树
进行布局layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置、大小)——————画盒子,渲染布局
进行绘制panting(重绘):根据计算和获取的信息进行整个页面的绘制
display展示在页面上
回流(重排)
当渲染树中部分或全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过程成文回流
重绘
由于节点的样式的改变并不影响它在文档流中的位置和文档布局(color、background-color、outline)称为重绘
作用域
// let num = 10
// {
// let num = 20
// console.log(num)
// }
// console.log(num)
(function () {
let num = 10
}())
let num = 20
事件对象e
<button>点击</button>
<script>
let btn = document.querySelector('button')
btn.addEventListener('mouseenter', function (e) {
console.log(e)
})
</script>
e、event、ev
常用属性
type 获取当前事件类型
clientx/clienty 获取光标相对于浏览器可见窗口左上角的位置
offsetx/offsety 获取光标相对域当前dom元素左上角的位置
key 用户按下的键盘键的值
不提倡使用keycode
if(e.key=='Enter'){
send.click()
}
pagex/pagey 跟文档坐标有关系
clientX:触摸目标在视口中的x坐标。
clientY:触摸目标在视口中的y坐标。
identifier:标识触摸的唯一ID。
pageX:触摸目标在页面中的x坐标。
pageY:触摸目标在页面中的y坐标。
screenX:触摸目标在屏幕中的x坐标。
screenY:触摸目标在屏幕中的y坐标。
鼠标跟随移动
<img src="./images/tianshi.gif" alt="">
<script>
let img = document.querySelector('img')
document.addEventListener('mousemove', function (e) {
// 不断得到当前的鼠标坐标
// console.log(e.pageX)
// console.log(e.pageY)
// 把坐标给图片
// img.style.left = '100px'
img.style.left = e.pageX - 50 + 'px'
img.style.top = e.pageY - 40 + 'px'
})
</script>
事件流
指事件完整执行过程中的流动路径
捕获阶段 document—element html—element body— element div 从父到子
冒泡阶段 div—body—html—document 从子到父
触发事件会经历两个阶段 捕获阶段 冒泡阶段
事件冒泡和事件捕获
当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。
当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('click', function () {
alert('我是爸爸')
}, true)
son.addEventListener('click', function () {
alert('我是儿子')
}, true)
document.addEventListener('click', function () {
alert('我是爷爷')
}, true)
// btn.onclick = function() {}
DOM.addEventListener(事件类型,函数,是否使用捕获机制)
事件冒泡是默认存在的
false代表冒泡阶段触发,默认就是false
true代表捕获阶段触发
阻止事件流动
事件对象.stopPropagation()
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('click', function (e) {
alert('我是爸爸')
e.stopPropagation()
})
son.addEventListener('click', function (e) {
alert('我是儿子')
// 阻止流动 Propagation 传播
e.stopPropagation() 只执行自己
})
document.addEventListener('click', function () {
alert('我是爷爷')
})
mouseover和mouseenter区别
mouseover和mouseout有冒泡
mouseenter 和mouseleave没有冒泡(推荐)
<div class="father">
<div class="son"></div>
</div>
<script>
let fa = document.querySelector('.father')
let son = document.querySelector('.son')
fa.addEventListener('mouseenter', function () {
console.log(111)
})
</script>
阻止默认行为
如链接点击不跳转,表单域的跳转
e.preventDefault()
<a href="http://www.baidu.com">跳转到百度</a>
<script>
let a = document.querySelector('a')
a.addEventListener('click', function (e) {
// 阻止默认行为 方法
e.preventDefault()
})
</script>
两种注册事件的区别
传统on
后面的事件会覆盖前面的同一个事件
直接使用null覆盖就可以实现事件的解绑
都是冒泡执行
事件监听注册
后面注册的事件不会覆盖前面的注册事件 同一个事件
可以通过第三个参数确定冒泡或捕获
解绑必须使用removeEventListener(事件类型,函数,冒泡或捕获)
匿名函数无法被解绑
<button>点击</button>
<script>
let btn = document.querySelector('button')
// 1.l0 on
// 多次相同的事件,只执行最后一次
// btn.onclick = function () {
// alert('第一次')
// }
// btn.onclick = function () {
// alert('第二次')
// }
// 解绑事件
// btn.onclick = null
// 2. addEventListener
btn.addEventListener('click', add)
function add() {
alert('第一次')
}
// btn.addEventListener('click', function () {
// alert('第二次')
// })
btn.removeEventListener('click', add)
事件委托
jquery封装了事件委托的支持
//直接绑定
$('选择器').on('事件名',function(){})
//事件委托 原理:事件冒泡
$('祖先选择器').on('事件名','后代选择器',function(){})
减少事件注册
解决动态增加后代元素的绑定问题
// 不要每个小li注册事件了 而是把事件委托给他的爸爸
// 事件委托是给父级添加事件 而不是孩子添加事件
let ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
// alert('我点击了')
// 得到当前的元素
// console.log(e.target)
e.target.style.color = 'red'
})
手风琴案例
<body>
<div id="box">
<ul>
<li>
<a href="#">
<img src="./images/1.jpg" alt="">
</a>
</li>
<li>
<a href="#">
<img src="./images/2.jpg" alt="">
</a>
</li>
<li>
<a href="#">
<img src="./images/3.jpg" alt="">
</a>
</li>
<li>
<a href="#">
<img src="./images/4.jpg" alt="">
</a>
</li>
<li>
<a href="#">
<img src="./images/5.jpg" alt="">
</a>
</li>
</ul>
</div>
</body>
// 获取元素
let box = document.querySelectorAll('li');// lis = [li, li, li, li, li]
// 分析:
// 1、鼠标进入显示图片,
// 鼠标进入li,让当前li变成800,其他的li变成100
for (let i = 0; i < box.length; i++) {
box[i].addEventListener('mouseenter', function () {
for (let j = 0; j < box.length; j++) {// 事件触发执行,为了让所有li变成240宽的
box[j].style.width = '100px';
}
this.style.width = '800px'
})
box[i].addEventListener('mouseleave', function () {
// 让所有的li变成240
for (let j = 0; j < box.length; j++) {// 事件触发执行,为了让所有li变成240宽的
box[j].style.width = '240px';
}
})
页面滚动事件
事件名:scroll
<body>
<div>
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
我里面可以放很多的文字
</div>
<script>
let div = document.querySelector('div')
window.addEventListener('scroll', function () {
console.log(111)
})
// div.addEventListener('scroll', function () {
// console.log(111)
// })
</script>
页面加载事件
不光可以监听整个页面资源加载完毕,也可以针对某个资源邦迪load事件
<script>
window.addEventListener('load', function () {
let div = document.querySelector('div')
console.log(div)
})
</script>
当初始html文被完全加载和解析完成后,DOMcontentLoaded事件被触发,无需等待样式、图像完全加载
事件名:DOMcontentLoaded
给document添加事件
document.addEventListener('DOMcontentLoaded', function () {
})
Scroll家族
获取宽高:
获取内容总宽高 不含滚动条
scrollwidth和scrollHeight
获取位置:
scrollLeft ScrollTop 可以修改
获取元素内容往左、往上滚出去看不到的距离
// scrollWidth scrollHeight 内容 宽高 (了解)
let div = document.querySelector('div')
console.log(div.scrollWidth) // 150 不带单位
console.log(div.scrollHeight) // 336 不带单位
// div.addEventListener('scroll', function () {
// console.log(document.querySelector('div').scrollTop)
// })
div {
width: 150px;
height: 150px;
background-color: pink;
overflow: auto;
padding: 10px;
border: 10px solid red;
margin: 100px;
}
检查页面滚动距离
console.log(document.documentElement) // 返回 html 元素
// 可以修改 但是不要带单位
// 先做页面滚动事件
window.addEventListener('scroll', function () {
// console.log(11)
// 在得到页面滚动的距离 scrollTop
console.log(document.documentElement.scrollTop)
// document.documentElement.scrollTop = 500
})
Offset家族
获取宽高:
获取元素自身宽高、包含元素自身设置的宽高、padding、border
offsetWidth offsetHeight
内容超出盒子 以内容为准
获取位置:
获取元素距离自己定位父级元素的左、上位置
offsetLeft offsetTop 注意是只读属性
// offset 盒子元素的大小 = 盒子本身的宽度和高度 + padding + border
console.log(div.offsetWidth) // 150 不带单位
console.log(div.offsetHeight) // 150 不带单位
// console.log(div.offsetTop) //
// console.log(div.offsetLeft)
京东固定头部
let sk = document.querySelector('.sk')
let header = document.querySelector('.header')
// 1. 页面滚动事件
window.addEventListener('scroll', function () {
// console.log(11)
// 要检测滚动的距离
// console.log(document.documentElement.scrollTop)
// console.log(sk.offsetTop)
// 2. 要检测滚动的距离 >= 秒杀模块的offsetTop 则滑入
if (document.documentElement.scrollTop >= sk.offsetTop) {
// alert('改吃饭了')
header.style.top = '0'
} else {
header.style.top = '-80px'
}
})
电梯导航案例
// 1. 获元取素
let items = document.querySelectorAll('.item')
// 内容的盒子获取
let neirongs = document.querySelectorAll('.neirong')
// 2. 左侧aside 模块 点击谁,谁高亮
for (let i = 0; i < items.length; i++) {
items[i].addEventListener('click', function () {
// 找到上一个active 移除类
document.querySelector('.aside .active').classList.remove('active')
// 点击谁谁添加类
this.classList.add('active')
// 3. 右侧内容跟随走动 让页面滚动到对应的offsetTop值位置
// console.log(neirongs[i].offsetTop) 不用给单位
document.documentElement.scrollTop = neirongs[i].offsetTop
})
}
Client家族
获取宽高:
获取元素的可见部分的宽高 不含边框、滚动条
div.clientWidth clientHeight
获取位置:
clientTop clientLeft 边框的宽度 =border
会在窗口尺寸改变的时候触发事件:resize
// 当窗口变化的时候触发的事件
window.addEventListener('resize', function () {
// console.log(111)
let w = document.documentElement.clientWidth
// console.log(document.documentElement.clientWidth)
if (w >= 1920) {
document.body.style.backgroundColor = 'pink'
} else if (w > 540) {
document.body.style.backgroundColor = 'hotpink'
} else {
document.body.style.backgroundColor = 'deeppink'
}
})
// client 当前可视区域 不包含滚动条 边框等等
console.log(‘----------------------------’)
console.log(div.clientWidth)
console.log(div.clientHeight)
console.log(div.clientTop) // 边框的宽度 了解 呵呵
console.log(div.clientLeft)
轮播图案例
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
li {
list-style: none;
}
.main {
width: 700px;
margin: auto;
background: #000;
}
.slides {
height: 320px;
position: relative;
}
.slides ul li {
/* display: none; */
position: absolute;
top: 0;
left: 0;
opacity: 0;
/* 这里实现淡入淡出的关键 */
transition: all .3s;
}
.slides li.active {
/* display: block; */
opacity: 1;
}
.slides .extra {
width: 700px;
height: 53px;
line-height: 53px;
position: absolute;
bottom: 0px;
background-color: rgba(0, 0, 0, 0.8);
z-index: 10;
}
.slides .extra h3 {
width: 82%;
margin: 0;
margin-right: 20px;
padding-left: 20px;
color: #98E404;
font-size: 28px;
float: left;
font-weight: 500;
font-family: "Microsoft Yahei", Tahoma, Geneva;
}
.slides .extra a {
width: 30px;
height: 29px;
display: block;
float: left;
margin-top: 12px;
margin-right: 3px;
background-image: url(./assets/icon_focus_switch.png);
}
.slides .extra .prev {
background-position: 0 0;
}
.slides .extra .prev:hover {
background-position: -30px 0;
}
.slides .extra .next {
background-position: -60px 0;
}
.slides .extra .next:hover {
background-position: -90px 0;
}
.indicator {
padding: 10px 0;
}
.indicator ul {
list-style-type: none;
margin: 0 0 0 4px;
padding: 0;
overflow: hidden;
}
.indicator ul li {
position: relative;
float: left;
width: 60px;
margin: 0 4px 0 5px;
text-align: center;
cursor: pointer;
}
.indicator li img {
display: block;
border: 0;
text-align: center;
width: 60px;
}
.indicator li .mask {
width: 60px;
height: 60px;
position: absolute;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.4);
}
.indicator li .border {
display: none;
width: 54px;
position: absolute;
bottom: 0;
left: 0;
z-index: 20;
border: 3px solid #98E404;
}
/* li里面的mask 和 border 刚开始都是显示的 */
/* 我们写一个样式css */
.indicator .active .mask {
display: none;
}
.indicator .active .border {
display: block;
}
</style>
<body>
<div class="main">
<div class="slides">
<ul>
<li class="active"><a href="#"><img src="./assets/b_01.jpg" alt="第1张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_02.jpg" alt="第2张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_03.jpg" alt="第3张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_04.jpg" alt="第4张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_05.jpg" alt="第5张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_06.jpg" alt="第6张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_07.jpg" alt="第7张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_08.jpg" alt="第8张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_09.jpg" alt="第9张图的描述信息"></a></li>
<li><a href="#"><img src="./assets/b_10.jpg" alt="第9张图的描述信息"></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="assets/s_01.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_02.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_03.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_04.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_05.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_06.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_07.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_08.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_09.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
<li>
<img src="assets/s_10.jpg">
<span class="mask"></span>
<span class="border"></span>
</li>
</ul>
</div>
</div>
<script>
// 轮播图开始啦
// 需求①:小图标鼠标经过事件
// 鼠标经过小图片,当前高亮,其余兄弟变淡 添加类
let lis = document.querySelectorAll('.indicator li')
let piclis = document.querySelectorAll('.slides ul li')
let text = document.querySelector('.extra h3')
let next = document.querySelector('.next')
let prev = document.querySelector('.prev')
let main = document.querySelector('.main')
// 给多个小li绑定事件
for (let i = 0; i < lis.length; i++) {
lis[i].addEventListener('mouseenter', function () {
// 选出唯一的那个active ,删除类
document.querySelector('.indicator .active').classList.remove('active')
// 鼠标经过谁,谁加上active 这个类
this.classList.add('active')
// 需求② :大图片跟随变化 一定要放到鼠标经过事件里面
// 对应的大图片跟着显示,如果想要过渡效果,可以使用opacity效果,可以利用CSS淡入 淡出的效果,还是添加类
// 选出唯一的那个active ,删除类
document.querySelector('.slides ul .active').classList.remove('active')
// 对应序号的那个 li,谁加上active 这个类
piclis[i].classList.add('active')
text.innerHTML = `第${i + 1}张图的描述信息`
// 需求④:解决一个BUG
// 点击右侧按钮可以实现播放下一张,但是鼠标经过前面的,播放就会乱序
// 解决方案: 让变化量 index 重新赋值为 当前鼠标经过的索引号
// 鼠标经过了那个小li 他的索引号就是 i
// 右侧按钮是通过 index 来了控制播放的
index = i
})
}
// 需求③:右侧按钮播放效果
// 点击右侧按钮,可以自动播放下一张图片
// 需要一个变化量 index 不断自增
// 然后播放下一张图片
// 如果到了最后一张,必须要还原为第1张图片
// 教你一招: 索引号 = 索引号 % 数组长度 (放到播放前面)
let index = 0 // 全局变量 信号量 控制器 为了给 右侧按钮和左侧按钮同时使用
next.addEventListener('click', function () {
index++
// 选出 index 小图片 做操作
// console.log(index)
// if (index === lis.length) {
// index = 0
// }
index = index % lis.length
common()
})
// 需求⑤:左侧按钮播放效果
// 点击左侧按钮,可以自动播放上一张图片
// 需要一个变化量 index 不断自减
// 然后播放上一张图片
// 如果到了第一张,必须要从最后一张播放
// 教你一招: 索引号 = (数组长度 + 索引号) % 数组长度
prev.addEventListener('click', function () {
index--
// 选出 index 小图片 做操作
// console.log(index)
if (index < 0) {
index = lis.length - 1
}
// index = (lis.length + index) % lis.length
common()
})
// 需求⑥:
// 因为左侧按钮和右侧按钮里面有大量相同的操作,可以抽取封装一个函数 common
function common() {
document.querySelector('.indicator .active').classList.remove('active')
lis[index].classList.add('active')
// 选出 index 大图片 做操作
document.querySelector('.slides ul .active').classList.remove('active')
piclis[index].classList.add('active')
text.innerHTML = `第${index + 1}张图的描述信息`
}
// 需求⑦:开启定时器
// 其实定时器自动播放,就相当于点击了右侧按钮,此时只需要, next.click()
let timer = setInterval(function () {
// 自动调用右侧按钮的点击事件
next.click()
}, 1000)
// 需求⑧:
// 鼠标经过停止定时器 (清除定时器)
main.addEventListener('mouseenter', function () {
clearInterval(timer)
})
// 鼠标离开开启定时器 (开启定时器)
main.addEventListener('mouseleave', function () {
timer = setInterval(function () {
// 自动调用右侧按钮的点击事件
next.click()
}, 1000)
})
</script>
window对象
BOM浏览器对象模型
document
window是浏览器内置中的全局对象
window对象包含了五个属性 navigator location document history screen 构成了BOM
document是DOM的基础 依附于window的属性
定时器——延时函数
<body>
<button>解除定时器</button>
<script>
let btn = document.querySelector('button')
let timer = setTimeout(function () {
console.log(111)
}, 3000)
// 仅仅执行一次
btn.addEventListener('click', function () {
clearTimeout(timer)
})
</script>
</body>
setTimeout只执行一次 把一段代码延迟执行 平时省略window
<img src="./images/ad.png" alt="">
<script>
let img = document.querySelector('img')
setTimeout(function () {
img.style.display = 'none'
}, 3000)
</script>
递归函数
<script>
// 递归函数 : 自己调用自己就是递归函数
// 递归函数容易造成死递归,一定要加退出条件
let num = 0
function fn() {
num++
console.log(111)
// 在函数里面,调用自己
if (num >= 100) {
return
}
fn()
}
fn()
</script>
结合递归函数使用setTimeout 是实现setInterval的功能
<script>
// 利用递归函数 模拟了 setinterval
let div = document.querySelector('div')
function fn() {
div.innerHTML = new Date().toLocaleString()
setTimeout(fn, 1000)
}
fn()
setInterval由clearInterval 清除
setTimeout 由clearTimeout
js执行的机制
js是单线程的 同一时间只能做一件事
如果js的执行事件过长,就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉
js出现了同步和异步
同步
程序的执行顺序和任务的排列顺序是一致的
同步异步区别:流水线上的各个流程的执行顺序不同
所有的同步任务在主线程执行,形成一个执行栈
异步任务 :js 的异步是通过回调函数实现的
1、普通事件 click resize
2、资源加载 load error
3、定时器 setInterval setITimeout
异步任务添加在任务队列中
1、先执行执行栈中的同步任务
2、异步任务放入任务队列中
3、一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待任务,进入执行栈,开始执行。
当有异步任务时,提交给对应的异步进程处理
web API 异步API
1、ajax
2、DOM事件
3、setTImeout,setInterval
任务队列1:onload onclick
任务队列2:setTimeout setinterval
任务队列3:ajax网络请求
事件循环(event loop)
1、主线程执行完毕,查询任务队列,取出一个任务,推入主线程出力
2、重复该动作。————称为事件循环
location.href的使用
href获取完整的url地址 可以赋值 进行页面跳转
search 获取地址中携带的参数,符号?后面的部分
hash 获取地址中的哈希值 符号#后面部分
reload 用来刷新当前页面 传入参数true时表示强制刷新
五秒跳转页面
<a href="http://www.itcast.cn">支付成功,<span>5</span> 秒之后跳转首页</a>
<script>
let a = document.querySelector('a')
let num = 5
let timer = setInterval(function () {
num--
a.innerHTML = `支付成功,<span>${num}</span> 秒之后跳转首页`
if (num === 0) {
clearInterval(timer)
// 跳转页面
location.href = 'http://www.itcast.cn'
}
}, 1000)
location.search ?
location的数据类型是对象 拆分并保存了url地址的各个组成部分
search获取 的地址中携带的参数 符号?后面的部分
<form action="target.html">
<input type="text" name="username">
<button>提交</button>
</form>
location.hash
hash 获取地址中的哈希值 符号#后面部分
后期vue路由的铺垫,经常用于不刷新页面,显示不同页面,比如网易云音乐
href=“/#/"
location.reload
刷新
location.reload(true)强制刷新
ctrl+f5强制刷新 直接更新最新内容从网上拉去,不走本地缓存
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://m.itcast.cn'
}
})()
更换手机或电脑的页面版本
history对象
前进 后台 历史记录
back() forward() go(参数)1前进 -1后退1个页面
let qianjin = document.querySelector('.forward')
let houtui = document.querySelector('.back')
qianjin.addEventListener('click', function () {
// history.forward()
history.go(1)
})
houtui.addEventListener('click', function () {
// history.back()
history.go(-1)
})
</script>
swiper插件
轮播图
<!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>
<link rel="stylesheet" href="./css/swiper-bundle.min.css">
<style>
.box {
width: 600px;
height: 350px;
background-color: pink;
margin: 100px auto;
}
html,
body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #000;
margin: 0;
padding: 0;
}
.swiper-container {
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
.swiper-slide img {
width: 100%;
height: 350px;
}
.swiper-pagination-bullet {
width: 12px;
height: 12px;
}
.swiper-pagination-bullet-active {
background-color: #fff;
}
</style>
</head>
<body>
<div class="box">
<!-- Swiper -->
<div class="swiper-container one">
<div class="swiper-wrapper">
<div class="swiper-slide">
<a href="#">
<img src="./images/b_01.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_02.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_03.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_04.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_05.jpg" alt="">
</a>
</div>
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
<!-- Add Arrows -->
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
<div class="box">
<!-- Swiper -->
<div class="swiper-container two">
<div class="swiper-wrapper">
<div class="swiper-slide">
<a href="#">
<img src="./images/b_01.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_02.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_03.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_04.jpg" alt="">
</a>
</div>
<div class="swiper-slide">
<a href="#">
<img src="./images/b_05.jpg" alt="">
</a>
</div>
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
<!-- Add Arrows -->
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</div>
<script src="./js/swiper-bundle.min.js"></script>
<!-- 要放到插件的下面 -->
<!-- Initialize Swiper -->
<script>
var swiper = new Swiper('.one', {
slidesPerView: 1,
autoplay: {
delay: 3000,
stopOnLastSlide: false,
disableOnInteraction: true,
},
spaceBetween: 0,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
keyboard: true,
});
var swiper = new Swiper('.two', {
slidesPerView: 1,
autoplay: {
delay: 5000,
stopOnLastSlide: false,
disableOnInteraction: true,
},
spaceBetween: 0,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
keyboard: true,
});
</script>
</body>
</html>
本地存储
存储在浏览器中,设置 读取方便 刷新不丢失
sessionStorage
周期永久生效,除非收到删除,关闭页面也会存在
可以多窗口共享(同一浏览器)
以键值对的形式存储使用
用法更localStora相同
localStorage
setItem() getItem()removeItem()
// 存储数据 localStorage.setItem('键', '值')
// localStorage.setItem('uname', 'pink老师')
// localStorage.setItem('age', 18)
// 获取数据
// localStorage.getItem('键')
// console.log(localStorage.getItem('uname'))
// 删除数据
// localStorage.removeItem('uname')
// 1. 存储复杂数据类型(引用数据类型)
let obj = {
uname: '刘德华',
age: 17,
address: '黑马程序员'
}
// console.log(JSON.stringify(obj))
//(1) 复杂数据类型一定要转换为json字符串在进行存储 (因为本地存储只能存储字符串)
localStorage.setItem('obj', JSON.stringify(obj))
// AJAX
// JSON 属性和值都是双引号进行包含
// let obj = {
// "uname": "刘德华",
// "age": "17",
// "address": "黑马程序员"
// }
// (2) 取数据 可以使用 JSON.parse() 将json字符串转换为对象
// console.log(typeof localStorage.getItem('obj'))
console.log(JSON.parse(localStorage.getItem('obj')))
let object = {
age: 18
}
// 本地存储只能存储字符串 所以我要转换 转换为JSON格式的字符串
localStorage.setItem('key', JSON.stringify(object))
// 获取的过来的值是字符串,不是对象了没有办法直接使用,因此我们首先吧字符串转换为对象
// JSON.parse()
console.log(JSON.parse(localStorage.getItem('key')))
存储复杂数据类型
本地只能存储字符串,无法存储复杂数据类型,需要将复杂数据类型转换称json字符串,存储在本地
JSON.stringify
将复杂数据(对象)转换称Json字符串 存储在本地
JSON.parse
将JSOn字符串转换称对象 取出时候使用
自定义属性
固有属性:class id title
自定义:setAttribute() getAttribute() removeAttribute()
规范: data-自定义属性 data-开头
dataset 能得到所有自定义属性
不允许删除第一条数据 添加自定义属性
<div class="box" data-index="0" data-name="andy"></div>
<script>
// 设置自定义属性
let box = document.querySelector('.box')
// box.setAttribute('myid', 10)
// console.log(box.getAttribute('myid'))
console.log(box.dataset)
console.log(box.dataset.index)
</script>
正则表达式
用户名:/1{3,16}$/
过滤掉页面的一些敏感词,或从字符串中获取想要的特定部分(提取)
是用于匹配字符串中字符组合的模式
语法
let 变量=/表达式/
/ /是正则表达式的字面量 返回的是对象 正则对象
test()方法 用来查看正则表达式与指定的字符串是否匹配
exec() 检索 可以查找索引 返回的是数组
regObj.test(被检测的字符串)
// 定义正则表达式 reg 里面存的是对象
let reg = /前端/
// 2. 检测是否匹配 test (重点)
let str = '我们大家都在学前端'
// console.log(reg.test(str)) reg检测str
// 3. 检索 exec()
console.log(reg.exec(str)) // 返回的是数组
元字符
输入26个英文字母[a-z]
正则测试工具:http://tool.oschina.net/regex
MDN 文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
1、边界符 表示位置 开头和结尾 必须用什么开头 什么结尾
^ 表示匹配行首的文本
$ 表示匹配行尾的文本
**[]加上^取反符号 比如[^a-z]**匹配除了小写字母以外的字母
. 匹配除了换行符之外的任何单个字符
// console.log(/哈/.test('哈哈')) true
// console.log(/哈/.test('二哈')) true
// ^ 开头
console.log(/^哈/.test('二哈')) // false
console.log(/^哈/.test('我开心的哈哈大笑')) // false
console.log(/^哈$/.test('我开心的哈哈大笑')) // false
console.log(/^哈$/.test('哈哈')) // false
console.log(/^哈$/.test('哈')) // true 精确匹配
2、量词 表示重复次数
* | 重复0次或多次 |
---|---|
+ | 重复一次或多次 |
? | 重复0次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
// console.log(/a/.test('a'))
// // * 量词 n >= 0
// console.log(/a*/.test(''))
// console.log(/a*/.test('a'))
// console.log(/a*/.test('aa'))
// console.log(/a*/.test('aaaaaaaa'))
// console.log(/a*/.test('b'))
// console.log('--------------------------')
// // + 量词 n >= 1
// console.log(/a+/.test('')) false
// console.log(/a+/.test('a'))
// console.log(/a+/.test('aa'))
// console.log(/a+/.test('aaaaaaaa'))
// console.log(/a+/.test('b')) false
// console.log('--------------------------')
// // ? 出现 0 || 1
// console.log(/^a?$/.test(''))
// console.log(/^a?$/.test('a'))
// console.log(/^a?$/.test('aa')) false
// {n} 只能出现 n次 符号之间不要加空格
console.log(/^a{3}$/.test('aa')) false
console.log(/^a{3}$/.test('aaa'))
console.log(/^a{3}$/.test('aaaa')) false
// {n,} >= n
console.log(/^a{3,}$/.test('aa')) false
console.log(/^a{3,}$/.test('aaa'))
console.log(/^a{3,}$/.test('aaaa'))
console.log('--------------------------')
// {n,m} >= n <= m
console.log(/^a{3,6}$/.test('aa')) false
console.log(/^a{3,6}$/.test('aaa'))
console.log(/^a{3,6}$/.test('aaaa'))
console.log(/^a{3,6}$/.test('aaaaa'))
console.log(/^a{3,6}$/.test('aaaaaaaa')) false
3、字符类 \d 表示0-9
[]匹配字符 加上-连字符 表示范围
/[abc]/ 后面的字符串只要包含abc中任意一个字符 都返回true
// console.log(/abc/.test('abc'))
// console.log(/abc/.test('ab'))
// 字符类 []
// console.log(/[abc]/.test('abc'))
// console.log(/[abc]/.test(''))
// console.log(/[abc]/.test('andy'))
// console.log(/[abc]/.test('baby'))
// console.log(/[abc]/.test('cry'))
// console.log(/[abc]/.test('die'))
// 字符类 [-] 连字符
console.log(/^[abc]$/.test('abc'))
console.log(/^[abc]$/.test('a'))
console.log(/^[abc]$/.test('b'))
console.log(/^[abc]$/.test('c'))
console.log(/^[abc]$/.test('cc'))
// 26个英文字母选其中的一个
console.log(/^[a-zA-Z]$/.test('d'))
console.log(/^[a-zA-Z]$/.test('D'))
console.log(/^[a-zA-Z]$/.test('DD'))
console.log(/^[a-zA-Z0-9]$/.test('6'))
console.log(/^[a-zA-Z0-9-_]$/.test('6'))
console.log(/^abc+$/.test('cc'))
^[1-9][0-9]{4,}$ QQ1000从开始
用户名验证案例
let input = document.querySelector('input')
let span = input.nextElementSibling
input.addEventListener('blur', function () {
if (/^[a-zA-Z0-9-_]{6,16}$/.test(input.value)) {
span.className = 'right'
span.innerHTML = '要输正确'
} else {
span.className = 'error'
span.innerHTML = '只能要输6~16位字符'
}
})
\d | [0-9] |
---|---|
\D | [^0-9] |
\w | [A-Za-z0-9_] |
\W | [^A-Za-z0-9_] |
\s | 匹配空格(换行符、制表符、空格符)[\t\r\n\v\f] |
\S | [^\t\r\n\v\f] |
日期格式:^\d{4}-\d{1,2}-\d{1-2}
/表达式/修饰符
i 匹配字母不区分大小写
g 匹配所有满足正则表达式的结果
替换 replace
字符串.replace(/正则表达式/,"替换的文本")
过滤敏感词
<textarea name="" id="" cols="30" rows="10"></textarea>
<button>发布</button>
<div></div>
<script>
let btn = document.querySelector('button')
let textarea = document.querySelector('textarea')
let div = document.querySelector('div')
btn.addEventListener('click', function () {
// 过滤用户输入的内容
div.innerHTML = textarea.value.replace(/激情|基情/g, '**')
// div.innerHTML = textarea.value
})
</script>
change事件
// input 事件 只要输入就会触发
// change 事件 是 离开表单时候才触发 并且值有变化
// 当表单里面的值发生变化的时候触发,和 blur 不一样
<input type="text">
<input type="password">
<script>
let input = document.querySelector('input')
// 当表单里面的值发生变化的时候触发,和 blur 不一样
// input 事件 只要输入就会触发
// change 事件 是 离开表单时候才触发 并且值有变化
input.addEventListener('change', function () {
console.log(111)
})
</script>
属性选择器
input[type=text] {
background-color: red;
}
.test(‘abc’))
// console.log(/abc/.test(‘ab’))
// 字符类 []
// console.log(/[abc]/.test(‘abc’))
// console.log(/[abc]/.test(‘’))
// console.log(/[abc]/.test(‘andy’))
// console.log(/[abc]/.test(‘baby’))
// console.log(/[abc]/.test(‘cry’))
// console.log(/[abc]/.test(‘die’))
// 字符类 [-] 连字符
console.log(/^[abc]$/.test('abc'))
console.log(/^[abc]$/.test('a'))
console.log(/^[abc]$/.test('b'))
console.log(/^[abc]$/.test('c'))
console.log(/^[abc]$/.test('cc'))
// 26个英文字母选其中的一个
console.log(/^[a-zA-Z]$/.test('d'))
console.log(/^[a-zA-Z]$/.test('D'))
console.log(/^[a-zA-Z]$/.test('DD'))
console.log(/^[a-zA-Z0-9]$/.test('6'))
console.log(/^[a-zA-Z0-9-_]$/.test('6'))
console.log(/^abc+$/.test('cc'))
^[1-9][0-9]{4,}$ QQ1000从开始
#### 用户名验证案例
let input = document.querySelector('input')
let span = input.nextElementSibling
input.addEventListener('blur', function () {
if (/^[a-zA-Z0-9-_]{6,16}$/.test(input.value)) {
span.className = 'right'
span.innerHTML = '要输正确'
} else {
span.className = 'error'
span.innerHTML = '只能要输6~16位字符'
}
})
| \d | [0-9] |
| ---- | ---------------------------------------------- |
| \D | [^0-9] |
| \w | [A-Za-z0-9_] |
| \W | [^A-Za-z0-9_] |
| \s | 匹配空格(换行符、制表符、空格符)[\t\r\n\v\f] |
| \S | [^\t\r\n\v\f] |
日期格式:^\d{4}-\d{1,2}-\d{1-2}
/表达式/修饰符
i 匹配字母不区分大小写
g 匹配所有满足正则表达式的结果
**替换** replace
字符串.replace(/正则表达式/,“替换的文本”)
#### 过滤敏感词
<button>发布</button>
<div></div>
<script>
let btn = document.querySelector('button')
let textarea = document.querySelector('textarea')
let div = document.querySelector('div')
btn.addEventListener('click', function () {
// 过滤用户输入的内容
div.innerHTML = textarea.value.replace(/激情|基情/g, '**')
// div.innerHTML = textarea.value
})
</script>
### change事件
// input 事件 只要输入就会触发
// change 事件 是 离开表单时候才触发 并且值有变化
// 当表单里面的值发生变化的时候触发,和 blur 不一样
<input type="text">
<input type="password">
<script>
let input = document.querySelector('input')
// 当表单里面的值发生变化的时候触发,和 blur 不一样
// input 事件 只要输入就会触发
// change 事件 是 离开表单时候才触发 并且值有变化
input.addEventListener('change', function () {
console.log(111)
})
</script>
### 属性选择器
input[type=text] {
background-color: red;
}
a-z0-9_- ↩︎