DOM事件基础

获取元素

1.获取元素对象的方法

1
2
3
4
5
6
7
8
9
10
11
// 1.获取 ID
document.getElementById()
// 2.获取标签名 ul li
document.getElementsByTagName() // 返回是伪数组
// 3.H5新增获取类名
document.getElementByClassName() // 伪数组存储方式
// 4.H5新增通过选择器
document.querySelector('选择器') // 返回第一个元素对象
//querySelector('.class') ('#id') …………
// 4.1 根据选择器返回所有
document.querySelectorAll() //伪数组集合

2.获取特殊元素

1
2
3
4
// 获取 body 标签
var eleBody = document.body;
// 获取 html 标签
var eleHtml = document.documentElement; //这是获取的规范方式

事件基础

事件是由 事件源、事件类型、事件处理程序 组成,称为事件三要素

1
2
3
4
5
6
7
8
9
10
// 获取事件源
var btn = document.querySelector('#btn')

// 事件类型,绑定点击
btn.onclick

//事件处理程序
btn.onclick = function(){
console.log('被点击了')
}

常见鼠标事件

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获取鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发

操作元素

1.改变元素内容

innerText:IE发起,非标准。去除换行和空格

innerHTML:能渲染 HTML 标签,保留换行和空格(W3C标准)

2.表单元素的属性操作

type、value、checked、selected、disabled

3.样式属性操作

  • element.style 行内样式操作

  • element.className 类名样式操作,会更改元素的类名,会覆盖原先的类

    可以设置为多个类:className = ’first currentClass‘

注意:

  1. JS 里面的样式采用驼峰命名法
  2. JS 修改 style 样式操作,产生的是行内样式,css 权重比较高

4.自定义属性操作

自定义属性的目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存数据库中。

1
2
3
4
5
6
<div id="demo"></div>
<script>
var div = document.querySelector('div')
console.log(div.id) // 得到属性 id 值
var id = div.getAttribute('id') // 同上
</script>

设置属性值

1
2
div.id = 'demo2'
div.setAttribute('id','demo2')

规范

element.属性值 = '值':设置内置属性

element.setAttribute('id','demo2'):设置自定义属性

移除属性

div.removeAttribute('data-index')

自定义属性规范

H5规定自定义属性data-开头作为属性名并且赋值

H5新增获取自定义属性的方法

1
2
3
4
5
6
7
8
9
10
11
<div data-index="2" data-list-name="simple"></div>
<script>
var div = document.querySelector('div')
// dataset 是一个集合,规范的
console.log(div.dataset.index) //logs 2
console.log(div.dataset['index']) //logs 2

// 获取 data-list-name 自定义属性
div.dataset.listName // 使用驼峰命名法
div.dataset['listName']
</script>

dataset 是 规范自定义属性的集合,data-开头的都存在这个集合里面

console.log(div.dataset.index) console.log(div.dataset['index'])


节点操作

一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性

  • 元素节点 nodeType = 1
  • 属性节点 nodeType = 1
  • 文本节点 nodeType = 1(文本节点包含文字、空格、换行等)

父节点 和 子节点操作

1
2
3
4
5
6
7
8
9
10
11
<div class="box">
<span class="erweima">X</span>
</div>
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima')
// 正常获取父节点
var box = document.querySelector('.box')
// 通过节点获取
var box = erweima.parentNode // 获取的是最近的父级,得不到返回空
</script>
1
2
3
4
5
6
7
8
9
10
<ul>
<li></li>
<li></li>
<li></li>
</ul>
<script>
var ul = document.querySelector('ul')
// 获取子节点 是一个集合
var lis = ul.childNodes
</script>

获取子节点集合包含 元素节点 文本节点 等等。需要专为处理才能获取元素节点,因此不推荐使用 childNodes 获取子节点

通过非标准方法 : children

ul.children 获取是就是子节点元素,虽然不标准,但是得到浏览器的支持

获取第一个元素节点和最后一个元素节点

1
2
3
4
5
6
7
8
parentNode.firstChild // 获取的是第一个节点 ,不是元素节点
parentNode.lastChild
// 有兼容性问题
parentNode.firstElementChild
parentNpde.lastElementChild
// 实际开发
parentNode.children[0]
parentNode.children[parentNode.children.length - 1]

兄弟节点

