设计模式,说白了就是写代码的“套路”。用好了,你的代码就能更健壮,更易于维护。几乎所有应用都会遇到一些共性问题,设计模式就像一个宝库,提供了很多经过验证的解决方案。今天,我就来给大家分享 12 种 Vue 设计模式,每个模式都附带一个简单的例子,让你快速上手!这只是个开胃菜,想要深入学习,还需要花更多时间研究!
<script setup lang="ts"> import { reactive, toRefs, readonly } from 'vue'; import { themes } from './utils'; // 堆代码 duidaima.com // 1. 在模块作用域中创建全局状态,在每次使用此可组合函数时共享 const state = reactive({ darkMode: false, sidebarCollapsed: false, // 2. 此主题值对该可组合函数保持私有 theme: 'nord', }); export default () => { // 2. 仅暴露部分状态 // 使用 toRefs 允许我们共享单个值 const { darkMode, sidebarCollapsed } = toRefs(state); // 3. 修改我们的基础状态 const changeTheme = (newTheme) => { if (themes.includes(newTheme)) { // 仅在它是一个有效主题时更新 state.theme = newTheme; } }; return { // 2. 只返回部分状态 darkMode, sidebarCollapsed, // 2. 仅暴露状态的只读版本 theme: readonly(state.theme), // 3. 我们返回一个修改基础状态的方法 changeTheme, }; }; </script>二. 轻量级可组合函数
<script setup lang="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 }; } </script>三. 谦逊组件模式
<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>四. 提取条件逻辑
<!-- 之前 --> <template> <div v-if="condition"> <!-- 真实条件下的大量代码 --> </div> <div v-else> <!-- 假设条件下的大量代码 --> </div> </template> <!-- 之后 --> <template> <TrueConditionComponent v-if="condition" /> <FalseConditionComponent v-else /> </template>五. 提取可组合函数
<script setup lang="ts"> 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 }; } </script> <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>六. 列表组件模式
<!-- 之前:在父组件中直接使用 v-for --> <template> <div v-for="item in list" :key="item.id"> <!-- 每个项目的代码 --> </div> </template> <!-- 之后:将 v-for 抽象到子组件中 --> <template> <NewComponentList :list="list" /> </template>七. 保留对象模式
<!-- 使用整个对象 --> <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>八. 控制器组件
<!-- 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>九. 策略模式
<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>十. 隐藏组件模式
<!-- 重构之前 --> <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>十一. 内部交易模式
<!-- 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>十二. 长组件模式
<!-- 之前:一个冗长且复杂的组件 --> <template> <div> <!-- 大量 HTML 和逻辑 --> </div> </template> <!-- 之后:分解成更小的组件, 名称告诉你代码的作用。 --> <template> <ComponentPartOne /> <ComponentPartTwo /> </template>总结