Vue 3 组件推荐采用 独立目录封装 的结构,将组件模板、逻辑、样式、入口文件分离,适用于单个组件 / 组件库开发,核心优势:
结构清晰,便于团队协作与后期维护
支持局部 / 全局两种注册方式
适配 TypeScript 类型校验
便于扩展指令、样式、工具函数
最终标准目录结构:
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>说明
<script setup lang="ts">:Vue 3 官方推荐的组合式 API 语法糖,大幅简化组件编写
withDefaults + defineProps:TypeScript 环境下声明组件属性并设置默认值
defineEmits:声明组件自定义事件,是实现 v-model 双向绑定的核心
scoped 样式:Vue 自动为组件添加唯一属性,防止样式全局污染
属性透传:未定义的原生属性会自动绑定到组件根元素
创建 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)
}
}入口文件作用
统一组件导入路径,简化业务代码调用
实现 install 方法,支持全局注册组件
支持后续批量导出多个组件,适配组件库开发
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>组件采用目录化封装,是 Vue 3 企业级开发的标准规范
<script setup lang="ts"> + 类型声明,是 Vue 3 最新的组件编写方式
优先使用局部注册,全局注册适合高频使用的基础组件
完整的 Props + Events 设计,让组件具备复用性和扩展性