| <!DOCTYPE html> |
| <html lang="zh"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <title>DIY跳动爱心</title> |
| <style> |
| * { |
| padding: 0; |
| margin: 0; |
| } |
| |
| body { |
| height: 600px; |
| padding: 0; |
| margin: 0; |
| background: #000; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| } |
| |
| .container { |
| width: 500px; |
| height: 500px; |
| position: relative; |
| } |
| |
| canvas { |
| z-index: 99; |
| position: absolute; |
| width: 500px; |
| height: 500px; |
| } |
| |
| .text_box { |
| text-align: center; |
| position: absolute; |
| font-size: 1.125rem; |
| top: 36%; |
| left: 22%; |
| color: #ff437b; |
| z-index: 100; |
| } |
| |
| input { |
| font-size: 1.375rem; |
| color: #ff437b; |
| text-align: center; |
| background: none; |
| } |
| |
| button { |
| font-size: 1.375rem; |
| border: none; |
| border-radius: 4px; |
| } |
| |
| input::input-placeholder { |
| color: #dc4b61; |
| } |
| |
| input::-webkit-input-placeholder { |
| color: #dc4b61; |
| } |
| |
| |
| .heart { |
| animation: heart 1s infinite ease-in-out; |
| } |
| |
| @keyframes heart { |
| |
| 0%, |
| 100% { |
| transform: rotate(-2deg) scale(1); |
| } |
| |
| 50% { |
| transform: rotate(2deg) scale(1.12); |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div id="jsi-cherry-container" class="container "> |
| |
| <canvas id="pinkboard" class="container heart"> </canvas> |
| |
| <div class="text_box"> |
| <input type="text" id="text" placeholder="送给你的那个[Ta]️"> |
| <button id="btn" onclick="fn()">❤️</button> |
| </div> |
| |
| </div> |
| </body> |
| <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> |
| <script> |
| function fn() { |
| var a1 = document.querySelector('#text'); |
| var btn = document.querySelector('#btn'); |
| a1.style.border = 'none'; |
| btn.parentNode.removeChild(btn); |
| console.log("点关注不迷路!"); |
| } |
| </script> |
| <script> |
| |
| |
| |
| var settings = { |
| particles: { |
| length: 500, |
| duration: 2, |
| velocity: 100, |
| effect: -0.75, |
| size: 30, |
| }, |
| }; |
| |
| (function() { |
| var b = 0; |
| var c = ["ms", "moz", "webkit", "o"]; |
| for (var a = 0; a < c.length && !window.requestAnimationFrame; ++a) { |
| window.requestAnimationFrame = window[c[a] + "RequestAnimationFrame"]; |
| window.cancelAnimationFrame = |
| window[c[a] + "CancelAnimationFrame"] || |
| window[c[a] + "CancelRequestAnimationFrame"]; |
| } |
| if (!window.requestAnimationFrame) { |
| window.requestAnimationFrame = function(h, e) { |
| var d = new Date().getTime(); |
| var f = Math.max(0, 16 - (d - b)); |
| var g = window.setTimeout(function() { |
| h(d + f); |
| }, f); |
| b = d + f; |
| return g; |
| }; |
| } |
| if (!window.cancelAnimationFrame) { |
| window.cancelAnimationFrame = function(d) { |
| clearTimeout(d); |
| }; |
| } |
| })(); |
| |
| |
| |
| |
| var Point = (function() { |
| function Point(x, y) { |
| this.x = typeof x !== "undefined" ? x : 0; |
| this.y = typeof y !== "undefined" ? y : 0; |
| } |
| Point.prototype.clone = function() { |
| return new Point(this.x, this.y); |
| }; |
| Point.prototype.length = function(length) { |
| if (typeof length == "undefined") |
| return Math.sqrt(this.x * this.x + this.y * this.y); |
| this.normalize(); |
| this.x *= length; |
| this.y *= length; |
| return this; |
| }; |
| Point.prototype.normalize = function() { |
| var length = this.length(); |
| this.x /= length; |
| this.y /= length; |
| return this; |
| }; |
| return Point; |
| })(); |
| |
| |
| |
| |
| var Particle = (function() { |
| function Particle() { |
| this.position = new Point(); |
| this.velocity = new Point(); |
| this.acceleration = new Point(); |
| this.age = 0; |
| } |
| Particle.prototype.initialize = function(x, y, dx, dy) { |
| this.position.x = x; |
| this.position.y = y; |
| this.velocity.x = dx; |
| this.velocity.y = dy; |
| this.acceleration.x = dx * settings.particles.effect; |
| this.acceleration.y = dy * settings.particles.effect; |
| this.age = 0; |
| }; |
| Particle.prototype.update = function(deltaTime) { |
| this.position.x += this.velocity.x * deltaTime; |
| this.position.y += this.velocity.y * deltaTime; |
| this.velocity.x += this.acceleration.x * deltaTime; |
| this.velocity.y += this.acceleration.y * deltaTime; |
| this.age += deltaTime; |
| }; |
| Particle.prototype.draw = function(context, image) { |
| function ease(t) { |
| return --t * t * t + 1; |
| } |
| var size = image.width * ease(this.age / settings.particles.duration); |
| context.globalAlpha = 1 - this.age / settings.particles.duration; |
| context.drawImage( |
| image, |
| this.position.x - size / 2, |
| this.position.y - size / 2, |
| size, |
| size |
| ); |
| }; |
| return Particle; |
| })(); |
| |
| |
| |
| |
| var ParticlePool = (function() { |
| var particles, |
| firstActive = 0, |
| firstFree = 0, |
| duration = settings.particles.duration; |
| |
| function ParticlePool(length) { |
| |
| particles = new Array(length); |
| for (var i = 0; i < particles.length; i++) |
| particles[i] = new Particle(); |
| } |
| ParticlePool.prototype.add = function(x, y, dx, dy) { |
| particles[firstFree].initialize(x, y, dx, dy); |
| |
| |
| firstFree++; |
| if (firstFree == particles.length) firstFree = 0; |
| if (firstActive == firstFree) firstActive++; |
| if (firstActive == particles.length) firstActive = 0; |
| }; |
| ParticlePool.prototype.update = function(deltaTime) { |
| var i; |
| |
| |
| if (firstActive < firstFree) { |
| for (i = firstActive; i < firstFree; i++) |
| particles[i].update(deltaTime); |
| } |
| if (firstFree < firstActive) { |
| for (i = firstActive; i < particles.length; i++) |
| particles[i].update(deltaTime); |
| for (i = 0; i < firstFree; i++) particles[i].update(deltaTime); |
| } |
| |
| |
| while ( |
| particles[firstActive].age >= duration && |
| firstActive != firstFree |
| ) { |
| firstActive++; |
| if (firstActive == particles.length) firstActive = 0; |
| } |
| }; |
| ParticlePool.prototype.draw = function(context, image) { |
| |
| if (firstActive < firstFree) { |
| for (i = firstActive; i < firstFree; i++) |
| particles[i].draw(context, image); |
| } |
| if (firstFree < firstActive) { |
| for (i = firstActive; i < particles.length; i++) |
| particles[i].draw(context, image); |
| for (i = 0; i < firstFree; i++) particles[i].draw(context, image); |
| } |
| }; |
| return ParticlePool; |
| })(); |
| |
| |
| |
| |
| (function(canvas) { |
| var context = canvas.getContext("2d"), |
| particles = new ParticlePool(settings.particles.length), |
| particleRate = |
| settings.particles.length / settings.particles.duration, |
| time; |
| |
| |
| function pointOnHeart(t) { |
| return new Point( |
| 160 * Math.pow(Math.sin(t), 3), |
| 130 * Math.cos(t) - |
| 50 * Math.cos(2 * t) - |
| 20 * Math.cos(3 * t) - |
| 10 * Math.cos(4 * t) + |
| 25 |
| ); |
| } |
| |
| |
| var image = (function() { |
| var canvas = document.createElement("canvas"), |
| context = canvas.getContext("2d"); |
| canvas.width = settings.particles.size; |
| canvas.height = settings.particles.size; |
| |
| function to(t) { |
| var point = pointOnHeart(t); |
| point.x = |
| settings.particles.size / 2 + |
| (point.x * settings.particles.size) / 350; |
| point.y = |
| settings.particles.size / 2 - |
| (point.y * settings.particles.size) / 350; |
| return point; |
| } |
| |
| context.beginPath(); |
| var t = -Math.PI; |
| var point = to(t); |
| context.moveTo(point.x, point.y); |
| while (t < Math.PI) { |
| t += 0.01; |
| point = to(t); |
| context.lineTo(point.x, point.y); |
| } |
| context.closePath(); |
| |
| context.fillStyle = "#dc4b61"; |
| context.fill(); |
| |
| var image = new Image(); |
| image.src = canvas.toDataURL(); |
| return image; |
| })(); |
| |
| |
| function render() { |
| |
| requestAnimationFrame(render); |
| |
| |
| var newTime = new Date().getTime() / 1000, |
| deltaTime = newTime - (time || newTime); |
| time = newTime; |
| |
| |
| context.clearRect(0, 0, canvas.width, canvas.height); |
| |
| |
| var amount = particleRate * deltaTime; |
| for (var i = 0; i < amount; i++) { |
| var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random()); |
| var dir = pos.clone().length(settings.particles.velocity); |
| particles.add( |
| canvas.width / 2 + pos.x, |
| canvas.height / 2 - pos.y, |
| dir.x, |
| -dir.y |
| ); |
| } |
| |
| |
| particles.update(deltaTime); |
| particles.draw(context, image); |
| } |
| |
| |
| function onResize() { |
| canvas.width = canvas.clientWidth; |
| canvas.height = canvas.clientHeight; |
| } |
| window.onresize = onResize; |
| |
| |
| setTimeout(function() { |
| onResize(); |
| render(); |
| }, 10); |
| })(document.getElementById("pinkboard")); |
| </script> |
| </html> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)