1
2
3
4
5
6
7
var div = document.querySelector('div')
// 1. nextSibling 下一个兄弟节点 包含元素节点或文本节点
node.nextSibling
// 2. previousSibling 获取上一个兄弟节点
node.previousSibling
// 3. nextElementSibling previousElementSibling 获取兄弟元素节点

添加节点

document.createElement('li') 创建节点元素

node.appendChild(child)

将一个节点添加到指定父节点的子节点列表末尾。类似于 css 里面的 before伪元素

node.insertBefore(child,指定元素):指定元素是指子元素的哪一个,用节点选择

将一个节点添加到指定父节点的子节点列表末尾。类似于 css 里面的 after 伪元素

node.insertBefore(child,node.children[0]) 插入到第一个上面

删除节点

node.removeChild(node.children)

克隆节点

node.cloneNode() 括号为空或者false 是浅拷贝,只复制标签

node.cloneNode(true) 复制内容

动态生成表格案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!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>
table{
border-collapse: collapse;
width: 500px;
margin: 100px auto;
text-align: center;
}
th,td{
border: 1px solid #333;
width: 200px;
}
thead tr{
height: 40px;
background-color: #ccc;
}
</style>
</head>
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
// 数据
var data = [{
name: '李四',
subject: 'javascript',
score: 98
},
{
name: '张三',
subject: 'javascript',
score: 90
},
{
name: '老刘',
subject: 'javascript',
score: 92
},
{
name: '李逵',
subject: 'javascript',
score: 45
}]
// 获取 tbody 元素
var tbody = document.querySelector('tbody')
data.forEach( obj => { // 循环 data 数组 obj 是单个对象
var tr = document.createElement('tr') //创建tr 对象
tbody.appendChild(tr) // 添加到 body 里面
for(var i in obj){ // 再次遍历对象 obj
var td = document.createElement('td') //创建td
td.innerHTML = obj[i]
tr.appendChild(td) // 插入到 tr里面
}
// 添加删除单元格
var td = document.createElement('td')
td.innerHTML = '<a href="javascript:;">删除</a>'
tr.appendChild(td)
});
// 获取所有的 a 标签
var a = document.querySelectorAll('a')
for(var i=0;i<a.length;i++){
a[i].onclick = function(){
tbody.removeChild(this.parentNode.parentNode)
}
}
</script>
</body>
</html>

三种创建元素方式的区别

  • document.write()
  • element.innerHTML
  • document.createElement()



事件高级

注册事件(绑定事件)

给元素添加事件,称为注册事件或者绑定事件

注册事件有两种方式:传统方式和方法监听注册方式

1.方法监听注册方式

  • addEventListener() w3c标准
1
2
3
btn.addEventListener('click',function(){
})
// type 类型是字符串 'click' 点击事件 不要带 on

删除事件(解绑事件)

1
2
3
4
5
6
// 1. 传统解绑
btn.onclick = null;

// 2. removeEventListener
eventTarget.removeEventListener(type,listener[,useCapture])
btn.removeEventListener('click',fn)

Dom事件流

事件流描述的是从页面中接收事件的顺序

事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// addEventListener 第三个参数决定是捕获阶段 还是 冒泡阶段
// true 表示捕获阶段从上自下 document>body>父级>子级

// false 表示冒泡阶段 从下往上 子级>父级>body>document

// 假设
//<div id="father">
// <div id="son"></div>
//</div>

var son = document.querySelector('#son')
var father = document.querySelector('#father')
son.addEventListener('click',function(){
// 捕获阶段
console.log(1111)
},true)
father.addEventListener('click',function(){
console.log(2222)
},true)
// 打印结果肯定是 2222 1111 先执行父级事件,因为绑定了事件

son.addEventListener('click',function(){
// 冒泡阶段 false 或者省略默认是冒泡阶段
console.log(1111)
},false)
father.addEventListener('click',function(){
console.log(2222)
},false)
// 打印结果肯定是 1111 2222 先执行子级事件再执行父级

事件对象

侦听函数有一个形参 event 里面有很多事件属性

1
2
3
4
5
6
div.onclick = function(event){
console.log(event)
}
div.addEventListener('click',function(event){
//body
})

e.target 是触发对象

this 是绑定对象,两者有可能一样,但不完全一样

阻止默认行为

1
2
3
4
var a = document.querySelector('a');  
a.addEventListener('click',function(e){
e.preventDefault(); // 阻止 a 标签默认跳转行为
})

