效果图
具体效果请参考这个页面
思路
事件绑定
方法为:document.addEventListener(event, function, useCapture);
event为描述事件名称的字符串。
function为事件发生后触发执行的函数,当事件触发时,事件对象会作为第一个参数传入函数中。
useCapture为可选,默认为假的布尔值参数,true时事件句柄在捕获阶段执行,false时在冒泡阶段执行
1
| document.addEventListener("mousemove", myFunction);
|
当然,为了兼容手机端,也要绑定点击事件
1 2
| document.addEventListener("touchmove", myFunction); document.addEventListener("touchstart", myFunction);
|
元素
- 声明一个类,鼠标移动时实例化为拖尾元素;
- 元素实例化后进行初始化,元素属性要包括元素坐标,样式,颜色和速度,还有存活时间;
- 元素还要有个Update函数,根据速度计算出下一帧的坐标位置。根据剩余存活时间计算出缩放大小;
- 元素需要有一个销毁眼熟,当存活时间小于等于0的时候调用;
主循环
- 在鼠标移动时,每个循环在鼠标位置生成一个元素并初始化;
- 每个生成的元素都存在数组中,每个循环遍历所有数组元素进行Update,并进行渲染;
- 当元素存活时间小于等于0时,调用销毁函数,并将此元素移除数组;
通过计时器进行循环:setInerval(code, millisec)
1
| setInterval(function (), 1000 / 60);
|
因为时间以毫秒计数,所以如果一秒要刷新60帧则时间为1000 / 60;
特效
- 使用Math.random() 达成随机颜色和随机样式;
完整代码
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
| (function () { var colors = ["#D61C59", "#E7D84B", "#1B8798"]; characters = ["♬", "♪"]; elementGroup = []; class Element { constructor() { num = Math.floor(Math.random() * characters.length); this.character = characters[num]; this.lifeSpan = 120; this.initialStyles = { position: "fixed", top: "0", display: "block", pointerEvents: "none", "z-index": "10000000", fontSize: "25px", "will-change": "transform", color: "#000000" }; this.init = function (x, y, color) { this.velocity = { x: (Math.random() < .5 ? -1 : 1) * (Math.random() / 2), y: 1 }; this.position = { x: x - 10, y: y - 20 }; this.initialStyles.color = color; this.element = document.createElement("span"); this.element.innerHTML = this.character; ApplyStyle(this.element, this.initialStyles); this.update(); document.body.appendChild(this.element); }; this.update = function () { this.position.x += this.velocity.x; this.position.y += this.velocity.y; this.lifeSpan--; this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + this.lifeSpan / 120 + ")"; }; this.die = function () { this.element.parentNode.removeChild(this.element); }; } }
AddListener(); setInterval( function () { Rander(); }, 1000 / 60); function AddListener() { document.addEventListener("mousemove", onMouseMove); document.addEventListener("touchmove", Touch); document.addEventListener("touchstart", Touch); } function Rander() { for (var i = 0; i < elementGroup.length; i++) { elementGroup[i].update(); if (elementGroup[i].lifeSpan < 0) { elementGroup[i].die(); elementGroup.splice(i, 1); } } } function onMouseMove(t) { num = Math.floor(Math.random() * colors.length); CreateElement(t.clientX, t.clientY, colors[num]); } function CreateElement(x, y, color) { var e = new Element; e.init(x, y, color); elementGroup.push(e); } function ApplyStyle(element, style) { for (var i in style) { element.style[i] = style[i]; } } function Touch(t) { if (t.touches.length > 0) { for (var i = 0; i < t.touches.length; i++) { num = Math.floor(Math.random() * r.length); s(t.touches[i].clientX, t.touches[i].clientY, r[num]); } } } })();
|