大家好,我是大华。今天分享我在前端项目中怎么用设计模式解决实际问题的。都是简单实用的例子可以进行参考!
1. 单例模式:全局唯一的"管家"
场景:用户登录状态
用户登录后,整个网站都要知道这个状态。
typescript
// stores/user.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
// 用户信息
const userInfo = ref({
id: 0,
name: '',
email: '',
isLoggedIn: false
})
// 登录
const login = (name: string, email: string) => {
userInfo.value = {
id: Date.now(),
name,
email,
isLoggedIn: true
}
// 保存到本地
localStorage.setItem('user', JSON.stringify(userInfo.value))
}
// 退出
const logout = () => {
userInfo.value = {
id: 0,
name: '',
email: '',
isLoggedIn: false
}
localStorage.removeItem('user')
}
// 页面刷新时恢复状态
const init = () => {
const saved = localStorage.getItem('user')
if (saved) {
userInfo.value = JSON.parse(saved)
}
}
init()
return {
userInfo,
login,
logout
}
})
vue
<!-- 任意组件中使用 -->
<script setup lang="ts">
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// 登录
const handleLogin = () => {
userStore.login('张三', 'zhangsan@email.com')
}
// 退出
const handleLogout = () => {
userStore.logout()
}
</script>
更多使用场景:
- 用户登录状态
- 购物车
- 主题设置
- 全局配置
2. 工厂模式:动态创建组件
场景:不同类型的弹窗
网站有多种弹窗:提示框、确认框、表单框...
typescript
// components/Alert.vue
<template>
<div class="alert">
<h3>{{ title }}</h3>
<p>{{ message }}</p>
<button @click="onClose">确定</button>
</div>
</template>
<script setup lang="ts">
defineProps<{
title: string
message: string
onClose: () => void
}>()
</script>
typescript
// components/Confirm.vue
<template>
<div class="confirm">
<h3>{{ title }}</h3>
<p>{{ message }}</p>
<button @click="onCancel">取消</button>
<button @click="onConfirm">确定</button>
</div>
</template>
<script setup lang="ts">
defineProps<{
title: string
message: string
onConfirm: () => void
onCancel: () => void
}>()
</script>
typescript
// factories/modal-factory.ts
import { shallowRef } from 'vue'
import Alert from '@/components/Alert.vue'
import Confirm from '@/components/Confirm.vue'
// 弹窗类型
type ModalType = 'alert' | 'confirm'
// 创建弹窗
export function createModal(type: ModalType) {
const ModalComponent = shallowRef()
if (type === 'alert') {
ModalComponent.value = Alert
} else if (type === 'confirm') {
ModalComponent.value = Confirm
}
return {
ModalComponent
}
}
vue
<!-- 使用弹窗 -->
<script setup lang="ts">
import { createModal } from '@/factories/modal-factory'
const { ModalComponent } = createModal('alert')
const showAlert = () => {
// 显示提示框
}
</script>
更多使用场景:
- 不同类型的弹窗
- 动态表单
- 表格列渲染
- 消息通知
3. 观察者模式:组件间通信
场景:购物车数量同步
商品页加购,顶部购物车图标要显示数量。
typescript
// utils/event-bus.ts
// 事件中心
const eventBus = {
events: {}
}
// 发布消息
export function emit(event: string, data: any) {
if (eventBus.events[event]) {
eventBus.events[event].forEach(callback => callback(data))
}
}
// 订阅消息
export function on(event: string, callback: Function) {
if (!eventBus.events[event]) {
eventBus.events[event] = []
}
eventBus.events[event].push(callback)
}
vue
<!-- 商品详情页 -->
<script setup lang="ts">
import { on } from '@/utils/event-bus'
const addToCart = () => {
// 加购逻辑...
// 通知购物车更新
emit('cart-updated', { count: 5 })
}
</script>
vue
<!-- 头部导航 -->
<script setup lang="ts">
import { ref } from 'vue'
import { on } from '@/utils/event-bus'
const cartCount = ref(0)
// 监听购物车更新
on('cart-updated', (data) => {
cartCount.value = data.count
})
</script>
更多使用场景:
- 跨组件通信
- 状态同步
- 用户行为通知
- 数据更新
4. 策略模式:灵活的计算方式
实战场景:不同折扣计算
普通用户9折,VIP用户8折,SVIP用户7折。
typescript
// utils/discount.ts
// 折扣策略
const discountStrategies = {
// 普通用户 - 9折
normal: (price: number) => price * 0.9,
// VIP用户 - 8折
vip: (price: number) => price * 0.8,
// SVIP用户 - 7折
svip: (price: number) => price * 0.7
}
// 计算折扣后价格
export function calculatePrice(price: number, level: string) {
const strategy = discountStrategies[level]
if (strategy) {
return strategy(price)
}
return price // 默认不打折
}
vue
<!-- 商品页 -->
<script setup lang="ts">
import { calculatePrice } from '@/utils/discount'
const originalPrice = 100
const userLevel = 'vip'
// 计算最终价格
const finalPrice = calculatePrice(originalPrice, userLevel)
</script>
更多使用场景:
- 不同的计算方式
- 多种验证规则
- 排序/过滤
- 支付方式
5. 代理模式:统一处理请求
实战场景:API请求处理
每个接口都要加token,处理错误。
typescript
// utils/api.ts
// 创建API代理
export const api = new Proxy({}, {
get(target, prop) {
return async (data: any) => {
try {
// 显示loading
showLoading()
const response = await fetch(`/api/${prop}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// 自动加token
'Authorization': `Bearer ${getToken()}`
},
body: JSON.stringify(data)
})
const result = await response.json()
if (result.code !== 0) {
throw new Error(result.message)
}
return result.data
} catch (error) {
// 统一错误处理
handleError(error)
throw error
} finally {
// 隐藏loading
hideLoading()
}
}
}
})
// 获取token
function getToken() {
return localStorage.getItem('token') || ''
}
// 显示loading
function showLoading() {
console.log('loading...')
}
// 隐藏loading
function hideLoading() {
console.log('hide loading')
}
// 错误处理
function handleError(error: any) {
alert(error.message)
}
vue
<!-- 使用API -->
<script setup lang="ts">
import { api } from '@/utils/api'
// 获取用户信息
const getUser = async () => {
try {
const user = await api.getUser({ id: 123 })
console.log(user)
} catch (error) {
// 错误已经统一处理了
}
}
</script>
更多使用场景:
- 统一API处理
- 权限控制
- 数据缓存
- 日志记录
总结
设计模式很简单:
- 单例:全局唯一,比如用户状态
- 工厂:动态创建,比如不同弹窗
- 观察者:消息通知,比如状态同步
- 策略:多种方式,比如不同折扣
- 代理:统一处理,比如API请求
先解决问题,再想模式。代码简单最重要!
我是大华,专注分享Java、Vue前后端的实战笔记。关注我,少走弯路,一起进步!