阻止事件冒泡

事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点

事件冒泡本身的特性,会带来坏处,也会带来好处,需要灵活处理

阻止事件冒泡

  • 标准写法:利用事件对象里面的 stopPropagation() 方法

事件委托(代理、委派)

事件委托原理:
不是每一个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul>
<li>1</li><li>2</li><li>3</li>
<li>4</li><li>5</li><li>6</li>
<li>7</li><li>8</li><li>9</li>
<li>10</li>
</ul>
<script>
// 事件绑定在 ul 身上,但是可以点击 li标签
// 不需要给每一个li标签绑定点击事件
var ul = document.querySelector('ul')
ul.addEventListener('click',function(e){
e.target.onclick = function(){
ul.removeChild(this)
}
},true)
</script>

常用鼠标事件

1.禁用右键菜单

1
2
3
document.addEventListener('contextmenu',function(e){
e.preventDefault(); // 阻止默认行为
})

2.禁止选中文字

1
2
3
document.addEventListener('selectstart',function(e){
e.preventDefault(); // 阻止默认行为
})

案例:跟随鼠标移动的天使

  • 鼠标不断的移动,使用鼠标移动事件:mouesmove
  • 在页面中移动,给document注册事件
  • 图片要移动距离,而且不占位置,使用绝对定位
  • 核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,把这个X和Y坐标作为图片的top和left值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function mouseRouser() {
var body = document.body;
var img = document.createElement("img");
img.style.position = "absolute";
img.style.pointerEvents = "none";
img.src = "https://cdn.jsdelivr.net/gh/SimpleLifecst/simple@main//angel.gif";
body.appendChild(img);
document.addEventListener("mousemove", function (e) {
var x = e.pageX;
var y = e.pageY;
img.style.top = y + "px";
img.style.left = x + "px";
});
}
mouseRouser();

常用键盘事件

键盘事件 触发条件
onkeyup 某个键盘按键被松开时触发
onkeydown 某个键盘按键被按下时触发(会一直触发)
onkeypress 某个键盘按键被按下时触发 但是不识别功能键 比如 ctrl shift 箭头等

键盘事件对象

1
2
3
document.addEventListener('keyup',function(e){
console.log(e.keyCode) //获取按键的 ASCII 值
})

keyup 和 keydown 不区分大小写 a A 都是 65

keypress 事件区分大小写


BOM浏览器对象模型

BOM 概述

BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器宽口进行交互的对象,其核心对象就是 window

window对象是浏览器的顶级对象,它具有双重角色

  1. 它是 JS 访问浏览器窗口的一个接口
  2. 它是一个全局对象,定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。在调用的时候可以省略 window,前面学习的对话框都属于 window对象方法,如 alert()、prompt()

window 对象的常见事件

1.窗口加载事件

1
2
window.onload = function(){} 
window.addEventListener('load',function(){})

window.onload 是窗口加载事件,当文档内容完全加载会触发该事件(包括图像、脚本文件、CSS文件等),就调用的处理函数

1
2
document.addEventListener('DOMContentLoaded',function(){})
// DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等

2.调整窗口大小事件

1
2
3
4
5
6
window.onresize = function(){}
window.addEventListener('resize',function(){})
// onrezie 是调整窗口大小加载事件,当触发时就调用的处理函数
// 用于响应式布局
// 通过window.innerWidth 获取当前屏幕宽度
// 以前没有CSS3时,用js做响应式布局

定时器

window 对象给我们提供了2个非常好用的方法-定时器

  • setTimeout() 执行一次
  • setInterval() 每隔一定时间执行一次

清除定时器

1
2
3
4
5
6
7
8
9
10
11
// 1.清除setTimeout
var timer = setTimeout(function(){
console.log('ok')
},2000)
clearTimeout(timer) // 清除定时器

// 2.清除setInterval
var timer2 = setInterval(function(){
console.log('ok')
},2000)
clearInterval(timer2) // 清除定时器

this指向问题

  • 在全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window),指向的是调用者
1
2
3
// 默认定时器有一个调用者就是 window
// 函数也有调用者,就是window,只是 window调用者这个对象被省略了
// 因此 this 指向的是window
  • 方法调用中谁调用this指向谁
1
2
3
4
5
6
var o = {
sayHi:function(){
console.log(this)
}
}
// 这个 this 指向的就是 o,o调用了函数sayhi
  • 构造函数中 this 指向构造函数的示例
