背景:
今天,突然想到之前碰到过的一个场景:QQ空间中有着一些漂浮的装饰挂件,能够规律性在页面中移动(因为本人之前浏览别人空间时,确实遇到过装饰的非常好看的界面,因此印象比较深刻)。于是非常想知道这个功能是怎么实现的,于是就有了这一篇博客。
原理:
其实,实现原理很简单,就是在页面中添加一些好看的元素,然后使用定时器周期性改变这些元素的位置,这实现了该功能。这个可以在你自己的QQ空间中去验证,如下图片所示:
移动元素的原理
代码:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>移动标签实践</title>
6 <style>
7 body {
8 width: 1000px;
9 height: 600px;
10 margin: 0 auto;
11 position: relative;
12 border: black solid 1px;
13 }
14 #moveTag {
15 width: 30px;
16 height: 30px;
17 margin: 0;
18 position: absolute;
19 box-sizing: border-box;
20 border: black solid 1px;
21 }
22 </style>
23 </head>
24 <body>
25 <div id="moveTag"></div>
26 <script defer>
27 // 将传入的属性(string型,单位为 px)转换为 Number
28 const returnNumber = (num) => {
29 let x = num.indexOf('p')
30 return Number(num.slice(0, x))
31 }
32
33 // x 为计算过后的 margin 值,limit 表示移动的范围限制(分为横纵两轴),adjustment 表示的是移动元素的属性(分为width 和height)
34 const dealLimit = (x, limit, adjustment) => {
35 // console.log(x + ' ' + limit)
36 if (x >= limit) {
37 // 之所以要是使用 limit - adjustment,是因为移动的元素不要移动到当前元素的外面(此时为最大值限制)
38 return limit - adjustment + 'px'
39 } else if (x <= 0) {
40 // 此时为最小值限制
41 return 0 + 'px'
42 } else {
43 // 如果移动的值在范围之内,则直接返回
44 return x + 'px'
45 }
46 }
47
48 // 该函数是主要的变换函数
49 const moveTagElement = () => {
50 // 这里使用了闭包,保存了需要大量使用过的变量
51
52 let ele = document.querySelector('#moveTag')
53 // 获取<style>标签中的CSS值
54 // 注意:ele.style.property 这种语法只能获取内联CSS的属性
55 // 移动元素的width
56 let moveTagwidth = returnNumber(window.getComputedStyle(ele).getPropertyValue('width'))
57 // 移动元素的heigth
58 let moveTagheight = returnNumber(window.getComputedStyle(ele).getPropertyValue('height'))
59 // 由于 ele 不再使用,故释放 ele 的内存占用
60 ele = null
61
62 let box = document.querySelector('body')
63 // 参照元素的width
64 let boxWidth = returnNumber(window.getComputedStyle(box).getPropertyValue('width'))
65 // 参照元素的height
66 let boxHeight = returnNumber(window.getComputedStyle(box).getPropertyValue('height'))
67 // 由于 box 不再使用,故释放 box 的内存占用
68 box = null
69
70 // 用来判断 marginTop 是 + 还是 - ,即移动元素在 x 方向上是右移还是左移
71 let judgeTop = true
72 // 用来判断 marginLeft 是 + 还是 -,即移动元素在 y 方向上是是下移还是上移
73 let judgeLeft = true
74
75 return function () {
76 let ele = document.querySelector('#moveTag')
77 let top = returnNumber(ele.style.marginTop)
78 let left = returnNumber(ele.style.marginLeft)
79
80 // 表示移动的量
81 let topChange = 10
82 let leftChange = 10
83
84 // 这里和前面需要保持一致
85 // 如果超过 box 的限制,则改变移动元素移动的方向(上下)
86 if (top <= 0 || top >= boxHeight - moveTagheight) {
87 judgeTop = !judgeTop
88 }
89 // 计算移动的值,并赋值
90 ele.style.marginTop = judgeTop ? dealLimit(top + topChange, boxHeight, moveTagheight) : dealLimit(top - topChange, boxHeight, moveTagheight)
91
92 // 如果超过 box 的限制,则改变移动元素移动的方向(左右)
93 if (left <= 0 || left >= boxWidth - moveTagwidth) {
94 judgeLeft = !judgeLeft
95 }
96 // 计算移动的值,并赋值
97 ele.style.marginLeft = judgeLeft ? dealLimit(left + leftChange, boxWidth, moveTagwidth) : dealLimit(left - leftChange, boxWidth, moveTagwidth)
98 }
99 }
100
101 let func = moveTagElement()
102 // 使用定时器进行周期性控制
103 let timer = setInterval(func, 50)
104 </script>
105 </body>
106 </html>
运行结果:
运行结果
代码说明:
代码在注释中说的非常明白了,同时原理也并非很复杂,所以这里并不打算在继续使用文字进行相关的原理的介绍,有兴趣的小伙伴可以直接复制代码进行查看。
个人吐槽:
①. 虽然运行的结果简陋了点,但是原理确实实现了,( 0.0 )如果想更加美观一点,只需要更改界面以及移动元素的背景图片即可。
②. 做完这个内容我发现了一个问题:那就是打砖块这个游戏其实原理就是这个(这里自己先挖一个坑)
③. over