1. 组件目录结构
将所有的组件放在统一的components
目录中,并按功能进行分类。例如:
src/
└── components/
├── common/ // 公共组件
│ ├── Button.vue
│ ├── Modal.vue
│ └── Icon.vue
├── user/ // 用户模块相关组件
│ ├── UserProfile.vue
│ └── UserList.vue
├── product/ // 产品模块相关组件
│ ├── ProductCard.vue
│ └── ProductList.vue
- 建议:每个文件夹下组件数量不宜过多,保证分类清晰。
- 分层级结构:根据组件的作用范围进行分类,如
common
存放通用组件,feature
存放特定功能模块的组件。
2. 组件命名
-
组件文件名:使用大驼峰命名法(PascalCase),与组件名保持一致,例如
UserProfile.vue
、ProductCard.vue
。 -
组件名称:组件的
name
字段使用大驼峰命名法,保持与文件名一致,方便调试和排查。 -
命名建议:
- 使用名词或名词短语,表示组件的功能或内容。
- 对于复用性高的组件,如
Button
、Input
,应保持名称简洁明确。 - 对于特定模块的组件,可以在名称中体现模块名,例如
UserList
、ProductCard
等。
3. 组件类型划分
根据组件的功能和重用性,划分为以下几类:
-
基础组件(Base Components):
- 这些组件通常是没有业务逻辑的纯UI组件,如
Button
、Input
、Icon
等。 - 命名通常以
Base
开头,例如BaseButton.vue
、BaseInput.vue
。
- 这些组件通常是没有业务逻辑的纯UI组件,如
-
业务组件(Business Components):
- 这些组件与业务逻辑相关,包含特定模块功能,如
UserProfile.vue
、ProductCard.vue
等。
- 这些组件与业务逻辑相关,包含特定模块功能,如
-
页面级组件(Page Components):
- 页面级别的组件用于构建整个页面,通常在
pages
目录下管理,并通过路由直接渲染。
- 页面级别的组件用于构建整个页面,通常在
4. 组件内结构规范
组件内代码顺序
-
组件内部代码顺序应保持一致,建议如下顺序:
name
:组件名称,方便调试和查错。props
:接收的外部属性。data
:组件内部的状态数据。computed
:计算属性,派生数据。methods
:组件的业务逻辑方法。watch
:监控属性变化。lifecycle hooks
:生命周期钩子函数。
-
示例:
<script>
export default {
name: 'UserProfile',
props: {
userId: {
type: String,
required: true
}
},
data() {
return {
userProfile: null
};
},
computed: {
formattedName() {
return this.userProfile ? `${this.userProfile.firstName} ${this.userProfile.lastName}` : '';
}
},
methods: {
async fetchUserProfile() {
// 业务逻辑
}
},
mounted() {
this.fetchUserProfile();
}
};
</script>
Props 规范
-
类型定义:在
props
中定义时,必须明确类型,使用type
,并添加required
字段来说明该prop
是否必需。 -
默认值:使用
default
字段提供默认值。 -
规范示例:
props: {
userId: {
type: String,
required: true
},
isActive: {
type: Boolean,
default: false
},
options: {
type: Array,
default: () => []
}
}
5. 组件通信
父子组件通信(Props & Emit)
-
Props:父组件通过
props
传递数据到子组件,确保父组件控制数据流。 -
Emit:子组件通过
$emit
通知父组件事件。 -
示例:
-
父组件传递
prop
s:
-
<UserProfile :userId="userId" @update="handleUpdate" />
子组件emit
事件:
this.$emit('update', updatedData);
非父子组件通信(EventBus 或 Vuex)
- EventBus:使用事件总线进行跨组件的通信,但建议在较大项目中使用Vuex来管理全局状态。
- Vuex:使用状态管理工具Vuex进行全局状态的管理和数据传递。
6. 组件样式规范
局部样式作用域
-
使用
<style scoped>
来确保组件样式局部化,避免样式污染。 -
示例:
<style scoped>
.user-profile {
font-size: 14px;
}
</style>
样式命名(BEM命名法)
-
推荐使用BEM(Block Element Modifier)命名法管理样式。
-
示例:
<template>
<div class="user-profile">
<div class="user-profile__header">Header</div>
<div class="user-profile__body">Body</div>
<div class="user-profile__footer user-profile__footer--active">Footer</div>
</div>
</template>
Block: user-profile
Element: user-profile__header
, user-profile__body
Modifier: user-profile__footer--active
7. 组件重用
公共组件
- 创建公共组件库:提取项目中复用率高的组件,形成独立的公共组件库,例如
Button.vue
、Modal.vue
等。 - 按需加载:通过动态加载或按需引入的方式减少组件加载时的性能开销。
复用方法与逻辑(Mixin)
-
Mixin:对于多个组件之间共享的逻辑,可以使用
mixin
,实现代码重用。 -
示例:
export const userMixin = {
data() {
return {
userData: {}
};
},
methods: {
fetchUserData() {
// 复用的逻辑
}
}
};
在组件中使用:
import { userMixin } from '@/mixins/userMixin';
export default {
mixins: [userMixin],
mounted() {
this.fetchUserData();
}
};
8. 组件性能优化
-
异步组件:对于非关键路径的组件,可以使用
Vue
的异步组件加载功能进行按需加载,减少初始包体积。
const AsyncComponent = () => import('./components/AsyncComponent.vue');
-
懒加载:图片等资源可以使用懒加载技术,减少页面的初始加载时间。
-
避免不必要的重渲染:使用
key
值优化组件更新,避免无意义的重绘。
9. 组件测试
-
单元测试: 对每个组件编写单元测试,确保其功能和界面表现正确。使用
Jest
或Mocha
进行测试。测试内容:组件的渲染、
props
传递、事件触发等。
import { shallowMount } from '@vue/test-utils';
import UserProfile from '@/components/UserProfile.vue';
test('should render user profile', () => {
const wrapper = shallowMount(UserProfile, {
propsData: { userId: '123' }
});
expect(wrapper.find('.user-profile').exists()).toBe(true);
});
通过严格遵循这些组件化规范,能够确保代码的模块化、可维护性和重用性,减少项目开发中的复杂性并提升代码质量。