vue
vue基础
Vue的生命周期有哪些及每个生命周期做了什么?
- Vue的生命周期分为三个阶段:初始化阶段、数据更新阶段、销毁阶段
- 初始化阶段
- beforeCreate(页面创建前):此时实例还未完成初始化,是没有this的,所以无法访问到data、computed、watch、methods等属性和方法。
- created(页面创建后):实例已经创建完成,有了this,可以访问data、methods、computed等;但还没挂载DOM
- beforeMount(页面渲染前):在渲染前被调用,此时模板已经编译完成,但还是获取不到dom节点,但有this,这个阶段很少用。
- mounted(页面渲染后):在实例挂载到页面之后调用。此时真实DOM已经渲染完成,可以进行DOM操作。
- 数据更新阶段
- beforeUpdate(更新前):在数据更新之前被调用,该方法可用于在更新之前访问现有的DOM
- updated(更新完成):在数据更新之后被调用,该方法还会在组件的子组件更新之后被调用。
- 销毁阶段
- beforeDestroy(销毁前):此时实例仍然可以使用。
- destroyed(销毁完成):此时实例所有的指令和事件都已经卸除,所有的子实例都已经被销毁。
Vue3和Vue2的区别?
- 双向数据绑定原理:Vue2使用Object.defineProperty()对数据进行劫持,结合发布订阅者模式实现双向数据绑定。而Vue3是使用Proxy对数据进行处理,可以监听整个对象的变化。
- Props 的使用变化:vue2 通过 this 获取 props 里面的内容,vue3 直接通过 props
- Vue3是组合式API,使用生命周期钩子需要引入再使用,Vue2是选项API,可以直接调用生命周期钩子
- 生命周期的变化:使用setup代替了之前的beforeCreate和created
- ref和reactive,vue2没有这两个东西,vue3有,且用来创建响应式变量
- Route 获取页面实例与路由信息:vue2通过this获取router实例,vue3通过使用 getCurrentInstance/ userRoute和userRouter方法获取当前组件实例
Vue2的响应式原理是什么,Vue3的响应式原理是什么?
Vue2原理
- 在Vue 2中,响应式是通过使用Object.defineProperty()方法来实现的。在组件实例化过程中,Vue会对数据对象(data)进行递归地遍历,将每个属性都转换为getter/setter,并且为每个属性创建一个依赖追踪的系统。当属性被访问或修改时,getter/setter会触发依赖追踪系统,从而进行依赖收集和派发更新,以保证数据和视图的同步。
Vue3原理
对于基本数据类型的数据
- 响应式依然是靠Object.defineProperty()的get和set来完成的
对于对象类型的数据
- 通过Proxy代理:拦截对象中任意属性的变化,包括属性值得读写、添加、删除等操作等
- 通过Reflect反射函数进行操作
谈谈对MVVM的理解?
- MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。
v-model实现原理?
- 通过绑定变量,再监听事件对象,触发$event.target.value,再将值赋给变量
vue组件通信方式有哪些?
- props / $emit
- 父组件通过v-bind向子组件传递数据,子组件通过props去接收父组件传递过来的数据。然后子组件通过$emit将数据派发到父组件
- 插槽 => 可以显示父组件中传递的内容
- 默认插槽(父向子传递)、具名插槽(父向子传递)、作用域插槽(子向父传递)
- 默认插槽:默认情况下组件的内容都在slot中显示
- 具名插槽:允许父组件通过带有v-slot指令的
<template>标签向子组件的指定名称区域分发内容 - 作用域插槽:数据反向传递,允许子组件向父组件传递数据
- 依赖注入
- 前提:一定是嵌套的,不管多深都可以
- 在父组件调用provide()方法,将数据传递给子组件。子组件通过调用inject()方法来获取父组件传递过来的数据和方法
- 模板引用(ref与$refs)
- 在父组件中,使用
<template>标签定义子组件,并在<template>标签中使用ref属性为子组件指定一个引用名 - 在父组件中,可以使用$refs属性来获取子组件的实例
- 在父组件中,使用
如何传递多个插槽?
- 多个
<template>分别指定插槽名
动态插槽的应用场景?
- 根据状态动态切换插槽内容,比如表格组件根据数据类型渲染不同列
说一下v-if与v-show的区别?
- v-if是操作DOM元素的,v-show是操作样式的
- v-if是惰性的,当条件不成立时,v-if不会渲染DOM元素;v-show无论条件成不成立,都能被编译,而且DOM元素保留
Vue2中,data为什么是函数?
- 在Vue 2中,data 是一个函数,这是因为Vue需要确保每个组件实例都有独立的响应式数据。如果data 直接是一个对象,那么在多个组件实例中,它们可能会共享同一个数据,这将导致组件之间的状态互相影响,不符合预期。
- 通过将 data 设为一个函数,每次当一个组件实例被创建时,这个函数都会返回一个新的对象,从而确保每个组件实例都有自己的数据
computed和watch的区别?
相同:都能监听data的数据变化
区别:
- 写法的不同,watch不需要返回值
- compute是处理同步的,watch是处理异步的
- 使用场景不同:watch监听一个数据变化,影响其他N个数据;computed监听N个数据,只影响一个数据
watch和watchEffect的区别?
- 都能监听响应式数据变化,但监听数据变化的方式是不同得
- watch要明确指出监听的数据,watchEffect不用明确指出监听的数据
- watchEffect是立即执行的,在页面加载时会主动执行;watch是惰性的,不会立即执行
Vue中key值的作用?
- key作用:用来作为节点的唯一标识
- 当Vue用 v-for 正在更新已渲染过的元素列表是,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
- 为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。
Vue3中ref和reactive有什么区别?
- ref和reactive都是vue3中用于创建响应式数据的方法。
两者的区别- 数据类型不同:ref用于包裹简单数据类型的数据,reactive用于包裹复杂数据类型的数据
- 创建和访问方式不同:ref创建出来的响应式数据,想要通过.value去访问,而reactive创建出来的可以直接访问其属性或调用其方法
怎么用交叉观察者实现图片懒加载?
- 图片懒加载的实现原理是:将图片以自定义属性的方式存储,然后通过交叉观察者确定可视区是否需要渲染,再根据交叉观察者去动态将自定义属性存储的图片放到渲染属性上。
有没有了解过组件初始化?
- 组件初始化是指当组件被创建准备进行渲染时,所经历的一系列生命周期和内部状态设置的过程
beforeCreate
- 在beforeCreate阶段,组件已被创建,但数据、方法等还未被设置,还没有this
created
- 在created阶段,组件创建完成后立即调用,此时组件的数据、方法等已被设置,可以通过this访问
beforeMount
- 这个生命周期也是只有this,还没有dom,比较少用
mounted
- 在mounted中,组件已被渲染到页面上,在这个生命周期就可以操作dom了
v-html和v-text的区别?
- v-text和插值表达式渲染数据,不解析标签
- v-html不仅可以渲染数据,而且可以解析标签
setup在Vue3中是什么意思?
- setup是Vue3新增的生命周期函数,setup的加入就是为了让Vue3使用组合式API
- 代替了Vue2 中的 beforeCreate 和 created 钩子函数
get和post请求的区别?
- get请求用于从服务器获取数据,一般用于获取资源或查询数据,它将请求参数附加在url的后面,以键值对的形式传递给服务器,post请求用于向服务器提交数据,一般用于创建、更新或删除资源,它将请求参数放在请求体中等等。
- get因为参数会放在url中,所以隐私性,安全性较差,请求的数据长度是有限制的;post请求是没有的长度限制,请求数据是放在body中
- get请求刷新服务器或者回退没有影响,post请求回退时会重新提交数据请求
- get请求可以被缓存,post请求不会被缓存
- get请求会被保存在浏览器历史记录当中,post不会。get请求可以被收藏为书签,因为参数就是url中,但post不能。它的参数不在url中
vue父子组件的生命周期执行顺序?
加载渲染阶段
- 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
更新阶段
- 父beforeUpdate->子beforeUpdate->子updated->父updated
销毁阶段
- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
在setup()中如何访问this?
- setup()中没有this,响应式数据通过ref/reactive定义,方法直接申明
异步请求放在哪个钩子?
- 客户端渲染:onMounted => 确保DOM可用
说说你对 Vue 中异步组件的理解?
- 异步组件是指那些在需要时才加载的组件,而不是在应用初始化时就立即加载。这种机制可以显著提升页面加载速度和用户体验,尤其是在大型单页应用(SPA)中,通过懒加载的方式按需加载组件,避免不必要的资源浪费。
vue路由
如何实现路由页面鉴权?
分为两个层面:登录的情况、没登陆的情况
- 可以用router.beforeEach去实现。
- 用户还没登录的情况,设置白名单,如果用户需要跳转的页面不在白名单内,就强制用户跳转到登录页,如果在白名单内就直接放行
- 登录的情况,如果用户想要跳转到登录界面,就强制跳回首页
导航守卫beforeEach这些有多少个参数?
- 都有3个参数,分别是to:要进入的目标路由,from:要离开当前的路由,next:控制路由执行
Vue-router导航守卫有哪些?
- 全局前置钩子:beforeEach、beforeResolve、afterEach
- 路由独享的守卫:beforeEnter
- 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
Vue的路由模式有哪些?
- 哈希模式和历史模式
哈希路由
- 使用场景:通常用在B端,business;云服务或管理台
- 标志是不刷新页面,并且带#号,只是模块的切换
- 底层实现:通过hashChange事件监听hash值的变化实现切换 => localtion
history路由
- 使用场景:通常用在C端,client;商城
- 标志是刷新页面,并且不带#号,会请求服务器资源;
- 为什么能请求服务器资源,因为webpack开启了server服务;如果发布到线上的话,需要后端的配合才能成功跳转
- 底层实现:通过history.pushstate 和 history.change()实现的 => history
Vue路由之间的跳转方式有哪些?
声明式跳转
- router-link
编程式跳转
- query带?
- params跳转
- 动态路由
Vue-Router的懒加载如何实现?
- 使用箭头函数 + import动态加载
const List = () => import('@/components/list.vue')
const router = new VueRouter({
routes:[
{path:'/list',component:List}
]
})
- 使用箭头函数 + require动态加载
const router = new Router({
routes:[
{
path:'/list',
component:resolve => require(['@/component/list'],resolve)
}
]
})
route和router的区别?
- route是路由对象,提供关于当前路由的信息 => 包括path、params、hash、query等路由信息参数
- router是路由实例对象,提供操作路由的方法,控制路由导航 => 包括了路由的跳转方法,钩子函数等
如何定义动态路由?如何获取传过来的动态参数?
- param方式
- 配置路由格式:/router/:id
- 传递的方式:在path后面跟上对应的值
- 传递后形成的路径:/router/123
- query方式
- 配置路由格式:/router
- 传递的方式:对象中使用query的key作为传递方式
- 传递后形成的路径:/route?id=123
Vue-router跳转和location.href有什么区别?
- 使用location.href更简单,但刷新了页面。
- 使用router.push跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。
params和query的区别?
- 用法:query要用path来引入,params要用name来引入,接受参数都是类似的,分别是route.query.name和route.params.name
- query在浏览器地址栏中显示参数,params则不显示
谈谈你对vue中keep-alive的理解?
-
keep-alive是Vue中的内置组件,它不会渲染到dom树中,普通的组件在被替换之后,会销毁组件,组件中的一些状态都会被销毁,当这个组件再被创建时,组件内的所有属性和方法都是初始化状态的。而keep-alive的作用是,用keep-alive包裹某个组件,在这个组件被替换时,保存当前组件的状态,就是所谓的缓存
-
参数:include、exclude => 指定是否缓存某些组件
- include指定哪些被缓存,可以指定多个被缓存
- exclude指定哪些组件不被缓存
Pinia和Vuex
Pinia有哪些使用场景?
-
共享状态管理
- 多个组件可能需要访问和修改相同的状态、甚至不同页面间访问的数据。例如:用户登录信息、主题设置、购物车内容、全局配置等。
-
持久化数据存储
- Pinia 可以结合插件实现状态的持久化存储,例如将用户偏好设置保存在本地存储中。这样即使用户刷新页面或者重新打开应用,仍然可以恢复之前的状态,提供更好的用户体验。
-
替代 Vuex 的现代方案
- Pinia 被设计为 Vuex 的轻量级替代品,提供了更简洁的 API 和更直观的模块化结构。相比 Vuex,Pinia 减少了不必要的复杂性,例如不再需要 mutations,而是直接通过 actions 修改状态。
-
在组件外访问/修改状态
- 需要在 Vue 组件之外(例如路由守卫、Axios)读取或更新应用状态时,Pinia Store 提供了方便的访问点。
说说Pinia和Vuex的区别?
Vuex
- Vuex一共有五个属性state、getter、mutation、action、module。
- state:主要是用于管理store的一个容易,可以在这里面定义一些公用属性
- getter:主要用于做一些计算,也可以用于访问state中的属性
- mutation:主要用于对state的内容进行同步修改
- action:主要进行一些异步操作,然后通过mutation来该变state的内容,调用action的方法时使用dispatch;
- module:用于将store分模块,否则所有属性存在一个store中时会造成冗余
Pinia
- pinia在Vuex的基础上去掉了mutation,将action作为同步和异步共用的操作方法,并且去掉了module属性,因为每定义一个store就相当于一个模块。因此它一共有三个属性:state、getter、action。
区别
- 使用方式不同,pinia和vuex是两个不同的库,因此在使用方式上有些细微差别
- pinia支持compositionApi的格式,更加贴合Vue3
- pinia的语法和使用方式更加简洁,调用action的方法时无需使用dispatch