程序员的你是不是也想送个特别的礼物。今天给大家分享一个HTML+CSS+jQuery实现的情侣浪漫爱心表白JS特效,视觉效果还是相当不错!得此表白神器,程序猿也可以很浪漫!快去追你的女神吧,把这个告白爱心动画发给你心爱的她!
HTML代码如下,亲测可用。
<html lang="zh"> | |
<head> | |
<meta charset="UTF-"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>DIY跳动爱心</title> | |
<style> | |
* { | |
padding:; | |
margin:; | |
} | |
body { | |
height:px; | |
padding:; | |
margin:; | |
background: #; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.container { | |
width:px; | |
height:px; | |
position: relative; | |
} | |
canvas { | |
z-index:; | |
position: absolute; | |
width:px; | |
height:px; | |
} | |
.text_box { | |
text-align: center; | |
position: absolute; | |
font-size:.125rem; | |
top:%; | |
left:%; | |
color: #ffb; | |
z-index:; | |
} | |
input { | |
font-size:.375rem; | |
color: #ffb; | |
text-align: center; | |
background: none; | |
} | |
button { | |
font-size:.375rem; | |
border: none; | |
border-radius:px; | |
} | |
input::input-placeholder { | |
color: #dcb61; | |
} | |
input::-webkit-input-placeholder { | |
color: #dcb61; | |
} | |
.heart { | |
animation: hearts infinite ease-in-out; | |
} | |
@keyframes heart {%, | |
% { | |
transform: rotate(-deg) scale(1); | |
}% { | |
transform: rotate(deg) 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/.1.4/jquery.min.js"></script> | |
<script> | |
function fn() { | |
var a = document.querySelector('#text'); | |
var btn = document.querySelector('#btn'); | |
a.style.border = 'none'; | |
btn.parentNode.removeChild(btn); | |
console.log("点关注不迷路!"); | |
} | |
</script> | |
<script> | |
/* | |
* Settings | |
*/ | |
var settings = { | |
particles: { | |
length:, // maximum amount of particles | |
duration:, // particle duration in sec | |
velocity:, // particle velocity in pixels/sec | |
effect: -.75, // play with this for a nice effect | |
size:, // particle size in pixels | |
}, | |
}; | |
(function() { | |
var b =; | |
var c = ["ms", "moz", "webkit", "o"]; | |
for (var a =; 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(, 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); | |
}; | |
} | |
})(); | |
/* | |
* Point class | |
*/ | |
var Point = (function() { | |
function Point(x, y) { | |
this.x = typeof x !== "undefined" ? x :; | |
this.y = typeof y !== "undefined" ? y :; | |
} | |
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; | |
})(); | |
/* | |
* Particle class | |
*/ | |
var Particle = (function() { | |
function Particle() { | |
this.position = new Point(); | |
this.velocity = new Point(); | |
this.acceleration = new Point(); | |
this.age =; | |
} | |
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 =; | |
}; | |
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 +; | |
} | |
var size = image.width * ease(this.age / settings.particles.duration); | |
context.globalAlpha = - this.age / settings.particles.duration; | |
context.drawImage( | |
image, | |
this.position.x - size /, | |
this.position.y - size /, | |
size, | |
size | |
); | |
}; | |
return Particle; | |
})(); | |
/* | |
* ParticlePool class | |
*/ | |
var ParticlePool = (function() { | |
var particles, | |
firstActive =, | |
firstFree =, | |
duration = settings.particles.duration; | |
function ParticlePool(length) { | |
// create and populate particle pool | |
particles = new Array(length); | |
for (var i =; i < particles.length; i++) | |
particles[i] = new Particle(); | |
} | |
ParticlePool.prototype.add = function(x, y, dx, dy) { | |
particles[firstFree].initialize(x, y, dx, dy); | |
// handle circular queue | |
firstFree++; | |
if (firstFree == particles.length) firstFree =; | |
if (firstActive == firstFree) firstActive++; | |
if (firstActive == particles.length) firstActive =; | |
}; | |
ParticlePool.prototype.update = function(deltaTime) { | |
var i; | |
// update active particles | |
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 =; i < firstFree; i++) particles[i].update(deltaTime); | |
} | |
// remove inactive particles | |
while ( | |
particles[firstActive].age >= duration && | |
firstActive != firstFree | |
) { | |
firstActive++; | |
if (firstActive == particles.length) firstActive =; | |
} | |
}; | |
ParticlePool.prototype.draw = function(context, image) { | |
// draw active particles | |
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 =; i < firstFree; i++) particles[i].draw(context, image); | |
} | |
}; | |
return ParticlePool; | |
})(); | |
/* | |
* Putting it all together | |
*/ | |
(function(canvas) { | |
var context = canvas.getContext("d"), | |
particles = new ParticlePool(settings.particles.length), | |
particleRate = | |
settings.particles.length / settings.particles.duration, // particles/sec | |
time; | |
// get point on heart with -PI <= t <= PI | |
function pointOnHeart(t) { | |
return new Point( * Math.pow(Math.sin(t), 3), | |
* Math.cos(t) - | |
* Math.cos(2 * t) - | |
* Math.cos(3 * t) - | |
* Math.cos(4 * t) + | |
); | |
} | |
// creating the particle image using a dummy canvas | |
var image = (function() { | |
var canvas = document.createElement("canvas"), | |
context = canvas.getContext("d"); | |
canvas.width = settings.particles.size; | |
canvas.height = settings.particles.size; | |
// helper function to create the path | |
function to(t) { | |
var point = pointOnHeart(t); | |
point.x = | |
settings.particles.size / + | |
(point.x * settings.particles.size) /; | |
point.y = | |
settings.particles.size / - | |
(point.y * settings.particles.size) /; | |
return point; | |
} | |
// create the path | |
context.beginPath(); | |
var t = -Math.PI; | |
var point = to(t); | |
context.moveTo(point.x, point.y); | |
while (t < Math.PI) { | |
t +=.01; // baby steps! | |
point = to(t); | |
context.lineTo(point.x, point.y); | |
} | |
context.closePath(); | |
// create the fill | |
context.fillStyle = "#dcb61"; | |
context.fill(); | |
// create the image | |
var image = new Image(); | |
image.src = canvas.toDataURL(); | |
return image; | |
})(); | |
// render that thing! | |
function render() { | |
// next animation frame | |
requestAnimationFrame(render); | |
// update time | |
var newTime = new Date().getTime() /, | |
deltaTime = newTime - (time || newTime); | |
time = newTime; | |
// clear canvas | |
context.clearRect(, 0, canvas.width, canvas.height); | |
// create new particles | |
var amount = particleRate * deltaTime; | |
for (var i =; i < amount; i++) { | |
var pos = pointOnHeart(Math.PI - * Math.PI * Math.random()); | |
var dir = pos.clone().length(settings.particles.velocity); | |
particles.add( | |
canvas.width / + pos.x, | |
canvas.height / - pos.y, | |
dir.x, | |
-dir.y | |
); | |
} | |
// update and draw particles | |
particles.update(deltaTime); | |
particles.draw(context, image); | |
} | |
// handle (re-)sizing of the canvas | |
function onResize() { | |
canvas.width = canvas.clientWidth; | |
canvas.height = canvas.clientHeight; | |
} | |
window.onresize = onResize; | |
// delay rendering bootstrap | |
setTimeout(function() { | |
onResize(); | |
render(); | |
},); | |
})(document.getElementById("pinkboard")); | |
</script> | |
</html> |