源本科技 | 码上会

Vue3 标准组件

2026/04/23
36
0

引言

目录设计规范

Vue 3 组件推荐采用 独立目录封装 的结构,将组件模板、逻辑、样式、入口文件分离,适用于单个组件 / 组件库开发,核心优势:

  1. 结构清晰,便于团队协作与后期维护

  2. 支持局部 / 全局两种注册方式

  3. 适配 TypeScript 类型校验

  4. 便于扩展指令、样式、工具函数

最终标准目录结构:

src/
└── components/
    └── MyText/           # 组件根目录(大驼峰命名)
        ├── src/          # 组件核心代码目录
        │   └── index.vue # 组件单文件
        └── index.ts      # 组件入口文件

创建组件目录

在项目的 src/components 目录下,新建子目录 MyText(组件名采用大驼峰命名法,为 Vue 官方强制规范)。

编写组件文件

创建 src/components/MyText/src/index.vue,基于 <script setup lang="ts"> 最新语法,实现文本输入框的双向绑定、属性配置、样式优化等核心功能:

<template>
  <!-- 文本输入框,自动透传原生属性 -->
  <input
    type="text"
    class="my-input-text"
    :value="modelValue"
    @input="$emit('update:modelValue', ($event.target as HTMLInputElement)?.value ?? '')"
    :placeholder="placeholder"
    :disabled="disabled"
  />
</template>

<script setup lang="ts">
/**
 * MyText 文本输入框组件
 * 支持 v-model 双向绑定、占位符、禁用状态
 */
interface Props {
  /** 双向绑定值 */
  modelValue?: string
  /** 输入框占位提示文字 */
  placeholder?: string
  /** 是否禁用输入框 */
  disabled?: boolean
}

// TS 环境定义 Props 并配置默认值
const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  placeholder: '请输入内容',
  disabled: false
})

// 定义自定义事件,实现 v-model 双向绑定
const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()
</script>

<style scoped>
/* scoped:样式仅作用于当前组件,避免全局污染 */
.my-input-text {
  width: 80%;
  padding: 10px;
  border-radius: 3px;
  border: 1px solid #ccc;
  outline: none;
  transition: border-color 0.3s;
}

/* 聚焦状态样式优化 */
.my-input-text:focus {
  border-color: #409eff;
}

/* 禁用状态样式 */
.my-input-text:disabled {
  background-color: #f5f7fa;
  cursor: not-allowed;
}
</style>

说明

  1. <script setup lang="ts">:Vue 3 官方推荐的组合式 API 语法糖,大幅简化组件编写

  2. withDefaults + defineProps:TypeScript 环境下声明组件属性并设置默认值

  3. defineEmits:声明组件自定义事件,是实现 v-model 双向绑定的核心

  4. scoped 样式:Vue 自动为组件添加唯一属性,防止样式全局污染

  5. 属性透传:未定义的原生属性会自动绑定到组件根元素

编写统一入口文件

创建 src/components/MyText/index.ts,作为组件的统一导出入口,同时兼容 Vue 插件规范:

// 导入组件核心文件
import MyText from './src/index.vue'

// 具名导出(用于局部注册)
export { MyText }

// 默认导出(支持 app.use 全局注册)
export default {
  install(app: any) {
    app.component('MyText', MyText)
  }
}

入口文件作用

  1. 统一组件导入路径,简化业务代码调用

  2. 实现 install 方法,支持全局注册组件

  3. 支持后续批量导出多个组件,适配组件库开发

TypeScript 类型声明

TS 项目必备

src 目录下创建 vite-env.d.ts,解决 TS 无法识别 .vue 单文件的问题:

/// <reference types="vite/client" />

// 声明 Vue 组件模块类型
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

组件使用方法

Vue 3 提供局部注册全局注册两种使用方式,按需选择即可。

局部注册使用(推荐)

按需导入组件,减少打包体积,是企业项目首选方案:

<template>
  <div class="demo-box">
    <h3>MyText 组件演示</h3>
    <!-- 基础用法 -->
    <MyText v-model="text" placeholder="请输入内容" />
    
    <!-- 禁用状态 -->
    <MyText v-model="disabledText" disabled placeholder="禁用输入框" />
  </div>
</template>

<script setup lang="ts">
import { MyText } from './components/MyText'
import { ref } from 'vue'

// 响应式数据
const text = ref('')
const disabledText = ref('测试数据')
</script>

<style scoped>
.demo-box {
  padding: 20px;
}
</style>

全局注册使用

在项目入口 src/main.ts 中注册,全项目可直接使用:

import { createApp } from 'vue'
import App from './App.vue'
// 导入组件
import MyText from './components/MyText'

const app = createApp(App)
// 全局注册组件
app.use(MyText)
app.mount('#app')

全局注册后,无需导入直接使用:

<template>
  <MyText v-model="value" />
</template>

组件进阶扩展

原生属性透传

无需额外配置,直接使用 input 原生属性:

<MyText v-model="value" maxlength="10" autocomplete="off" />

深度样式修改

使用 :deep() 语法修改组件内部样式(Vue 3 最新标准):

<style scoped>
:deep(.my-input-text) {
  width: 100 %;
}
</style>

总结

  1. 组件采用目录化封装,是 Vue 3 企业级开发的标准规范

  2. <script setup lang="ts"> + 类型声明,是 Vue 3 最新的组件编写方式

  3. 优先使用局部注册,全局注册适合高频使用的基础组件

  4. 完整的 Props + Events 设计,让组件具备复用性和扩展性