粒子效果、利用自定义ref实现防抖、TypeScript函数重载、命令式组件
一、如何轻松实现粒子效果particles.js
核心定位
专注实现粒子特效的第三方 JavaScript 库,支持雪花、新星、方块、线条等多种动态视觉效果。适合作为个人博客、在线简历、产品展示页等静态或轻交互页面的背景装饰,有效提升页面视觉质感与动态吸引力。
功能特点
- 预设效果丰富:内置雪花飘落、粒子新星爆发、方块矩阵、连线网络等多种经典粒子动画。
- 背景装饰专用:设计初衷即为页面添加优雅而不喧宾夺主的动态背景,增强浏览体验。
- 配置灵活:提供颜色、密度、速度、交互响应等多项参数,可轻松适配不同页面风格。
优势与特色
轻量级
- 无复杂依赖,纯 JavaScript 实现。
- 引入简单,几行代码即可启动特效。
- 对新手友好,学习成本低。
高持续认可度
- 项目约 10 年前 开发,已 8-9 年未主动维护。
- 在前端技术快速迭代的背景下,依然在 GitHub 上保持 27.3K Star,且数量仍在缓慢增长。
- 侧面印证其稳定性与实用性经受住了长期考验,被众多开发者持续使用与推荐。
适用场景
- 个人技术博客、作品集网站
- 在线简历、自我介绍页面
- 轻量级产品宣传页、活动页
- 需要温和动态元素增强氛围的静态页面
注意事项
- 项目已长期未更新,可能与最新浏览器 API 或前端框架存在兼容性问题,建议在实际引入前进行测试。
- 作为背景特效,应注意控制性能消耗,避免粒子数量过多导致低端设备卡顿。
- 因其未维护状态,不建议用于对安全性和长期维护性要求极高的生产环境。
简要使用示例(概念代码)
html
<script src="path/to/particle-library.js"></script>
<script>
// 通常只需初始化并选择效果类型
ParticleEffect.init({
type: 'snow',
color: '#ffffff',
density: 'medium'
});
</script>二、如何封装命令式组件
核心原则
通用功能封装的核心:优先保证使用便捷度,而非开发便捷度。 开发成本是一次性投入,而使用成本会随调用次数叠加,降低使用门槛能大幅提升团队效率。
核心思路:
通过函数调用的方式创建弹窗实例,无需在模板中声明组件。
1. 封装命令式弹窗函数 messageBox.js
ts
import { createVNode, render } from 'vue'
import MessageBox from './MessageBox.vue'
// 定义弹窗调用函数
export const showMessageBox = (options) => {
// 1. 解构参数:消息内容 + 确认回调
const { message, onConfirm } = options
// 2. 创建 DOM 容器
const container = document.createElement('div')
document.body.appendChild(container)
// 3. 创建组件虚拟节点(vnode)
const vnode = createVNode(MessageBox, {
visible: true,
message,
// 确认按钮的回调:执行传入的函数 + 销毁弹窗
confirm: () => {
onConfirm?.()
// 卸载组件 + 移除 DOM
render(null, container)
document.body.removeChild(container)
}
})
// 4. 渲染虚拟节点到 DOM 容器
render(vnode, container)
}2. 页面中调用函数(极简使用)
vue
<template>
<button @click="openMessageBox">命令式打开弹窗</button>
</template>
<script setup>
import { showMessageBox } from './messageBox.js'
const openMessageBox = () => {
// 只需调用函数,传入参数即可
showMessageBox({
message: '这是命令式弹窗',
onConfirm: () => {
console.log('用户点击了确定')
}
})
}
</script>3. 优化:高内聚整合(组件 + 函数写在一个文件)
为了更易维护,可将组件和函数整合到同一个 JS 文件,用 render 替代模板:
js
import { createVNode, render, defineComponent, h } from 'vue'
// 1. 用 defineComponent + h 函数定义弹窗组件
const MessageBox = defineComponent({
props: ['visible', 'message', 'onConfirm'],
render() {
if (!this.visible) return null
// h 函数:创建虚拟 DOM 节点
return h('div', {
style: {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '20px',
border: '1px solid #ccc',
background: '#fff'
}
}, [
h('div', null, this.message),
h('button', {
onClick: () => {
this.onConfirm?.()
}
}, '确定')
])
}
})
// 2. 封装调用函数
export const showMessageBox = (options) => {
const container = document.createElement('div')
document.body.appendChild(container)
const vnode = createVNode(MessageBox, {
visible: true,
...options,
onConfirm: () => {
options.onConfirm?.()
render(null, container)
document.body.removeChild(container)
}
})
render(vnode, container)
}也可以使用jsx, styled Component重构
前置准备
安装依赖
shell
npm install @styils/vue
npm install @vitejs/plugin-vue-jsx -D配置 vite.config.js 启用 JSX 插件
ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
export default defineConfig({
plugins: [vue(), vueJsx()]
})重构后代码
ts
import { createVNode, render, defineComponent } from 'vue'
import { styled } from '@styils/vue'
// 1. 用 @styils/vue 定义样式化组件
const MessageBoxWrapper = styled('div', {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '20px',
border: '1px solid #ccc',
background: '#fff',
borderRadius: '4px' // 额外加个圆角优化样式
})
const MessageContent = styled('div', {
marginBottom: '16px',
fontSize: '14px',
color: '#333'
})
const ConfirmButton = styled('button', {
padding: '4px 12px',
border: '1px solid #409eff',
background: '#409eff',
color: '#fff',
borderRadius: '4px',
cursor: 'pointer',
'&:hover': {
opacity: '0.9'
}
})
// 2. 用 JSX 定义弹窗组件(替代 h 函数)
const MessageBox = defineComponent({
props: {
visible: {
type: Boolean,
required: true
},
message: {
type: String,
required: true
},
onConfirm: {
type: Function,
default: () => {}
}
},
render() {
// 不显示则返回 null
if (!this.visible) return null
// JSX 语法,和 Vue 模板写法逻辑一致
return (
<MessageBoxWrapper>
<MessageContent>{this.message}</MessageContent>
<ConfirmButton onClick={this.onConfirm}>确定</ConfirmButton>
</MessageBoxWrapper>
)
}
})
// 3. 封装命令式调用函数(逻辑不变)
export const showMessageBox = (options) => {
const container = document.createElement('div')
document.body.appendChild(container)
const vnode = createVNode(MessageBox, {
visible: true,
...options,
// 点击确定后销毁组件 + 移除 DOM
onConfirm: () => {
options.onConfirm?.()
render(null, container)
document.body.removeChild(container)
}
})
render(vnode, container)
}核心亮点
- 命令式优势: 调用时无需关注组件挂载细节,一行代码即可弹出,大幅降低使用成本。
- 高内聚优化: 将组件逻辑和调用函数整合到单个文件,便于维护和复用。
- 内存友好: 弹窗关闭时主动卸载组件、移除 DOM 节点,避免内存泄漏。