1
2
3
4
5
function Fun(){
console.log(this)
}
var fun = new Fun()
// 打印的this就是指向 fun 实例对象

JS 执行机制

JS 执行机制是单线程的

1.先执行执行栈中的同步任务;2.异步任务(回调函数)放入任务队列中;3.一旦执行栈中所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行

1.异步任务

JS异步是通过回调函数实现的

一般,异步任务有以下三种类型

  1. 普通事件、click、resize等
  2. 资源加载,如load、error等
  3. 定时器,包括 setInterval、setTimeout

异步任务相关回调函数添加到任务队列中(任务队列也称消息队列)

2.事件循环

由于主线程不断的重复获取任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)

JS执行机制图

location 对象

window 对象给我们提供了一个location属性用于获取或设置窗体的URL,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性也称为location对象

1
2
3
4
5
6
7
// 分割获取的参数 search
// substr('起始的位置','长度') 默认截取全部
// split('分割符')
var params = location.search.substr(1)
var arr = params.split('=')
console.log(arr) //得到参数数组

navigator 对象包含有关浏览器的信息,它有很多属性,我们常用的就是 userAgent,该属性可以返回由客户端发送服务器的 user-agent 头部的值

1
2
3
4
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.location.href = "../H5/index.html"; //手机
}
// 进入手机端的

history 对象

window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL

history对象方法 作用
back() 后退功能
forward() 前进功能
go(参数) 前进后退功能,参数是1,前进一个页面。参数-1,后退一个页面

PC网页特效

元素偏移量 offset 系列

offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

  • 获得元素距离带有定位父元素的位置

  • 获得元素自身的大小(宽度高度)

  • 注意: 返回的数值都不带单位

案例获取盒子鼠标的坐标

1
2
3
4
5
// 获取盒子距离左侧body的距离   offsetLeft
// 获取鼠标距离左侧body的距离 pageX
X = pageX - offsetLeft
Y = pageY - offsetTop
// 无法直接得到鼠标在盒子内的坐标,但是可以用这种方式去获取到

拖拽模态框案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 获取鼠标在盒子内的固定位置 event.pageX - offsetLeft 得到鼠标距离盒子左边的固定位置
// 使用 mousedown 按下 mouseup 弹起 mousemove 移动 这个三个事件
// 固定位置的获取,只需要在按下的事件时获取到
var box = document.querySelector(".box");
box.addEventListener("mousedown", function (e) {
// (1) 一开始获取鼠标距离盒子内的距离,这是固定的
var x = e.pageX - this.offsetLeft
var y = e.pageY - this.offsetTop
document.addEventListener("mousemove", move)
function move(e){
box.style.left = e.pageX - x + 'px'
box.style.top = e.pageY - y + 'px'
console.log(x,y);
}
// (2) 当事件 mouseup 鼠标松开时 删除事件 mousemove
document.addEventListener('mouseup',function(){
document.removeEventListener('mousemove',move)
})
})

// 拖拽的图标 cursor:move;

仿京东图片放大镜案例

1
2
3
4
5
6
7
<div class="box">
<img src="./images/1.jpg" alt="">
<div class="mask"></div>
<div class="bigimage">
<img src="./images/1.jpg" alt="">
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 var box = document.querySelector('.box');
var mask = document.querySelector('.mask');
var bigimage = document.querySelector('.bigimage');
var bigimg = document.querySelector('.bigimage img');
// 通过鼠标事件 mouseover mouseout 用来显示隐藏遮挡层 和 大图片
box.addEventListener('mouseover',function(){
mask.style.display = 'block';
bigimage.style.display = 'block';
})
box.addEventListener('mouseout',function(){
mask.style.display = 'none';
bigimage.style.display = 'none';
})
// 移动mask
box.addEventListener('mousemove',function(e){
var x = e.pageX - box.offsetLeft; // 鼠标距离最左侧的距离 - 盒子距离父级左侧的距离,
var y = e.pageY - box.offsetTop; //box的父级就是document = 得到鼠标在盒子内的距离

var maskX = x - mask.offsetWidth / 2; // maskX,maskY 是 遮挡层在盒子内的距离
var maskY = y - mask.offsetHeight / 2;
// 最大移动间隙 box.offsetWidth - mask.offsetWidth
moveMax_X = box.offsetWidth - mask.offsetWidth;
moveMax_Y = box.offsetHeight - mask.offsetHeight;
// 控制遮挡层的移动
mask.style.left = maskX<=0?maskX=0+'px':maskX+'px'
mask.style.left = maskX>=moveMax_X?maskX=moveMax_X+'px':maskX+'px'
mask.style.top = maskY<=0?maskY=0+'px':maskY+'px'
mask.style.top = maskY>=moveMax_Y?maskY=moveMax_Y+'px':maskY+'px'


// 大图片移动
// 大图片的间隙
// 遮挡层移动距离 / 遮挡层最大移动距离 = 大图片移动距离 / 大图片最大移动距离
//可以求出大图片的移动距离
// maskX 遮挡层距离盒子左侧的距离
// bigMax 大图片最大的移动距离
// moveMax_X 遮挡层移动最大距离
var bigMax = bigimg.offsetWidth - bigimage.offsetWidth; // 获取到 容器和照片的间隙
var bigX = maskX * bigMax / moveMax_X; //
var bigY = maskY * bigMax / moveMax_Y;
bigimg.style.left = -bigX + 'px';
bigimg.style.top = -bigY + 'px';
})

