效果:
代码:
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
let num = 0;
const show = ref(true)
let arr1 = new Array(120);
arr1.fill("12");
function getMousePosition(event) {
var x = 0;
var y = 0;
var doc = document.documentElement;
var body = document.body;
if(!event) event=window.event;
if (window.pageYoffset) {//pageYoffset是Netscape特有
x = window.pageXOffset;
y = window.pageYOffset;
}else{
x = (doc && doc.scrollLeft || body && body.scrollLeft || 0)
- (doc && doc.clientLeft || body && body.clientLeft || 0);
y = (doc && doc.scrollTop || body && body.scrollTop || 0)
- (doc && doc.clientTop || body && body.clientTop || 0);
}
x += event.clientX;
y += event.clientY;
return {'x' : x, 'y' : y};
};
const createFire = ({x,y})=>{
var firePage = document.getElementById('firePage');
let newFire = document.createElement('div');
newFire.className = "fireOrigin";
newFire.id = `fireOrigin_${num}`;
newFire.style.left = `${x}px`;
newFire.style.top = `${y}px`;
newFire.style.transform = 'translate(-50% , -50%)';
newFire.style.position = "absolute";
newFire.style.margin = "0";
let html = ''
for (let i = 0; i < arr1.length; i++) {
html = html + `<div class="fireItem fireItem_${i%6}">
<div class="fireItem1 fireItemTail"></div>
<div class="fireItem2 fireItemTail"></div>
</div>`
}
newFire.innerHTML = html
firePage.appendChild(newFire);
const numberStr = num
setTimeout(()=>{
console.log(`fireOrigin_${numberStr}`);
let removeChild = document.getElementById(`fireOrigin_${numberStr}`);
firePage.removeChild(removeChild)
},3500)
num++
console.log(num,x,y);
};
onMounted(() => {
document.addEventListener('click',(e)=>{
const obj = getMousePosition(e)
createFire(obj)
})
});
onUnmounted(()=>{
document.removeEventListener('click',(e)=>{
const obj = getMousePosition(e)
createFire(obj)
})
})
</script>
<template>
<div class="firePage" id="firePage">
<div class="fireOrigin" id="fireOrigin">
<div
v-for="(item, index) in arr1"
:class="'fireItem_' + (index % 6)"
:key="index"
class="fireItem"
>
<div class="fireItem1 fireItemTail"></div>
<div class="fireItem2 fireItemTail"></div>
</div>
</div>
</div>
</template>
<style lang="less">
.firePage {
width: 100%;
height: 100vh;
min-height: 400px;
min-width: 400px;
background: #000;
border: 1px solid transparent;
position: relative;
.fireOrigin {
width: 400px;
height: 400px;
margin: 50px auto;
position: relative;
@fireBack: rgba(255, 0, 0, 1);
@fireBack1: rgba(255, 0, 0, 0.5);
@fireBack2: rgba(255, 0, 0, 0.3);
@fireBack3: rgba(255, 0, 0, 0);
@time: 3s;
.fireItem {
position: absolute;
width: 200px;
height: 1px;
background: transparent;
top: 50%;
left: 50%;
transform-origin: left;
z-index: 1;
.fireItem1 {
width: 0px;
// width: 10px;
// height: 10px;
height: 1px;
border-radius: 50% 0 50% 0;
background: @fireBack;
position: absolute;
z-index: 2;
left: 0px;
top: 50%;
transform: rotate(45deg) translateY(-50%);
animation: fireX1 @time
linear(0 0%, 0.9 64.68%, 0.95 70.53%, 0.98 79.68%, 1 88.97%, 1 100%);
}
.fireItem2 {
// width: 1px;
width: 0px;
height: 1px;
border-radius: 50% 0 50% 0;
background: @fireBack;
position: absolute;
z-index: 2;
left: 0px;
top: 50%;
transform: rotate(45deg) translateY(-50%);
animation: fireX2 @time
linear(0 0%, 0.9 64.68%, 0.95 70.53%, 0.98 79.68%, 1 88.97%, 1 100%);
}
.fireItemTail {
&::after {
content: "";
position: absolute;
left: 0;
top: 0;
transform: translate(-90%, 0%) rotate(-45deg);
clip-path: polygon(
0 60%,
0 40%,
30% 10%,
50% 0%,
100% 10%,
100% 90%,
50% 100%,
30% 90%
);
// width: 50px;
width: 0px;
height: 10px;
transform-origin: right center;
background: linear-gradient(
to left,
@fireBack1 0%,
@fireBack2 50%,
@fireBack3 100%
);
animation: tail @time linear;
}
@keyframes tail {
0% {
width: 0px;
height: 1px;
}
100% {
width: 50px;
height: 10px;
}
}
}
@keyframes fireX1 {
0% {
left: 0px;
width: 1px;
height: 1px;
opacity: 0.7;
box-shadow: 0px 0px 0px @fireBack;
}
30% {
opacity: 0.9;
}
50% {
opacity: 1;
box-shadow: 0px 0px 30px @fireBack;
}
70% {
opacity: 1;
}
80% {
opacity: 0.7;
}
90% {
opacity: 0.9;
}
100% {
left: 100%;
width: 10px;
height: 10px;
opacity: 0;
box-shadow: 0px 0px 40px @fireBack;
}
}
@keyframes fireX2 {
0% {
left: 0px;
width: 1px;
height: 1px;
opacity: 0.7;
box-shadow: 0px 0px 0px @fireBack;
}
30% {
opacity: 0.9;
}
50% {
opacity: 1;
box-shadow: 0px 0px 30px @fireBack;
}
70% {
opacity: 1;
}
80% {
opacity: 0.7;
}
90% {
opacity: 0.9;
}
100% {
left: 90%;
width: 10px;
height: 10px;
opacity: 0;
box-shadow: 0px 0px 40px @fireBack;
}
}
// transform: translate(-50%,-50%);
}
.fireItem_0 {
.fireItem1 {
animation-delay: 0s;
}
.fireItem2 {
animation-delay: @time / 4; // 0.75
}
}
.fireItem_1 {
.fireItem1 {
animation-delay: @time / 12; // 0.25
}
.fireItem2 {
animation-delay: @time / 3; // 1
}
}
.fireItem_2 {
.fireItem1 {
animation-delay: @time / 6; // 0.5
}
.fireItem2 {
animation-delay: @time / 2.4; // 1.25
}
}
.fireItem_3 {
.fireItem1 {
animation-delay: @time / 12;
}
.fireItem2 {
animation-delay: @time / 3;
}
}
.fireItem_4 {
.fireItem1 {
animation-delay: 0s;
}
.fireItem2 {
animation-delay: @time / 4;
}
}
.fireItem_5 {
.fireItem1 {
animation-delay: @time / 6;
}
.fireItem2 {
animation-delay: @time / 2.4;
}
}
.generate-z-index(@n, @i: 1) when (@i =< @n) {
@deg: 360deg / @n;
.fireItem:nth-child(@{i}) {
z-index: (200-@i);
transform: rotate(@deg * (@i));
-ms-transform: rotate(@deg * (@i)); /* Internet Explorer */
-moz-transform: rotate(@deg * (@i)); /* Firefox */
-webkit-transform: rotate(@deg * (@i)); /* Safari 和 Chrome */
-o-transform: rotate(@deg * (@i)); /* Opera */
.fireItem1 {
}
}
.generate-z-index(@n, (@i + 1));
}
.generate-z-index(120);
}
}
</style>