← Back to Lab
// Engineering2026.05.042 min read

Vue3 组件封装哲学:从 RTSP 播放器到通用表单

在多个项目中沉淀的 Vue3 组件封装实践——RTSP 播放器自动重连、ActionOverflow 权限按钮、动态表单配置化生成,以及拖拽上传等通用组件的设计思路。

Vue3 组件封装哲学

核心原则

好的组件封装不是把代码藏起来,而是让团队不需要重复做同样的决策。

RTSP 播放器:自动重连

<template>
  <video ref="videoRef" @error="handleError" />
</template>

<script setup lang="ts">
const props = defineProps<{
  url: string
  autoReconnect?: boolean
  maxRetry?: number
}>()

const videoRef = ref<HTMLVideoElement>()
let retryCount = 0

const handleError = () => {
  if (!props.autoReconnect) return
  if (retryCount >= (props.maxRetry ?? 3)) return
  setTimeout(() => {
    retryCount++
    loadStream()
  }, 2000 * retryCount)
}

const loadStream = () => {
  if (!videoRef.value) return
  videoRef.value.src = props.url
  videoRef.value.play()
}

onMounted(loadStream)
</script>

ActionOverflow 权限按钮

根据用户权限动态显示/隐藏按钮:

// 全局注册
app.directive('permission', {
  mounted(el, binding) {
    const permissions = useUserStore().permissions
    if (!permissions.includes(binding.value)) {
      el.parentNode?.removeChild(el)
    }
  }
})

动态表单:配置化生成

interface FormField {
  key: string
  label: string
  type: 'input' | 'select' | 'date' | 'switch'
  rules?: Rule[]
  options?: { label: string; value: any }[]
  dynamic?: boolean  // 动态表单项
}

const formConfig: FormField[] = [
  { key: 'name', label: '姓名', type: 'input', rules: [required] },
  { key: 'type', label: '类型', type: 'select', options: [...] },
]

通过配置文件生成表单项,减少模板冗余代码超 50%。

拖拽上传

<template>
  <div
    class="upload-zone"
    @dragover.prevent="dragging = true"
    @dragleave.prevent="dragging = false"
    @drop.prevent="handleDrop"
  >
    <slot />
  </div>
</template>

沉淀规范

  • 统一样式与代码规范(ESLint / Prettier)
  • 通用组件全局注册,降低团队冲突率
  • 每个组件配套 TypeScript 类型定义