面试问题记录
问题 1
请简单介绍一下你对 Vue 的理解,包括它的特点和优势。
回答:
Vue 是一款渐进式 JavaScript 框架,主要用于构建用户界面。它的核心库专注于视图层,并且易于与其他库或现有项目集成。
Vue 的特点:
- 渐进式框架:可以从简单的项目逐步扩展为复杂的单页应用(SPA)。
- 双向数据绑定:通过
v-model
实现数据和视图的实时同步。 - 组件化开发:将页面分解成可复用的组件,提高开发效率和可维护性。
- 虚拟 DOM:通过虚拟 DOM 提高性能,减少直接操作真实 DOM 的开销。
- 生态系统丰富:配套工具(如 Vue Router 和 Vuex)支持完整的应用开发。
- 直观易学:语法简单,适合初学者。
Vue 的优势:
- 简单易用:上手成本低,适合初学者快速学习。
- 性能优秀:虚拟 DOM 和高效的差异化更新机制使其性能优越。
- 社区支持:有活跃的社区,丰富的插件和第三方库。
- 灵活性强:可以与其他项目集成,也可以作为单页应用的全栈解决方案。
- 开发体验优异:提供开发者工具(Vue DevTools),便于调试和性能优化。
Vue 因其轻量、灵活、强大的特性,是目前前端开发中非常流行的框架之一。
问题 2
在 Vue 项目中,你通常如何组织和管理组件?请描述一下你的组件化开发思路。
回答:
在 Vue 项目中,组件化开发是核心思想,我通常遵循以下原则来组织和管理组件:
组件组织思路:
目录结构清晰:
src/components
目录用于存放全局通用组件。src/views
目录用于存放与路由对应的页面组件。- 将每个组件文件夹独立管理(包括组件逻辑、样式和测试文件)。
组件命名规范:
- 使用 PascalCase 命名法(如
UserCard.vue
)。 - 页面组件使用文件夹名加
index.vue
,例如HomePage/index.vue
。
- 使用 PascalCase 命名法(如
分离通用和特定组件:
- 通用组件(如按钮、弹窗等)封装到
components
目录。 - 特定功能组件归属于页面或模块内部(如
views/Home/FeatureList.vue
)。
- 通用组件(如按钮、弹窗等)封装到
组件复用:
- 将公共逻辑抽离到混入(Mixins)、组合式 API(Composition API)或自定义钩子中。
- 创建可配置的基础组件,减少重复开发。
组件开发原则:
- 单一职责:每个组件只负责一项功能,便于测试和维护。
- 父子通信清晰:通过
props
传递数据,使用事件 ($emit
) 通知父组件。 状态管理:
- 小型状态通过组件自身管理。
- 跨组件共享状态时使用 Vuex、Pinia 或 Context API。
- 样式隔离:使用 Scoped CSS 或 CSS Modules,确保样式不冲突。
性能优化:
- 按需加载组件,使用
defineAsyncComponent
实现懒加载。 - 合理使用
v-once
和v-for
的key
提高渲染性能。
- 按需加载组件,使用
通过清晰的结构设计和规范的开发流程,可以确保组件的高内聚、低耦合,便于维护和扩展。
问题 3
Vue 的生命周期钩子有哪些?它们在什么阶段被调用?
回答:
Vue 的生命周期钩子是 Vue 实例在不同阶段触发的函数。以下是 Vue 2 和 Vue 3 中的生命周期钩子及其调用阶段:
Vue 2 的生命周期钩子:
创建阶段:
beforeCreate
:实例初始化之后,数据观测和事件尚未设置。created
:实例创建完成,数据观测和事件已设置,但 DOM 未生成。
挂载阶段:
beforeMount
:挂载之前调用,模板已编译成渲染函数。mounted
:挂载完成,真实 DOM 已生成。
更新阶段:
beforeUpdate
:数据更新后,视图更新前调用。updated
:视图更新后调用。
销毁阶段:
beforeDestroy
:实例销毁前调用,仍可访问实例。destroyed
:实例销毁后调用,所有事件监听和子实例均被移除。
Keep-Alive 特有生命周期钩子:
activated
:组件被激活时调用。deactivated
:组件被停用时调用。
Vue 3 的生命周期钩子:
Vue 3 使用 Composition API 的钩子函数,与 Options API 的生命周期名称略有不同:
创建阶段:
onBeforeMount
:等价于 Vue 2 的beforeMount
。onMounted
:等价于 Vue 2 的mounted
。
更新阶段:
onBeforeUpdate
:等价于 Vue 2 的beforeUpdate
。onUpdated
:等价于 Vue 2 的updated
。
销毁阶段:
onBeforeUnmount
:等价于 Vue 2 的beforeDestroy
。onUnmounted
:等价于 Vue 2 的destroyed
。
新增钩子:
onRenderTracked
:响应式依赖被收集时触发。onRenderTriggered
:响应式依赖更新时触发。onActivated
:等价于 Vue 2 的activated
。onDeactivated
:等价于 Vue 2 的deactivated
。
总结:
- Vue 2 和 Vue 3 的生命周期整体一致,但 Vue 3 在 Composition API 中提供了更灵活的钩子函数。
- 使用生命周期钩子可以在不同阶段执行相应逻辑,如数据初始化、事件绑定、资源释放等。
问题 4
谈谈你对 Vue 的响应式系统的理解,以及它是如何实现数据的双向绑定的。
回答:
Vue 的响应式系统是其核心特性之一,它通过数据劫持和依赖追踪来实现视图和数据的实时联动。以下是其工作原理和实现方式:
Vue 2 的响应式原理:
数据劫持:Vue 使用
Object.defineProperty
为对象的每个属性定义 getter 和 setter。通过拦截属性的访问和修改,实现数据的响应式。- getter:在读取数据时,收集依赖(Watcher)。
- setter:在修改数据时,通知依赖进行更新。
依赖收集:
- 每个响应式属性对应一个 Dep 对象,用于存储依赖该属性的所有 Watcher。
- 当属性被访问时,将当前的 Watcher 添加到 Dep 中。
通知更新:
- 属性值发生变化时,触发 setter,Dep 通知所有 Watcher 执行更新逻辑。
模板更新:
- Watcher 负责更新 DOM。通过虚拟 DOM 和 Diff 算法,Vue 只更新必要的部分,提升性能。
Vue 3 的响应式原理:
Vue 3 使用 Proxy 替代了 Vue 2 的 Object.defineProperty
实现响应式,解决了 Vue 2 中的一些局限性:
Proxy 的优势:
- 可以监听动态属性的添加和删除。
- 支持对数组、Map、Set 等复杂数据类型的监控。
Reactive 和 Ref:
reactive
:将对象包装为响应式对象。ref
:包装基础数据类型或单个值为响应式。
依赖追踪和触发更新:
- 内部使用
effect
函数收集依赖,并在数据变化时触发对应的更新逻辑。
- 内部使用
数据双向绑定:
v-model
实现:- Vue 2 中,
v-model
是语法糖,相当于绑定value
和监听input
事件。 - Vue 3 中,
v-model
支持绑定多个值,通过v-model:propName
实现。
- Vue 2 中,
事件驱动:
- 数据变化时,触发 setter,通知依赖更新视图。
- 用户输入时,通过事件更新数据,完成双向绑定。
总结:
Vue 的响应式系统通过劫持数据访问和修改,实现视图与数据的同步更新。Vue 3 的 Proxy 提升了性能和灵活性,使响应式系统更加高效、易用。
问题 5
在 Vue 中,如何进行路由管理?你是否使用过 Vue Router?
回答:
在 Vue 中,路由管理通常使用 Vue Router 进行。Vue Router 是 Vue.js 的官方路由管理器,提供了在单页应用中实现路由功能的能力。以下是使用 Vue Router 进行路由管理的基本步骤和概念:
Vue Router 的基本使用:
安装 Vue Router:
使用 npm 或 yarn 安装 Vue Router:
npm install vue-router
创建路由配置:
定义路由规则,通常在一个单独的文件中(如
router/index.js
):import { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import About from '../views/About.vue'; const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: About } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;
在 Vue 应用中使用路由:
在主应用文件(如
main.js
)中引入并使用路由:import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; createApp(App) .use(router) .mount('#app');
在组件中使用路由:
使用
<router-link>
组件进行导航:<template> <nav> <router-link to="/">Home</router-link> <router-link to="/about">About</router-link> </nav> </template>
使用
<router-view>
组件显示匹配的组件:<template> <router-view></router-view> </template>
路由管理的功能:
- 动态路由:支持动态参数,如
/user/:id
。 - 嵌套路由:支持在父路由中嵌套子路由。
- 路由守卫:可以在路由进入或离开时进行权限验证或数据预加载。
- 懒加载:通过动态导入实现路由组件的懒加载,提升性能。
总结:
我在多个项目中使用过 Vue Router,熟悉其基本用法和高级特性。Vue Router 提供了强大的路由管理功能,使得在单页应用中实现复杂的导航和状态管理变得简单高效。
问题 6
对于 Vue 的状态管理,你有什么经验?是否使用过 Vuex 或其他类似的状态管理库?
回答:
在 Vue 应用中,状态管理是非常重要的,尤其是在大型应用中。Vuex 是 Vue.js 的官方状态管理库,提供了集中式存储和管理应用的所有组件状态。以下是我在使用 Vuex 及其他状态管理库方面的经验:
Vuex 的基本使用:
安装 Vuex:
使用 npm 或 yarn 安装 Vuex:
npm install vuex
创建 Vuex Store:
在一个单独的文件中(如
store/index.js
)定义状态、变更、动作和获取器:import { createStore } from 'vuex'; const store = createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } }, actions: { increment({ commit }) { commit('increment'); }, decrement({ commit }) { commit('decrement'); } }, getters: { getCount(state) { return state.count; } } }); export default store;
在 Vue 应用中使用 Vuex:
在主应用文件(如
main.js
)中引入并使用 Vuex:import { createApp } from 'vue'; import App from './App.vue'; import store from './store'; createApp(App) .use(store) .mount('#app');
在组件中访问状态:
使用
mapState
和mapActions
辅助函数来简化状态和动作的访问:<template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> <button @click="decrement">Decrement</button> </div> </template> <script> import { mapState, mapActions } from 'vuex'; export default { computed: { ...mapState(['count']) }, methods: { ...mapActions(['increment', 'decrement']) } }; </script>
其他状态管理库:
除了 Vuex,我还使用过其他一些状态管理库,如:
Pinia:
- Pinia 是 Vue 3 的新一代状态管理库,具有更简单的 API 和更好的 TypeScript 支持。
- 它的使用方式与 Vuex 类似,但更加轻量和灵活。
Vue Composition API:
- 在 Vue 3 中,可以使用 Composition API 来管理状态,利用
reactive
和ref
创建响应式状态。 - 适合小型应用或特定功能模块的状态管理。
- 在 Vue 3 中,可以使用 Composition API 来管理状态,利用
总结:
我在多个项目中使用过 Vuex,熟悉其核心概念和使用方式。Vuex 提供了强大的状态管理功能,适合大型应用的需求。同时,我也在探索 Pinia 和 Composition API 的使用,以便在不同场景下选择合适的状态管理方案。
问题 7
请你说说 Pinia 和 Vuex 的不同。
回答:
Pinia 和 Vuex 都是用于 Vue 应用的状态管理库,但它们在设计理念、API 结构和使用体验上有一些显著的不同。以下是它们的主要区别:
1. 设计理念
Vuex:
- Vuex 是 Vue.js 的官方状态管理库,旨在为大型应用提供集中式的状态管理。
- 采用了较为复杂的结构,强调状态、变更、动作和获取器的分离。
Pinia:
- Pinia 是 Vue 3 的新一代状态管理库,旨在提供更简单、直观的 API。
- 设计上更加轻量,适合现代 Vue 应用的需求。
2. API 结构
Vuex:
- 使用
state
、mutations
、actions
和getters
来管理状态。 - 需要通过
commit
来触发变更,使用dispatch
来调用动作。
- 使用
Pinia:
- 使用
defineStore
来定义状态存储,直接在存储中定义状态、变更和动作。 - 支持直接在组件中调用存储的状态和动作,简化了 API 的使用。
- 使用
3. TypeScript 支持
Vuex:
- Vuex 对 TypeScript 的支持相对较弱,使用时需要额外的类型定义。
Pinia:
- Pinia 从一开始就设计为支持 TypeScript,提供了更好的类型推导和类型安全。
4. 响应式系统
Vuex:
- Vuex 使用 Vue 2 的响应式系统,依赖于
Object.defineProperty
。
- Vuex 使用 Vue 2 的响应式系统,依赖于
Pinia:
- Pinia 使用 Vue 3 的响应式系统,基于 Proxy,能够更好地处理动态属性和复杂数据结构。
5. 代码组织
Vuex:
- 通常需要将状态、变更、动作和获取器分开组织,可能导致文件结构较为复杂。
Pinia:
- 通过
defineStore
将状态、变更和动作放在同一个地方,代码组织更加简洁明了。
- 通过
总结:
Pinia 和 Vuex 各有优缺点,选择使用哪个库取决于项目的需求和开发者的偏好。对于新项目,尤其是使用 Vue 3 的项目,Pinia 提供了更现代化的状态管理体验,而对于已有的 Vue 2 项目,Vuex 仍然是一个可靠的选择。
问题 8
在 Vue 项目中,你如何处理异步请求?通常使用什么库或方法?
回答:
在 Vue 3 项目中,处理异步请求通常使用 Axios 或 Fetch API,并结合组合式 API 和 TypeScript。以下是使用这两种方法的示例:
1. 使用 Axios
安装 Axios:
npm install axios
基本用法:
<template> <div> <p>User Data: {{ userData }}</p> <p v-if="error">Error: {{ error }}</p> <button @click="fetchUserData">Fetch User Data</button> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; import axios from 'axios'; export default defineComponent({ setup() { const userData = ref<string | null>(null); const error = ref<string | null>(null); const fetchUserData = async () => { try { const response = await axios.get('https://api.example.com/user'); userData.value = JSON.stringify(response.data); error.value = null; } catch (err) { error.value = (err as Error).message; } }; return { userData, error, fetchUserData }; } }); </script>
2. 使用 Fetch API
基本用法:
<template> <div> <p>User Data: {{ userData }}</p> <p v-if="error">Error: {{ error }}</p> <button @click="fetchUserData">Fetch User Data</button> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; export default defineComponent({ setup() { const userData = ref<string | null>(null); const error = ref<string | null>(null); const fetchUserData = async () => { try { const response = await fetch('https://api.example.com/user'); if (!response.ok) { throw new Error('Network response was not ok'); } userData.value = JSON.stringify(await response.json()); error.value = null; } catch (err) { error.value = (err as Error).message; } }; return { userData, error, fetchUserData }; } }); </script>
总结:
在 Vue 3 项目中,处理异步请求通常使用 Axios 或 Fetch API。结合组合式 API 和 TypeScript,可以提高代码的可读性和可维护性,同时确保类型安全。
问题 9
请分享一些你在 Vue 项目中进行性能优化的经验和技巧。
回答:
在 Vue 项目中进行性能优化的经验和技巧包括:
使用虚拟 DOM:
- 利用 Vue 的虚拟 DOM 特性,减少直接操作真实 DOM 的次数,提高渲染性能。
懒加载组件:
- 使用动态导入(
import()
)实现路由组件的懒加载,减少初始加载时间。
- 使用动态导入(
合理使用
v-if
和v-show
:- 使用
v-if
进行条件渲染时,避免频繁切换,适合不常变化的内容;使用v-show
适合频繁切换的内容。
- 使用
使用
key
属性:- 在
v-for
循环中使用唯一的key
属性,帮助 Vue 更高效地识别和更新 DOM 元素。
- 在
避免不必要的计算:
- 使用计算属性(computed)而非方法(methods)来缓存计算结果,避免重复计算。
使用
watch
监听特定数据:- 只监听需要的特定数据变化,避免不必要的更新。
优化图片和资源:
- 使用合适的图片格式和大小,利用懒加载技术加载图片,减少初始加载时间。
使用服务端渲染(SSR):
- 对于大型应用,考虑使用 Nuxt.js 进行服务端渲染,提高首屏加载速度和 SEO 性能。
减少组件的复杂性:
- 将大型组件拆分为小型组件,降低每个组件的复杂度,提高可维护性和性能。
使用性能分析工具:
- 利用 Vue DevTools 和浏览器的性能分析工具,监测和分析应用的性能瓶颈。
总结:
通过以上技巧,可以有效提升 Vue 项目的性能,确保应用在用户体验和响应速度上的优化。
问题 10
对于 Vue 的单文件组件(.vue 文件),你对它的结构和用法有什么了解?
回答:
Vue 的单文件组件(.vue 文件)是 Vue 应用中最常用的组件结构,具有以下特点:
结构:
单文件组件通常由三部分组成:
<template>
、<script>
和<style>
。<template>
:定义组件的 HTML 结构,支持 Vue 的模板语法。<script>
:包含组件的逻辑和数据,通常使用 JavaScript 或 TypeScript 编写。<style>
:定义组件的样式,可以使用普通 CSS、预处理器(如 SCSS)或 CSS Modules。
作用域样式:
- 可以使用
scoped
属性来限制样式的作用范围,确保样式只应用于当前组件,避免样式冲突。
- 可以使用
组件复用:
- 单文件组件可以被其他组件导入和使用,支持组件的复用和组合。
生命周期钩子:
- 在
<script>
部分可以使用 Vue 的生命周期钩子(如mounted
、created
等)来管理组件的生命周期。
- 在
组合式 API:
- 在 Vue 3 中,可以使用组合式 API(如
setup
函数)来组织组件的逻辑,提高代码的可读性和可维护性。
- 在 Vue 3 中,可以使用组合式 API(如
模块化:
- 单文件组件使得组件的结构更加模块化,便于管理和维护。
总结:
单文件组件是 Vue 应用的核心构建块,通过清晰的结构和模块化的设计,提升了开发效率和可维护性。
问题 11
如果要在 Vue 项目中集成第三方库或插件,你通常会采取哪些步骤?
回答:
在 Vue 项目中集成第三方库或插件通常包括以下步骤:
安装库或插件:
使用 npm 或 yarn 安装所需的第三方库。例如:
npm install library-name
引入库或插件:
在需要使用的组件或全局配置中引入该库。例如,在
main.js
中全局引入:import library from 'library-name';
配置插件:
根据库的文档进行必要的配置,可能需要在 Vue 实例中使用
.use()
方法进行注册:createApp(App).use(library).mount('#app');
使用库的功能:
- 在组件中使用该库提供的功能或组件,按照库的文档进行调用。
处理样式:
如果库需要样式支持,确保在项目中引入相应的 CSS 文件,通常在
main.js
或组件中引入:import 'library-name/dist/library.css';
查看文档:
- 参考第三方库的官方文档,了解其 API、用法和配置选项,以便正确集成和使用。
测试和调试:
- 在集成后进行测试,确保库的功能正常工作,并根据需要进行调试。
总结:
通过以上步骤,可以有效地在 Vue 项目中集成第三方库或插件,扩展应用的功能和特性。
问题 12
在团队合作中,你是如何与其他成员协作开发 Vue 项目的?
回答:
在团队合作中,我通常采取以下方法与其他成员协作开发 Vue 项目:
使用版本控制系统:
- 使用 Git 进行版本控制,确保代码的版本管理和协作开发。通过分支管理(如 Git Flow)来处理不同的功能和修复。
明确分工:
- 在项目开始时,与团队成员明确分工,确定每个人负责的模块或功能,避免重复工作。
代码规范:
- 制定统一的代码规范和风格指南,确保代码的一致性和可读性。可以使用 ESLint 和 Prettier 等工具进行代码检查和格式化。
定期沟通:
- 定期召开团队会议,讨论项目进展、遇到的问题和解决方案,确保团队成员之间的信息共享。
使用协作工具:
- 使用项目管理工具(如 禅道)和协作工具(如 企业微信TAPD)进行任务分配和进度跟踪。
代码审查:
- 在合并代码之前进行代码审查(Code Review),确保代码质量和功能的正确性,促进知识共享。
文档编写:
- 编写项目文档,包括开发文档、API 文档和使用说明,帮助团队成员快速上手和理解项目。
持续集成和部署:
- 使用 CI/CD 工具(如 Jenkins、GitLab CI/CD)实现自动化测试和部署,提高开发效率和代码质量。
灵活应变:
- 在开发过程中保持灵活性,及时调整计划和任务分配,以应对项目需求的变化。
总结:
通过以上方法,可以有效地与团队成员协作开发 Vue 项目,提高开发效率和项目质量。
问题 13
请描述一次你在 Vue 项目中遇到的挑战,并说明你是如何解决它的。
回答:
在一个 Vue 项目中,我曾遇到过性能瓶颈的问题,具体表现为页面加载速度慢和响应不及时,尤其是在数据量较大的情况下。
挑战描述:
项目中有一个数据展示页面,需要从后端获取大量数据并进行渲染。随着数据量的增加,页面的渲染速度显著下降,用户体验受到影响。
解决方案:
数据分页:
- 我们决定对数据进行分页处理,而不是一次性加载所有数据。通过后端 API 支持分页,前端只请求当前页的数据,减少了初始加载的数据量。
懒加载和虚拟滚动:
- 实现了懒加载和虚拟滚动技术,只有在用户滚动到页面底部时才加载更多数据,进一步减少了初始渲染的负担。
使用计算属性:
- 将一些复杂的计算逻辑移到计算属性中,避免在模板中直接进行复杂计算,提升了渲染性能。
优化组件渲染:
- 对于频繁更新的组件,使用
v-once
和v-if
来控制渲染,确保只有必要的部分被更新。
- 对于频繁更新的组件,使用
性能监测:
- 使用 Vue DevTools 和浏览器的性能分析工具,监测组件的渲染时间和性能瓶颈,针对性地进行优化。
结果:
通过以上措施,页面的加载速度和响应时间得到了显著改善,用户体验大幅提升。最终,团队对性能优化的成果感到满意,并将这些优化策略应用到其他页面中。
总结:
在 Vue 项目中遇到性能瓶颈时,通过数据分页、懒加载、虚拟滚动和组件优化等方法,有效解决了问题,提升了应用的整体性能。
问题 14
请说说 Vue 项目中一般把数据请求这个操作放在哪个位置。
回答:
在 Vue 项目中,数据请求通常放在以下几个位置,具体取决于项目的结构和需求:
mounted
钩子:- 在组件的
mounted
生命周期钩子中进行数据请求是最常见的做法。此时组件已经挂载到 DOM 中,可以安全地进行数据请求。 - 适用于组件独立的数据请求,确保在组件加载完成后立即获取所需的数据。例如,用户详情页面在加载时请求用户信息。
- 在组件的
setup
函数(其实是onMounted钩子):- 在 Vue 3 中,使用组合式 API 时,可以在
setup
函数中进行数据请求。这种方式使得逻辑更加集中,便于管理和复用。 - 适用于使用组合式 API 的组件,能够在组件创建时就初始化数据,保持代码的清晰性和可维护性。
- 在 Vue 3 中,使用组合式 API 时,可以在
Vuex/Pinia:
- 对于需要在多个组件中共享的数据,通常将数据请求放在 Vuex 或 Pinia 的
actions
中。通过集中管理状态,可以实现数据的共享和统一管理。 - 适用于大型应用或需要跨组件共享数据的场景,例如在用户登录后,多个组件需要访问用户信息。
- 对于需要在多个组件中共享的数据,通常将数据请求放在 Vuex 或 Pinia 的
路由守卫:
- 在路由守卫中进行数据请求,适用于需要在路由切换时获取数据的场景。例如,在进入某个路由之前请求数据并存储在 Vuex 或 Pinia 中。
- 适用于需要在路由切换时预加载数据的情况,如在访问某个详情页之前先加载相关数据。
服务层:
- 创建一个服务层(如 API 模块)来封装所有的数据请求逻辑,组件只需调用服务层的方法。这种方式有助于保持组件的简洁性和可维护性。
- 适用于大型项目,便于管理和维护 API 请求,确保请求逻辑与组件逻辑分离,提高代码的可重用性。
总结:
在 Vue 项目中,数据请求的具体位置取决于项目的需求和结构。常见的位置包括组件的 mounted
钩子、组合式 API 的 setup
函数、Vuex/Pinia 的 actions
、路由守卫和服务层。选择合适的位置可以提高代码的可读性和可维护性。
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。