元素可视区 client 系列

client 系列的相关属性来获取元素可视区的相关信息,通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等

立即执行函数

1
2
3
4
5
6
7
8
9
10
// 1.立即执行函数 不需要调用,立马能够自己执行的函数
// 2.写法
(function() {})(); 或者 (function(){}());

// 同样可以传递参数
(function(a,b){
console.log(a +b)
})(a,b)

// 最大的好处:独立创建了一个作用域

PS:如果有多个立即执行函数,需要用分号隔开

立即执行函数 this 始终指向 Window

元素滚动 scroll 系列

image-20210928114322672

scroll 得到的是内容的大小,client 是盒子的大小

scroll事件

1
2
3
scroll 是 是滚动条的事件,侧边栏的效果就是  通过scroll事件来确定的
element.scrollTop 是滚动条移动,上面移除的部分高度
获取页面移除的高度 window.pageYOffset

image-20210928135604468

mouseover 和 mouseenter 进入盒子事件的区别

mouseover 进入盒子触发,进入子盒子仍然触发

mouseenter 进入该盒子触发,子盒子不触发

原因:mouseenter 不会有冒泡阶段

和 mouseenter 对应的是 mouseleave 同样没有冒泡阶段

动画函数封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//var obj = {};
//obj.name = 'andy'
// 给不同的元素指定了不同的定时器
// obj是一个对象,添加定时器通过 obj.timer 取名,可以添加不同的定时器
function animate(obj,target){
// 避免我们连续调用这个动画函数,加快定时器执行
// 每次触发都会清除原先的动画定时器
clearInterval(obj.timer);
obj.timer = setInterval(function(){
if(obj.offsetLeft >= target){
// 停止动画
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft +1 + 'px';
},30);
}
var div = document.querySelector('div');
animate(div,200); // 调用动画

1.缓动动画效果

公式:(目标值 - 现在的位置)/ 10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 获取到的 步长值可能是小数,避免完整到达目标值,我们会取整
// 当向前走 步长值是正是数,去大点整数 使用函数 Math.ceil() 、当步长值是负值,向小值去整 Math.floor()
function animate(obj,target){
// 避免我们连续调用这个动画函数,加快定时器执行
// 每次触发都会清除原先的动画定时器
clearInterval(obj.timer);
obj.timer = setInterval(function(){
var step = (target - obj.offsetLeft) / 10
step = step > 0?Math.ceil(step):Math.floor(step)
if(obj.offsetLeft >= target){
// 停止动画
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + step + 'px'; // step 是一个从大到小的值,如果是固定值,就是匀速动画
},15); // 15毫秒是一个标准的动画时间
}
var div = document.querySelector('div');
animate(div,400); // 调用动画

2.动画函数添加回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 给封装动画函数,添加形参 callback 回调函数
// 给调用时,传入函数 function(){}
function animate(obj,target,callback){ // 省略

// 定时器清除时,调用回调函数
if(obj.offsetLeft >= target){
// 停止动画
clearInterval(obj.timer);
if(callback){ // 看是否有回调函数
callback();
}
}

animate(div,200,function(){
// 回调函数写内容
})

3.完整的动画封装 animate.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function animate(obj,target,callback){
// 清除一下原先的定时器,防止叠加定时器
clearInterval(obj.timer)
obj.timer = setInterval(function(){
var step = (target - obj.offsetLeft) / 10
step = step > 0?Math.ceil(step):Math.floor(step)
if(obj.offsetLeft>=target){
clearInterval(obj.timer)
//if(callback){
// callback(); // 当传入了回调函数 callback 就调用
//}
callback && callback();
}
obj.style.left = obj.offsetLeft + step + 'px';
},15)
}

4.轮播图

  • 无缝滚轮连接,将第一张图片复制到最后一张,当到最后一张无动画跳到第一张,接着轮播
  • 节流阀:

防止轮播图按钮连续点击造成播放过快。

节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心实现思路:设置一个变量,锁住函数和解锁函数,利用动画的回调函数解锁

5.封装返回顶部动画

1
2
3
4
5
6
7
8
9
10
11
12
13
animate(window,0); // 调用
function animate(obj,target,callback){
clearInterval(obj.timer);
obj.timer = setInterval(function(){
var step = (target - window.pageYOffset) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if(window.pageYOffset == target){
clearInterval(obj.timer);
callback && callback();
}
window.scroll(0,window.pageYOffset + step);
},15)
}

移动端网页特效

1. DOM触屏事件

  • touchstart 触摸事件
  • touchmove 触摸移动事件
  • touchend 触摸离开事件

当手机按压某块内容,先触发 touchstart ,如果不松手并移动就触发 touchmove ,松手就触发 touchend

2.触摸事件对象

TouchEvent 是一类描述手指在触摸屏幕的状态变化的事件。这类事件描述一个或多个触点。

常用触摸元素 targetTouches

1
2
3
1. touches  正在触摸屏幕手指的一个列表
2. targetTouches 正在触摸当前 DOM 元素上的手指的一个列表
3. changedTouches 手指状态发送了改变的列表,从无到有,从有到无的变化

3.移动端移动盒子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// (1) 触摸元素 touchstart 获取手指初始坐标,同时获得盒子原来的位置
// (2) 移动手指 touchmove 计算手指的滑动距离,并且移动盒子
// (3) 离开手指 touchend
var div = document.querySelector('div');
var startX = 0; // 获取手指初始坐标
var startY = 0;
var x = 0; // 获得盒子原来的位置
var y = 0;
div.addEventListener('touchstart',function(e){
// 获取手指初始坐标
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
x = this.offsetLeft;
y = this.offsetTop;
})

div.addEventListener('touchmove',function(e){
// 计算手指的移动距离:手指移动之后的坐标减去手指初始的坐标
var moveX = e.targetTouches[0].pageX - startX;
var moveY = e.targetTouches[0].pageY - startY;
// 移动我们的盒子 盒子原来的位置 + 手指移动的距离
this.style.left = x + moveX + 'px';
this.style.top = y + moveY + 'px';
// 手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动
e.preventDefault();
})

4.添加类名 classList

1
2
3
// <div class="one two"></div> 追加类名
element.classList.add('newClass');
// 添加后 class="one two newClass"

移动类名

element.classList.remove('one')

切换类,有就删除,没有就添加

element.classList.toggle('bg')

本地存储WebStorage

本地存储特性

  1. 数据存储在用户浏览器中

  2. 设置、读取方便、甚至页面刷新不丢失数据

  3. 容量较大,sessionStorage 约5MlocalStorage 约20M

  4. 只能存储字符串,可以将对象 JSON.stringify() 编码后存储

    通过JSON.parse()解析

1.window.sessionStorage

  • 生命周期为关闭浏览器
  • 在用一个窗口下数据可以共享
  • 以键值对的形式存储使用
1
2
3
4
5
6
7
8
// 存储数据
sessionStorage.setItem(key,value)
// 获取数据
sessionStorage.getItem(key)
// 移除数据
sessionStorage.removeItem(key)
// 清除所有的数据
sessionStorage.clear()

2.window.localStorage

  • 生命周期永久生效,除非手动删除 否则关闭页面也会存在
  • 可以多窗口共享(同浏览器可以共享)
  • 以键值对的形式存储
1
2
3
4
5
6
7
8
// 存储数据
localStorage.setItem(key,value)
// 获取数据
localStorage.getItem(key)
// 移除数据
localStorage.removeItem(key)
// 清除所有的数据
localStorage.clear()