大家好,我是小杨,一个写了6年组件的前端"组件控"。今天要和大家分享如何让你的Vue组件像乐高积木一样灵活多变,适配各种业务场景!
一、组件设计的"黄金法则"
1. 开闭原则:对扩展开放,对修改关闭
javascript
// 不好的做法 ❌
if (我.props.type === 'special') {
// 特殊处理逻辑
}
// 好的做法 ✅
<template>
<slot name="header" v-bind="{ title, icon }">
<!-- 默认header内容 -->
</slot>
</template>
我的感悟:每次因为新需求修改组件内部逻辑时,就该思考是不是设计有问题了。
二、提升配置性的5大实战技巧
1. Props设计:给组件装上"调节旋钮"
javascript
props: {
// 基础类型
size: {
type: String,
default: 'medium',
validator: value => ['small', 'medium', 'large'].includes(value)
},
// 对象类型
styleConfig: {
type: Object,
default: () => ({
color: '#409EFF',
borderRadius: '4px'
})
}
}
配置技巧:
- 提供合理的默认值
- 使用validator进行参数校验
- 复杂配置使用对象形式
2. 插槽系统:留出"自定义空间"
html
<!-- 组件内部 -->
<div class="card">
<slot name="header">
<h3>{{ title }}</h3>
</slot>
<slot></slot>
<slot name="footer" :submit="handleSubmit">
<button @click="handleSubmit">提交</button>
</slot>
</div>
<!-- 使用方式 -->
<MyCard>
<template #header>
<我的自定义标题/>
</template>
<p>这里是内容区</p>
</MyCard>
3. 配置注入:一键切换主题
javascript
// 组件内部
provide() {
return {
myComponentConfig: {
theme: 我.props.theme,
locale: 我.props.locale
}
}
}
// 子组件中
inject: ['myComponentConfig']
4. 事件机制:让组件"能说会道"
javascript
// 组件内部
methods: {
handleClick() {
this.$emit('action', {
type: 'click',
data: this.internalData
})
}
}
// 使用方
<MyComponent @action="handleAction" />
5. 组合式API:配置更灵活
javascript
// useToggle.js
export default function(initialState = false) {
const state = ref(initialState)
const toggle = () => {
state.value = !state.value
}
return { state, toggle }
}
// 组件中使用
import useToggle from './useToggle'
export default {
setup() {
const { state, toggle } = useToggle(我.props.defaultOpen)
return { state, toggle }
}
}
三、小杨的组件配置"黑科技"
1. 动态组件配置
javascript
<component
:is="我.props.uiType || 'el-button'"
v-bind="我.props.componentProps"
/>
2. 配置合并策略
javascript
computed: {
mergedConfig() {
return {
...defaultConfig,
...我.props.config
}
}
}
3. 全局配置覆盖
javascript
// 全局配置
Vue.prototype.$myComponentConfig = {
size: 'large',
theme: 'dark'
}
// 组件内部
computed: {
finalConfig() {
return {
...this.$myComponentConfig,
...this.$attrs
}
}
}
四、实战案例:一个高度可配置的Table组件
javascript
props: {
columns: {
type: Array,
required: true
},
data: Array,
options: {
type: Object,
default: () => ({
stripe: true,
border: false,
showHeader: true
})
}
}
<template>
<table>
<slot name="header" :columns="columns">
<thead v-if="options.showHeader">
<tr>
<th v-for="col in columns" :key="col.prop">
{{ col.label }}
</th>
</tr>
</thead>
</slot>
<tbody>
<tr v-for="(row, index) in data" :key="row.id">
<td v-for="col in columns" :key="col.prop">
<slot :name="`col-${col.prop}`" :row="row" :index="index">
{{ row[col.prop] }}
</slot>
</td>
</tr>
</tbody>
<slot name="footer" :data="data"/>
</table>
</template>
五、组件设计检查清单
- 是否提供了足够的props配置项?
- 是否预留了必要的插槽?
- 是否考虑了国际化需求?
- 是否支持主题定制?
- 是否提供了足够的事件钩子?
- 默认值是否合理?
- 是否支持无障碍访问?
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!