粒子效果 tsparticles 封装使用
shell
pnpm add tsparticles @tsparticles/vue3 @tsparticles/engine tsparticles-interaction-particles-links lodash-es
pnpm add -D @types/lodash-es查看封装代码
ts
import type { Engine, IOptions, IParticlesOptions, RecursivePartial } from '@tsparticles/engine'
import { merge } from 'lodash-es'
import { loadFull } from 'tsparticles'
import type { ILinks } from 'tsparticles-interaction-particles-links'
// 官方网站 https://particles.js.org/
// 官方文档 https://particles.js.org/docs/interfaces/tsParticles_Engine.Options_Interfaces_IOptions.IOptions.html
export type Option = RecursivePartial<
IOptions & {
particles: RecursivePartial<IParticlesOptions & { links: ILinks }>
emitters?: Option
}
>
export function createParticlesOption(option: Option) {
return merge(
{
autoPlay: true, // 自动播放
clear: true,
background: {
color: '#fff'
},
// 启用视网膜检测,如果禁用,画布使用的比率将始终为 1,而不是设备设置
detectRetina: true,
fpsLimit: 90, // 帧率限制
fullScreen: false, // 设置粒子画布的动画背景模式,将其置于前面或后面
// 粒子相互作用选项 交互
interactivity: {
// 将检测鼠标事件的位置 如果设置为canvas仅将粒子画布作为目标 如果设置为parent仅将粒子画布父级作为目标 如果设置为window每个区域都将作为目标
detectsOn: 'window',
// 交互模式选项,这配置每个模式的行为
modes: {
// 跟踪,拖拽
trail: {
delay: 1,
pauseOnStop: false,
quantity: 1
},
// 吸引
attract: {
distance: 100,
duration: 0.4,
easing: 'ease-out-quad',
factor: 1,
maxSpeed: 50,
speed: 1
},
// 碰撞
bounce: {
distance: 200
},
// 气泡
bubble: {
distance: 400,
duration: 2,
mix: false,
opacity: 1,
size: 40,
divs: {
distance: 200,
duration: 0.4,
mix: false,
selectors: []
}
},
// 连接
connect: {
distance: 80,
links: {
opacity: 0.5
},
radius: 60
},
// 抓住
grab: {
distance: 100,
links: {
blink: false,
consent: false,
opacity: 1
}
},
// 推、放(点击有效)
push: {
default: true,
groups: [],
quantity: 4
},
// 删除(点击有效)
remove: {
quantity: 2
},
// 排斥
repulse: {
distance: 200,
duration: 0.4,
factor: 100,
speed: 1,
maxSpeed: 50,
easing: 'ease-out-quad',
divs: {
distance: 200,
duration: 0.4,
factor: 100,
speed: 1,
maxSpeed: 50,
easing: 'ease-out-quad',
selectors: []
}
},
// 使迟缓,hover有效
slow: {
factor: 3,
radius: 200
},
// 高亮?
light: {
area: {
gradient: {
start: {
value: 'red'
},
stop: {
value: 'green'
}
},
radius: 1000
},
shadow: {
color: {
value: '#000000'
},
length: 2000
}
}
},
// 交互事件选项,这配置了启用哪些事件以及应使用哪些模式
events: {
onHover: { enable: false, mode: 'light' },
resize: { enable: true }
}
},
particles: {
// 反弹
bounce: {},
// 碰撞
collisions: {},
color: '#aaa',
// 效果
effect: {},
// 分组
// groups:{},
// 粒子间的连线
links: {},
move: {},
number: {},
opacity: {},
shadow: {},
// 形状
shape: {
// 自定义图片第一种
//type:'image'
//image:{ src:'' }
// 自定义图片第二种
//type: "images",
//options: {
// images: {
// src: "https://particles.js.org/images/cyan_amongus.png",
// width: 500,
// height: 634
// }
//}
},
size: {
// 变换
anim: {
enable: false,
speed: 80,
size_min: 4,
sync: false
}
},
stroke: {},
zIndex: {},
// 摇晃 loadSlim不生效,loadFull才生效
wobble: {
distance: 10,
enable: false,
speed: {
angle: 10,
move: 10
}
},
// 减少重复
reduceDuplicates: true
},
smooth: true, // 平滑动画
pauseOnOutsideViewport: false, // 视窗外暂停
pauseOnBlur: false // 失去焦点后暂停
// 弹射 loadFull生效
//emitters: {
// 速率
// rate: {
// 量
// quantity: 1,
// 延迟s
// delay: 1
// },
//}
} as Option,
option
) as Option
}
export async function particlesInit(engine: Engine) {
console.log('[ engine ]', engine)
await loadFull(engine)
//await loadSlim(engine);
}基本使用
查看代码
vue
<template>
<div>
<ClientOnly>
<vue-particles
style="z-index: -1; height: 400px; width: 100%"
id="tsparticles-basic"
@particles-loaded="particlesLoaded"
:options
/>
</ClientOnly>
</div>
</template>
<script lang="ts" setup>
import type { Container } from '@tsparticles/engine'
import { loadFull } from 'tsparticles'
import { getCurrentInstance } from 'vue'
import { createParticlesOption } from './particles'
const particlesLoaded = (container: Container) => {
console.log('Particles container loaded', container)
}
const options = createParticlesOption({
background: { color: '#000' },
interactivity: {
modes: {
grab: {
distance: 300
}
},
// 交互事件选项,这配置了启用哪些事件以及应使用哪些模式
events: {
onHover: { enable: true, mode: 'grab' },
onClick: { enable: true, mode: 'push' },
resize: { enable: true }
}
},
particles: {
color: {
value: '#aaa'
},
links: {
color: '#aaa',
distance: 150,
enable: true,
opacity: 0.75,
width: 2
},
move: {
enable: true,
outModes: 'bounce',
random: false,
speed: 3
},
number: {
value: 50
},
opacity: {
value: 0.75
},
shape: {
type: 'circle'
},
size: {
value: 5
}
}
})
</script>雪花
查看代码
vue
<template>
<div>
<ClientOnly>
<vue-particles
style="z-index: -1; height: 400px; width: 100%"
id="tsparticles-snow"
@particles-loaded="particlesLoaded"
:options
/>
</ClientOnly>
</div>
</template>
<script lang="ts" setup>
import type { Container } from '@tsparticles/engine'
import Particles from '@tsparticles/vue3'
import { loadFull } from 'tsparticles'
import { getCurrentInstance } from 'vue'
import { createParticlesOption } from './particles'
import snowSvg from './snow.svg'
const particlesLoaded = (container: Container) => {
console.log('Particles container loaded', container)
}
const options = createParticlesOption({
background: {
color: '#000'
},
particles: {
color: {
value: '#fff'
},
move: {
direction: 'bottom',
enable: true,
random: false,
speed: 3
},
number: { value: 60 },
opacity: {
value: { max: 0.8, min: 0.4 }
},
shape: { type: 'image', options: { image: { src: snowSvg } } },
// 暂时无效,不知原因
wobble: { distance: 10, enable: true, speed: { angle: 10, move: 10 } },
size: {
//random: true,
value: { max: 14, min: 4 }
}
}
})
</script>漂浮
查看代码
vue
<template>
<div>
<ClientOnly>
<vue-particles
style="z-index: -1; height: 400px; width: 100%"
id="tsparticles-fly"
@particles-loaded="particlesLoaded"
:options
/>
</ClientOnly>
</div>
</template>
<script lang="ts" setup>
import type { Container } from '@tsparticles/engine'
import Particles from '@tsparticles/vue3'
import { loadFull } from 'tsparticles'
import { getCurrentInstance } from 'vue'
import { createParticlesOption } from './particles'
import ufoSvg from './ufo.svg'
const particlesLoaded = (container: Container) => {
console.log('Particles container loaded', container)
}
const options = createParticlesOption({
background: { color: '#000' },
particles: {
color: { value: '#fff' },
groups: {
z5000: { number: { value: 70 }, zIndex: { value: 50 } },
z7500: { number: { value: 30 }, zIndex: { value: 75 } },
z2500: { number: { value: 50 }, zIndex: { value: 25 } },
z1000: { number: { value: 40 }, zIndex: { value: 10 } }
},
move: {
angle: { offset: 0, value: 10 },
direction: 'right',
enable: true,
speed: 5
},
number: { value: 200 },
opacity: { value: 1 },
shape: { close: true, fill: true, options: {}, type: 'circle' },
size: { value: 3 }
// zIndex: { value: 5, opacityRate: 0.5, sizeRate: 1, velocityRate: 1 },
},
// 弹射
emitters: {
autoPlay: true,
life: { wait: false },
rate: { quantity: 1, delay: 7 },
particles: {
shape: { type: 'image', options: { image: { src: ufoSvg } } },
size: { value: 60 },
move: {
speed: 10,
outModes: { default: 'out', right: 'destroy' },
straight: true
},
zIndex: { value: 0 }
//rotate: {
// value: { min: 0, max: 360 },
// animation: { enable: true, speed: 10, sync: true }
//}
},
position: { x: -5, y: 50 }
}
})
</script>星空
查看代码
vue
<template>
<div>
<ClientOnly>
<vue-particles
style="z-index: -1; height: 400px; width: 100%"
id="tsparticles-star"
@particles-loaded="particlesLoaded"
:options
/>
</ClientOnly>
</div>
</template>
<script lang="ts" setup>
import type { Container } from '@tsparticles/engine'
import Particles from '@tsparticles/vue3'
import { loadFull } from 'tsparticles'
import { getCurrentInstance } from 'vue'
import { createParticlesOption } from './particles'
import ufoSvg from './ufo.svg'
const particlesLoaded = (container: Container) => {
console.log('Particles container loaded', container)
}
const options = createParticlesOption({
background: { color: '#000' },
manualParticles: [
{
options: {
shape: { type: 'image', options: { image: { src: ufoSvg } } },
size: {
value: { min: 54, max: 80 },
animation: {
enable: true,
mode: 'auto',
speed: 50
}
},
move: { enable: false },
opacity: { value: 1 },
zIndex: { value: 0 }
},
position: { x: 50, y: 50 }
}
],
particles: {
color: { value: '#fff' },
groups: {
z5000: { number: { value: 70 }, zIndex: { value: 50 } },
z7500: { number: { value: 30 }, zIndex: { value: 75 } },
z2500: { number: { value: 50 }, zIndex: { value: 25 } },
z1000: { number: { value: 40 }, zIndex: { value: 10 } }
},
move: {
straight: true,
direction: 'left',
enable: true,
speed: 5
},
number: { value: 200 },
opacity: {
value: { max: 1, min: 0.4 },
animation: {
count: 0,
enable: true,
speed: 2,
sync: false,
mode: 'auto',
startValue: 'random'
}
},
shape: { type: 'star' },
size: { value: 3 }
}
})
</script>