说一下Vue的生命周期
Vue 的生命周期指的是一个 Vue 实例从创建到销毁的完整过程,大致可以分为创建 → 挂载 → 更新 → 销毁四个阶段。
创建阶段
beforeCreate:实例刚创建,此时数据响应式、computed、watch 等都还没初始化,基本拿不到 data。
created:实例创建完成,data、methods、computed、watch 都已经可用,但DOM还没有生成。一般在这里发送请求(ajax)或初始化数据。
挂载阶段
beforeMount:模板已经编译成 render 函数,但还没真正渲染到页面。
mounted:DOM已经挂载完成,可以访问 $el,也可以进行DOM 操作。常用于操作DOM、初始化第三方库。
更新阶段
当响应式数据变化时触发:
beforeUpdate:数据变了,但页面还没更新。
updated:DOM 已经更新完成。一般不建议在这里再次修改数据,否则可能造成无限更新。
第四阶段:销毁阶段
beforeDestroy:实例销毁前,组件仍可使用。常用于清除定时器、解绑事件、取消请求。
destroyed:组件完全销毁,事件监听和子组件全部移除。
created和mounted的区别
它们最大的区别在于 DOM 是否已经生成。
created:在实例创建完成后调用,数据已经完成响应式初始化,data、methods、computed、watch 都可以使用,DOM 还没有挂载,访问不到 $el
mounted:在组件模板已经渲染并挂载到真实 DOM 后调用,可以访问 $el,可以操作真实 DOM
keep-alive 中的生命周期哪些
keep-alive 是Vue的内置组件,用于缓存组件实例,避免组件在切换时被重复创建和销毁,从而提升性能并保留组件状态。当组件被 keep-alive 包裹后,会新增两个生命周期:
activated:组件从缓存中重新显示时触发,相当于组件被"重新进入页面"常用于:重新发送请求,刷新页面数据,恢复定时器
deactivated:组件被切换离开,但没有销毁时触发,组件进入缓存,常用于:清除定时器,暂停监听或动画
Vue 组件通信
1.父子组件通信
props / $emit
父 → 子:通过props传递数据
子 → 父:通过$emit触发事件通知父组件修改数据
这是 Vue 提倡的单向数据流。使用场景:绝大多数业务开发。
ref / $refs:父组件通过ref获取子组件实例,直接调用方法或访问数据。调用子组件方法,表单校验,控制弹窗
provide / inject:深层组件传值,避免 props 层层传递(prop drilling),默认不是响应式(Vue2)。
2.兄弟组件通信
EventBus(事件总线),通过一个公共 Vue 实例进行事件派发:Vue3不使用了
3.跨层级组件通信
attrs / listeners,用于多层组件透传props和事件。常见场景:A → B → C,B 不处理数据,直接透传给 C。
4.任意组件通信
就是Vuex/Pinia
路由的hash和history模式的区别
Vue Router 有两种路由模式:hash 模式和 history 模式,它们主要区别在于 URL 形式和实现原理不同。
hash 模式的 URL 会带一个 #,比如 /#/user,它是通过监听浏览器的 hashchange 事件实现路由切换的。hash 变化不会向服务器发送请求,所以不需要后端配合,兼容性也很好,这是Vue 默认的模式。
history 模式基于HTML5的History API,比如 pushState,URL 看起来像正常路径,没有 #,更美观,也更利于 SEO。不过刷新页面时浏览器会向服务器请求当前路径,如果后端没有做重定向配置,就会出现 404。
一般来说,后台管理系统常用 hash 模式,而官网或需要SEO的项目更适合history模式。
route 和 router 的区别主要是:
route 是路由信息对象,router 是路由实例对象。
$route 用来获取当前路由的信息,比如 path、params、query、name等,它是只读的,通常用于获取参数或监听路由变化。
$router 是整个 Vue Router 的实例,主要用来进行路由操作,比如 push、replace、go,用于页面跳转或注册导航守卫。
route 负责"拿数据",router 负责"做跳转"。
Vue-router跳转和location.href有什么区别
location.href,会刷新页面,浏览器会重新向服务器请求资源。页面状态会丢失,整个应用重新加载。
Vue-Router(this.$router.push() 或 <router-link>),不刷新页面,属于前端路由的跳转。Vue-Router 会用 diff 算法更新视图,只渲染变化的部分 DOM,性能更好。本质上,history 模式下是封装了 history.pushState(),hash 模式下是修改 location.hash。
params和query的区别
在Vue-Router中,params和query都可以传递参数,但方式不同。params需要在路由中定义动态路径(如 /user/:id),通过name跳转,参数通过this.route.params 获取,不会显示在 URL 上,但刷新页面会丢失。query 是普通路由传参(如 /user?id=123),通过 path 跳转,参数通过 this.route.query 获取,会显示在 URL 上,刷新页面参数不会丢失。
对前端路由的理解
前端路由的核心是在单页面应用(SPA)中,通过 URL 来标识不同的视图,实现无需刷新页面即可切换内容的效果。早期网页是多页面模式,每次切换页面都会刷新整个页面,体验较差;SPA 的出现解决了页面无刷新更新的问题,但带来了"URL 不变、用户操作无法定位"和"SEO 不友好"的问题。
前端路由通过在浏览器端感知URL的变化,将不同的 URL 映射到不同的视图上,即便刷新页面,也能根据 URL 渲染对应内容。同时,前端路由会拦截刷新操作,避免服务器无意义的请求,从而实现了 SPA 下的导航、前进后退和状态保持。常见实现方式有hash模式和history模式,分别通过 # 或 HTML5 History API来管理URL与视图的对应关系。
Vuex的原理
Vuex 本质上是 Vue 的集中式状态管理方案 ,用于管理多个组件之间共享的数据。它的核心思想是:用一个全局 Store 统一管理状态,并通过单向数据流保证数据变化可预测。组件不能直接修改 state,而是必须按照固定流程进行数据修改:组件通过 dispatch 触发 action,action 主要处理异步逻辑,然后通过 commit 提交 mutation,mutation 再去同步修改 state。当 state 发生变化时,由于 Vue 的响应式机制,依赖该数据的组件会自动重新渲染。
Vuex中action和mutation的区别
在 Vuex 中,mutation 和 action 都是用来修改状态流程的一部分,但职责不同。
mutation 主要负责修改 state,并且必须是同步操作,组件通过 commit 来触发 mutation。这样做是为了保证状态变化是可追踪的,方便调试。
action 主要负责 处理业务逻辑和异步操作,比如请求接口、定时任务等。action 不能直接修改 state,而是通过 commit 去调用 mutation 来间接修改数据,组件通过 dispatch 来触发 action。
Vuex和localStorage的区别
存储位置不同
Vuex:存储在内存中,读取快,刷新页面会丢失数据。
localStorage:存储在浏览器本地,以字符串形式保存,刷新页面不会丢失数据。
响应性和用途
Vuex:支持响应式,适合组件间共享和管理状态。
localStorage:不支持响应式,适合跨页面保存固定数据。
应用场景
Vuex:组件之间传值和状态管理。
localStorage:长期保存数据或跨页面传递数据。
Redux 和 Vuex 有什么区别,它们的共同思想
Vuex 和 Redux 都是前端状态管理库,本质上都是把数据从视图中抽离出来,实现单一数据源和可预测的状态变化。不同点是:Vuex 用 mutations 替代 Redux 的 reducer,不需要 switch,直接在 mutation 里修改 state;Vuex 利用 Vue 的响应式特性,修改 state 后组件会自动重新渲染,而 Redux 需要手动订阅更新;Vuex 弱化了 dispatch 和 reducer,只需通过 commit 改变状态,更加简单直观。
Vuex 有哪几种属性
Vuex 是 Vue 的状态管理工具,它主要有五种属性:state 存放基本数据,getters 从 state 派生数据,mutations 用于同步修改 state,actions 用来触发 mutations 并支持异步操作,modules 则用于模块化管理状态,方便大型项目维护。整个流程是组件通过 dispatch 或 commit 调用 actions 或 mutations 改变 state,state 改变后,组件会响应式更新视图,从而实现全局状态的可预测管理。
Vuex和单纯的全局对象有什么区别?
Vuex 和单纯的全局对象最大的区别在于响应式和可预测管理:Vuex 的状态存储是响应式的,组件读取 store 中的状态时,如果状态发生变化,组件会自动高效更新;同时,Vuex 不允许直接修改 state,必须通过 commit 提交 mutation 来改变状态,这样可以方便地跟踪每一次状态变化,保证数据流可预测且易于维护,而单纯的全局对象无法做到这些**。**
为什么 Vuex 的 mutation 中不能做异步操作?
Vuex 中的 mutation 不能做异步操作,因为 mutation 是唯一改变 state 的途径,它必须同步执行以保证每次状态变化都是可追踪的。异步操作会通过 action 提交 mutation,这样可以让状态变化有明确的时间点,使 devtools 能够记录快照,实现状态追踪和 time-travel 调试。如果 mutation 支持异步操作,就无法准确知道状态何时更新,调试和追踪都会变得困难。
Vue3.0有什么更新
Vue 3 相比 Vue 2 的主要更新是:响应式机制由 Object.defineProperty 改为 Proxy,支持更多数据类型;模板优化了作用域插槽和 render 函数,提升渲染性能;组件写法更易于 TypeScript 和组合式 API 使用;支持 Fragment、Portal、多根节点渲染;并且体积更小,可 tree-shaking,性能和扩展性都更好。
defineProperty和proxy的区别/为什么Vue3要用Proxy
Vue 2 用 Object.defineProperty 逐个属性设置 getter/setter 来实现响应式,但无法检测新增或删除的属性,也无法监听数组索引和长度变化;Vue 3 用 Proxy 直接代理整个对象,不用 Vue.set/delete 就能检测属性新增或删除,能监听属性增删和数组变化,性能更好,支持更多数据类型。
Composition API与React Hook很像,区别是什么
Composition API 和 React Hook 都是组合式逻辑复用的方案,但区别在于:React Hook 每次组件重渲染都要调用 Hook,需要在顶层固定顺序、手动管理依赖;而 Vue 的 Composition API 利用响应式系统,只在 setup 调用一次,可在循环或条件中使用,依赖收集自动完成,性能更优且使用更灵活。
虚拟DOM的理解
虚拟DOM其实是一个轻量级的 JavaScript 对象,用来描述真实 DOM 的结构。每次数据变化时,Vue 会先生成新的虚拟 DOM,再和之前的虚拟 DOM 进行 diff 比较,只把变化的部分更新到真实 DOM,从而减少重排和重绘,提升性能。本质上,虚拟 DOM 是对 DOM 的抽象,它让前端渲染跨平台成为可能,也让开发者无需手动操作 DOM,提高了开发效率和可维护性。
虚拟DOM的解析过程
构建虚拟 DOM:首先将要渲染的 DOM 树抽象成 JavaScript 对象,每个节点包含 tag、props、children 等信息,形成一棵对象树。
Diff 比较:当数据变化时,重新生成一棵新的虚拟 DOM 树,然后和旧的虚拟 DOM 树进行比较,找出差异。
更新真实 DOM:将差异部分应用到真实 DOM 中,只更新变化的节点,从而减少重排重绘,提升性能。
为什么要用虚拟 DOM:
保证性能:通过在 JS 层构建虚拟 DOM 树并进行 Diff 对比,只更新变化的节点,避免频繁操作真实 DOM 的重排重绘,提高渲染效率,即便不手动优化也能获得较好性能。
跨平台:虚拟 DOM 是 JS 对象,可以方便地在不同平台渲染,如服务端渲染(SSR)、移动端框架(uni-app)等,实现跨平台开发。
Diff 算法原理:
在虚拟 DOM 更新时,Vue 会先判断新旧节点是否为同一节点,如果不是就直接替换;如果是同一节点,则对节点的属性和子节点进行比对。对子节点的比对只在同一层级进行(不跨级比较),包括新增、删除和移动操作,匹配到相同子节点则递归对比。通过这种策略,时间复杂度从 O(n³) 降到 O(n),只对必要部分进行最小化更新,从而提升渲染性能。
Vue 中 key 的作用:
key 用于虚拟 DOM 的唯一标识,保证节点更新时能准确、高效地复用或替换。在 v-if 场景中,key 可以避免元素被复用,确保切换时状态重置;在 v-for 场景中,key 用于追踪列表中每个元素的身份,使 Vue 能够高效地比对和更新虚拟 DOM,从而减少不必要的 DOM 操作,提高渲染性能。