对于苏州网站建设来说,设计模式曾经是个谜,在看招聘说明时经常能看到它,比如下面这两张图,就是随便翻某聘时看到的。但好长一段时间,苏州网站建设都没太理解啥是设计模式,只觉得它挺高大上的。


后来听一位大咖介绍设计模式,我觉得他讲得挺好。他说,设计模式其实就是套路,你写代码写多了,发现有好多情况可以用类似的代码来解决,经过不断提炼和优化,大家见了纷纷学之,这样的代码架构就成了套路,也就是所谓的设计模式。
好的设计模式能让你的代码质量更高、更简洁,毕竟是经过大家千锤百炼之后得到公认的。这也就是为什么好多企业在招聘时需要你熟悉设计模式。
只不过,虽然不少图书或教程都介绍过JS或TS的设计模式,但有关Vue开发设计模式的内容却很少。但这不代表Vue就没有设计模式,恰恰相反,Vue还有不少个性化的设计模式。
虽然现在大家动不动就说前端已死,但搞前端开发的同学们还是得靠它吃饭啊,尤其是Vue,作为国内前端开发的主流框架,更是前端必备的技能。为了帮大家捧好这个饭碗,今天苏州网站建设就给大家整理了一篇文章,粗浅地介绍一下Vue的设计模式,共有12种,并附上了示例代码,展示这些设计模式的工作原理,供大家参考和学习。
这篇文章是苏州网站建设为前端(其实应该是全栈)同学推出的一篇长文,也是我想推出的前端学习系列的第一篇文章,欢迎大家多留言,提出建议。
再多说一句,苏州网站建设非常认真地对待每一篇文章,尽力给大家提供更好的阅读体验和更实用的知识,希望能和大家一起在开发学习的道路上共同进步。
1. 数据存储模式
解决状态管理最简单的方法是使用组合式函数创建共享的数据存储。
这种模式分为以下几种情况。
•全局状态单例
•导出部分或全部状态
•访问与修改状态的方法
示例如下。
import { reactive, toRefs, readonly } from "vue";
import { themes } from "./utils";
// 在模块作用域中创建全局状态,每次使用组合式函数时都会共享
const state = reactive({
darkMode: false,
sidebarCollapsed: false,
// theme 的值在组合式函数中为私有
theme: "nord",
});
export default () => {
// 只暴露部分状态
// 使用 toRefs 分享单个值
const { darkMode, sidebarCollapsed } = toRefs(state);
// 修改底层状态
const changeTheme = (newTheme) => {
if (themes.includes(newTheme)) {
// 仅在存在该主题时才更新
state.theme = newTheme;
}
};
return {
// 仅返回部分状态
darkMode,
sidebarCollapsed,
// 仅暴露状态的只读版本
theme: readonly(state.theme),
// 返回修改底层状态的方法
changeTheme,
};
};2. 轻量组合式函数模式
轻量组合式函数引入了额外的抽象层,把核心业务逻辑与响应式管理分离开来。这种模式使用 JS 或 TS 函数处理业务逻辑,然后在其上添加轻量的响应处理层。
import { ref, watch } from "vue";
import { convertToFahrenheit } from "./temperatureConversion";
export function useTemperatureConverter(celsiusRef: Ref<number>) {
const fahrenheit = ref(0);
watch(celsiusRef, (newCelsius) => {
// 业务逻辑包含在这个函数中
fahrenheit.value = convertToFahrenheit(newCelsius);
});
return { fahrenheit };
}3. 谦卑组件模式
所谓谦卑(humble),在这里可以理解为组件要谦逊,一个组件只专注实现一个功能;别逞能,不要在一个组件中实现过多的功能,这样才能让组件的复用、测试与维护更容易。
这种模式要求组件专注于页面呈现与用户输入,不要处理业务逻辑。依据该模式设计的组件代码更易懂,预测数据流也更加容易。
<template>
<div class="max-w-sm rounded overflow-hidden shadow-lg">
<img class="w-full" :src="userData.image" alt="User Image" />
<div class="px-6 py-4">
<div class="font-bold text-xl mb-2">
{{ userData.name }}
</div>
<p class="text-gray-700 text-base">
{{ userData.bio }}
</p>
</div>
<div class="px-6 pt-4 pb-2">
<button
@click="emitEditProfile"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Edit Profile
</button>
</div>
</div>
</template>
<script setup>
defineProps({
userData: Object,
});
const emitEditProfile = () => {
emit("edit-profile");
};
</script>4. 提取条件分支模式
为了简化多条件分支的模板,可以把多个分支的内容抽取成独立的组件。这种模式让代码更易读、更好维护。
你读到这里可能会觉得怎么翻来覆去都是这句话?其实设计模式的主要目的就是让你的代码架构更清晰、更简洁、更好懂、更好维护,所以就只能这么说了,大家主要看代码啊,这些代码表述得还是挺清楚的,别只看文字,好好看代码。
<!--提取之前 --> <template> <div v-if="condition"> <!-- 条件为真时的代码 --> </div> <div v-else> <!-- 条件为假时的代码 --> </div> </template> <!-- 提取之后 --> <template> <TrueConditionComponent v-if="condition" /> <FalseConditionComponent v-else /> </template>
5. 提取组合式函数模式
把处理业务逻辑的代码提取为组合式函数,即便只使用一次的逻辑代码也应该提取出来。
组合式函数可以让组件的代码更简单、更容易理解和维护。在组合式函数中添加方法与状态也更简单,例如撤销与重做等功能。这种模式有利于分离UI与业务逻辑。
import { ref, watch } from "vue";
export function useExampleLogic(initialValue: number) {
const count = ref(initialValue);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`);
});
return { count, increment, decrement };
}<template>
<div class="flex flex-col items-center justify-center">
<button @click="decrement" class="bg-blue-500 text-white p-2 rounded">
Decrement
</button>
<p class="text-lg my-4">Count: {{ count }}</p>
<button @click="increment" class="bg-green-500 text-white p-2 rounded">
Increment
</button>
</div>
</template>
<script setup lang="ts">
import { useExampleLogic } from "./useExampleLogic";
const { count, increment, decrement } = useExampleLogic(0);
</script>6. 列表组件模式
列表组件的代码有时会导致混乱,让模板难以管理,这时你可以把v-for循环中涉及的代码提取到子组件里。
<!-- 提取之前:直接在父组件中使用 v-for --> <template> <div v-for="item in list" :key="item.id"> <!-- 这里是一堆针对 item 的代码 --> </div> </template> <!-- 把 v-for 相关的代码提取到子组件中 --> <template> <NewComponentList :list="list" /> </template>
7. 保留对象模式
要想简化组件代码,可以把整个对象传递给组件,不要把对象的内容分别传递给组件的每个props。然而,这种模式可能会让组件过于依赖对象的结构。因此,这种设计模式并不适用于通用组件。
<!-- 把整个对象传递给组件 -->
<template>
<CustomerDisplay :customer="activeCustomer" />
</template>
<!-- CustomerDisplay.vue -->
<template>
<div>
<p>Name: {{ customer.name }}</p>
<p>Age: {{ customer.age }}</p>
<p>Address: {{ customer.address }}</p>
</div>
</template>8. 控制器组件模式
控制器组件桥接了UI(谦卑组件)与业务逻辑(组合式函数),可以集中管理状态与交互操作,协调应用的整体行为。鉴于控制器组件集中管理状态的这种特性,在单元测试与集成测试时可以不用关心UI的实现细节,让业务逻辑测试更简单。
<!-- TaskController.vue -->
<script setup>
import useTasks from "./composables/useTasks";
// 包含业务逻辑的组合式函数
const { tasks, addTask, removeTask } = useTasks();
</script>
<template>
<!-- 实现 UI 的谦卑组件 -->
<TaskInput @add-task="addTask" />
<TaskList :tasks="tasks" @remove-task="removeTask" />
</template>9. 策略模式
策略模式能根据运行时的条件动态切换组件,使代码更易读、更灵活。根据用户权限动态切换菜单组件的显示,就是策略模式的典型应用场景。
<template>
<component :is="currentComponent" />
</template>
<script setup>
import { computed } from "vue";
import ComponentOne from "./ComponentOne.vue";
import ComponentTwo from "./ComponentTwo.vue";
import ComponentThree from "./ComponentThree.vue";
const props = defineProps({
conditionType: String,
});
const currentComponent = computed(() => {
switch (props.conditionType) {
case "one":
return ComponentOne;
case "two":
return ComponentTwo;
case "three":
return ComponentThree;
default:
return DefaultComponent;
}
});
</script>10. 隐式组件模式
隐式组件模式的思路是把复杂的大组件分割为多个更小、更专注的组件(有点类似谦卑模式)。如果不同性质的代码可以独立使用,则可以进行组件分割。
<!-- 重构前 --> <template> <!-- 这里可以分割为图表组件 --> <DataDisplay :chart-data="data" :chart-options="chartOptions" /> <!-- 这里可以分割为表格组件 --> <DataDisplay :table-data="data" :table-settings="tableSettings" /> </template> <!-- 重构后 --> <template> <Chart :data="data" :options="chartOptions" /> <table :data="data" :settings="tableSettings" /> </template>
11. 内幕交易模式
内幕交易模式解决的是Vue中父子组件过度耦合的问题,这种模式通过在父组件中内联子组件进行简化,有利于形成连贯且一致的组件架构。
<!-- ParentComponent.vue -->
<template>
<div>
<!-- 子组件使用的都是来自父组件的数据,它存在的目的是什么? -->
<ChildComponent
:user-name="userName"
:email-address="emailAddress"
:phone-number="phoneNumber"
@user-update="(val) => $emit('user-update', val)"
@email-update="(val) => $emit('email-update', val)"
@phone-update="(val) => $emit('phone-update', val)"
/>
</div>
</template>
<script setup>
defineProps({
userName: String,
emailAddress: String,
phoneNumber: String,
});
defineEmits(["user-update", "email-update", "phone-update"]);
</script>12. 长组件
什么样的组件是长组件?简单说,让人难以理解的组件就是长组件。
长组件模式的原则是把组件拆分为多个命名清晰的小组件,可以提升代码的整体质量,易于理解。
<!-- 之前:又长又复杂的组件 --> <template> <div> <!-- 这里是一堆 HTML 代码和业务逻辑 --> </div> </template> <!-- 之后:分解为多个小组件,通过组件名就可以了解该组件的功能 --> <template> <ComponentPartOne /> <ComponentPartTwo /> </template>
希望这篇文章能让大家初步了解Vue的设计模式。这12种模式都是Vue前端开发时常用的,当然,如果你使用 React 或 Vanilla JS,也可以参考。










