Skip to content

粒子效果、利用自定义ref实现防抖、TypeScript函数重载、命令式组件

一、如何轻松实现粒子效果particles.js

核心定位

专注实现粒子特效的第三方 JavaScript 库,支持雪花、新星、方块、线条等多种动态视觉效果。适合作为个人博客、在线简历、产品展示页等静态或轻交互页面的背景装饰,有效提升页面视觉质感与动态吸引力。

功能特点

  • 预设效果丰富:内置雪花飘落、粒子新星爆发、方块矩阵、连线网络等多种经典粒子动画。
  • 背景装饰专用:设计初衷即为页面添加优雅而不喧宾夺主的动态背景,增强浏览体验。
  • 配置灵活:提供颜色、密度、速度、交互响应等多项参数,可轻松适配不同页面风格。

优势与特色

  1. 轻量级

    • 无复杂依赖,纯 JavaScript 实现。
    • 引入简单,几行代码即可启动特效。
    • 对新手友好,学习成本低。
  2. 高持续认可度

    • 项目约 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 节点,避免内存泄漏。

The future is promising