# 小册学习 demo
掘金小册的学习demo: 如何使用 Canvas 制作出炫酷的网页背景特效
# 小册介绍
这本小册比较简单,对canvas的一些应用场景介绍,api的介绍,然后通过一个例子进行实战;
# 看完小册之后便动起手来
背景颜色模拟昼夜交替的做法让我有点意外,这小脑袋也太机智了 笔者利用了一个蓝黑的渐变作为最底层的背景颜色,然后通过一个有透明度动画效果的遮罩层实现昼夜交替的效果;
<div class="wrapper">
<div class="wrapper_mark"></div>
<img class="img" src="./city.png">
<canvas id="canvas"></canvas>
</div>
1
2
3
4
5
2
3
4
5
<style type="text/css">
body, html{
padding: 0;
margin: 0;
}
.wrapper {
font-size: 0;
background: linear-gradient(to bottom, #000000 0%, #5788fe 100%);
position: relative;
}
.wrapper_mark {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background: #fe5757;
animation: colorChange 30s ease-in-out infinite;
animation-fill-mode: both;
mix-blend-mode: overlay;
}
.img {
position: absolute;
width: 100%;
z-index: 20;
left: 0;
right: 0;
bottom: 0;
}
#canvas {
position: relative;
z-index: 10;
}
@keyframes colorChange {
0%, 100% {
opacity: 0;
}
50% {
opacity: .9;
}
}
</style>
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
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
canvas的逻辑部分全部在CanvasRond.js中,在使用时先引入,
window.onload = () => {
let canvas = document.getElementById('canvas');
this.canvasRond = new CanvasRond({
el: canvas,
width: window.innerWidth,
height: window.innerHeight,
initRoundPopulation: 40 // 粒子的个数
})
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
用面向对象的方式,会使整个逻辑更加的清晰;
- CanvasRond是整个舞台对象
- RounItem是粒子对象
- MouseRound是触摸移动生成的圆的对象
class CanvasRond {
constructor({el, width, height, initRoundPopulation}) {
this.el = el;
this.width = width;
this.height = height;
this.el.width = this.width;
this.el.height = this.height;
this.initRoundPopulation = initRoundPopulation;
this.content = this.el.getContext('2d');
this.init();
}
// 初始化
init() {
this.rounds = [];
let {content, initRoundPopulation, width, height} = this;
for (let i = 0; i < initRoundPopulation; i++) {
this.rounds[i] = new RounItem({
index: i,
x: Math.random() * width,
y: Math.random() * height,
content
});
this.rounds[i].draw();
}
this.addEventListener();
this.render();
}
// 渲染
render() {
let {width, height, content} = this;
content.clearRect(0, 0, width, height);
this.rounds.forEach(item => {
item.y < 0 ? (item.y = height) : item.move();
})
this.mouseRounds.forEach((item, index) => {
item.r < 0 ? this.mouseRounds.splice(index, 1) : item.move();
})
requestAnimationFrame(this.render.bind(this));
}
// 添加事件
addEventListener() {
this.mouseRounds = [];
let lock = false;
window.addEventListener('touchmove', e => {
if (!lock) { //节流
lock = true;
this.mouseRounds.push(new MouseRound({
x: e.touches[0].clientX,
y: e.touches[0].clientY,
r: 6,
content: this.content
}));
setTimeout(() => {
lock = false
}, 30);
}
})
}
}
class RounItem {
constructor({index, x, y, content}) {
this.content = content;
this.index = index;
this.x = x;
this.y = y;
this.r = Math.random() * 2 + 1;
let alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
this.color = "rgba(255, 255, 255, " + alpha + ")";
}
draw() {
let {content, color, r, x, y} = this;
content.fillStyle = color;
content.shadowBlur = r * 2;
content.beginPath();
content.arc(x, y, r, 0, 2 * Math.PI, false);
content.closePath();
content.fill();
}
move() {
this.y -= 0.15;
this.draw();
}
}
class MouseRound {
constructor({x, y, r, content}) {
this.content = content;
this.x = x;
this.y = y;
this.r = r;
this.color = '#fff';
}
draw() {
let {content, color, r, x, y} = this;
content.fillStyle = color;
content.shadowBlur = r * 5;
content.shadowColor = '#fff';
content.beginPath();
content.arc(x, y, r, 0, 2 * Math.PI, false);
content.closePath();
content.fill();
}
move() {
this.r -= 0.2;
if (this.r < 0) return;
this.draw();
}
}
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# 小结
以上逻辑也比较的简单,利用对于画布的清除和再次重绘,实现动画; 利用requestAnimationFrame,我们可以实现60/s的刷新频率,对于画布上所要出现的东西,我们都用对象的方式,去存储在list中,每次刷新的时候我们都可以去改变对象的属性,并在requestAnimationFrame的回调函数中,我们清空画布并且把最新的list中的对象渲染到画布中;
dranein@163.com
地址:https://github.com/Dranein/activities-/tree/master/canvas/city