——————————————————vue2——————————————————————
一、keep-alive
(一) keep-alive原理
- Vue 内部维护了一个 cache 对象,用于存储需要缓存的组件;
- 当一个组件第一次被 包裹时,Vue 会将组件的 vnode 缓存到 cache 对象中;
- 当组件被激活时, 会从 cache 缓存中取出组件对应的 vnode,然后将它们渲染到页面上。
- 当子组件被停用时, 会将组件对应的 vnode 重新放回到 cache 缓存中,而不是直接销毁。
- 如果一个组件在缓存时被设置了 max 属性,则当缓存的组件实例数超过了 max 值时,Vue 会按照 LRU 算法(最近最少使用)从缓存中清除不活动的组件,以保证缓存的组件实例数不会超过 max 值。
(二) 如何更新keep-alive
- 组件实例上调用 $forceUpdate
- 组件添加 key 特性。当改变 key 的值keep-alive会重新渲染缓存的组件
二、Vue 自定义指令
我们可以通过 Vue.directive 全局方法或在组件的 directives 选项中来注册自定义组件
钩子函数
- bind: 当指令被绑定到元素上时调用,只调用一次,可以在这里进行初始的设置。
- inserted: 当被绑定的元素插入到父节点时调用,只调用一次。
- update: 当组件的VNode更新时调用,但子节点还未更新。
- componentUpdated: 当组件的VNode及其子节点更新后调用。
- unbind: 当指令从元素上解绑时调用。
参数
- el: 指令所绑定的元素,可以通过el属性访问元素的属性和方法。
- binding: 一个对象,包含指令的相关信息,如value(指令的绑定值)、name(指令的名称)、expression(绑定值的字符串形式)等。
- vnode: Vue编译生成的虚拟节点。
- oldVnode: 上一个虚拟节点
三、路由守卫
Vue Router 的底层原理是基于浏览器的 History API 和 Vue.js 的核心功能实现的。通过监听 URL 的变化、使用路由匹配系统和导航守卫机制
next()函数
- 不带参数:next() 或 next(true),表示允许当前导航继续进行,即通过导航到达目标路由。
- 传递一个路由路径(字符串)参数:next('/path'),表示取消当前导航,重定向到指定的路由路径。
- 传递一个命名的路由对象参数:next({ name: 'route-name' }),表示取消当前导航,重定向到指定的命名路由。
- 传递一个带有 replace 选项的路由对象参数:next({ path: '/path', replace: true }),表示取消当前导航,重定向到指定的路由路径,并替换当前的历史记录。
- 传递一个回调函数参数:next(callback),回调函数会在当前导航被确认之后执行。可以用于延迟导航或执行其他异步操作。
四、Vue 中常用修饰符
- .prevent:阻止默认事件。在事件指令上使用 .prevent 修饰符可以阻止事件的默认行为。
- .stop:停止事件冒泡。在事件指令上使用 .stop 修饰符可以停止事件的进一步传播。
- .once:只触发一次事件。在事件指令上使用 .once 修饰符可以确保事件只被触发一次。
- .capture:使用事件捕获模式。在事件指令上使用 .capture 修饰符可以将事件绑定在父元素上,然后在捕获阶段触发事件。
- .self:只在事件目标自身触发事件。在事件指令上使用 .self 修饰符可以确保事件只在触发事件的元素本身上被触发,而不是其子元素。
- .passive:指定事件监听器为被动的。在事件指令上使用 .passive 修饰符可以告诉浏览器事件监听器不会调用 preventDefault(),从而提高滚动性能。
- .native:监听组件根元素的原生事件。在自定义组件上使用 .native 修饰符可以监听组件根元素的原生事件。
- .number:将输入转换为数字类型。在表单元素上使用 .number 修饰符可以将输入的值自动转换为数字类型。
- .lazy:延迟更新输入值。在表单元素上使用 .lazy 修饰符可以将输入的值在失去焦点或按下回车键时才进行更新。
- .trim:自动去除输入值的首尾空格。在表单元素上使用 .trim 修饰符可以自动去除输入值的首尾空格。
五、生命周期
beforeCreate | 创建前----data和el都没有初始化,不能访问data、method |
---|---|
created | 创建后----data、method已被初始化,真实dom还没生成,$el还不可用,是最早可以调用data和method的钩子函数,故一般在此对数据进行初始化 |
beforeMount | 挂载前---模板已经编译完成,但是未挂载到页面中,虚拟dom还未加载为真实dom,el只有渲染完成后才会存在,这里读取不了真实的el |
mounted | 挂载后---此时模板已经被渲染成真实DOM,实例已经被完全创建好了,相当于在此阶段可以操作DOM |
beforeUpdate**** | 更新前---重新渲染之前(view层的数据变化前,不是data中的数据改变前)触发,页面中显示的数据还是旧的,此时date数据是最新的 |
updated | 更新后---数据已经更改完成 |
beforeDestroy**** | 销毁前---这里善后:清除计时器、清除非指令绑定的事件等等 |
destroyed | 销毁后---这里,卸载watcher,事件监听,子组件 |
独有的两个生命周期函数:
activated**** | 激活时---当页面缓存被缓存的时候,有activated钩子和created钩子函数时,两个钩子函数都会触发,且只会调用一次created |
---|---|
deactivated**** | 失活时---当页面被缓存的时候,就不会触发destroyed生命钩子,而触发的是此钩子函数 |
在捕获一个来自后代组件的错误时被调用:
errorCaptured | 返回false可以阻止错误继续向上传递。这个钩子带有三个实参:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串 |
---|
六、$set 的实现原理
- 判断目标对象是否为数组:
-
- 如果目标对象是数组,$set 方法会直接调用数组的 splice 方法实现对数组的变更。splice 方法可以用来向数组中添加新元素或删除已有元素,并会触发 Vue.js 监听到该数组的变化。
- 判断目标对象是否为响应式对象:
-
- 如果目标对象不是数组,$set 方法会先判断该对象是否已经是响应式的。如果是响应式的,直接使用 Vue.js 内部提供的 Observer 对象中的 defineReactive 方法将新属性转换为响应式属性。
- 如果不是响应式的,会先将该对象转换为响应式对象,再添加新属性。
七、router 的区别
- $router 是 Vue Router 的实例对象,它主要用于提供一些导航功能,例如路由跳转和导航守卫的方法等。
- $route 是当前访问的路由信息对象,它主要用于提供当前路由的一些相关数据,例如当前路由的名称、路径、参数、元信息等。
八、style 标签添加 scoped 属性原理
vue 使用了 CSS Modules 技术来实现组件的局部样式。具体来说,Vue 会为每个组件的样式添加一个唯一的标识符,然后在组件渲染时将样式的类名替换为带有标识符的类名。这样可以确保组件的样式不会与其他组件或者全局样式冲突。
九、组件通信
- props / emit 事件触发父组件的方法进行通信。可以通过 v-bind 和 v-on 简写为 :propName 和 @eventName。
- children:通过 children 访问父组件和子组件实例。但是这种方式不够优雅,并且存在一些潜在的问题,比如父子组件的嵌套结构变化时可能导致代码失效。
- provide / inject:父组件通过 provide 选项提供数据,子组件通过 inject 选项注入数据。这种方式可以跨越多个层级进行数据传递,但是不够直观,并且容易被滥用,影响代码的可维护性。
- listeners:listeners 包含了父组件绑定在子组件上的所有事件监听器。这种方式适用于开发通用组件库,但是不太适合在业务开发中使用。
- Vuex:Vuex 是 Vue 的状态管理库,适用于大型单页面应用程序的状态管理。可以将组件之间共享的状态提取到 Vuex 的 store 中,通过 mutations 和 actions 进行修改和更新。
- EventBus:EventBus 是一个简单的事件总线,可以在组件之间广播事件。可以通过 Vue.prototype.���注册事件总线,在组件中通过bus注册事件总线,在组件中通过emit 触发事件,通过 $on 监听事件。
十、Vue模版编译原理
- 解析模板:Vue先会解析模板字符串,将template转化为AST(抽象语法树)。
- 优化AST:对AST树进行静态内容优化,包括标记静态节点、静态属性和静态文本等。
- 生成渲染函数:利用优化后的AST生成渲染函数,接收一个上下文对象作为参数,并返回一个虚拟DOM树(VNode)
- 渲染虚拟DOM:执行渲染函数时会生成一个新的虚拟DOM树,如果存在真实的DOM树,Vue将通过比较新旧VNode来计算最小的更新操作并应用在真实DOM上
- 生成DOM: Vue将根据最新的VNode生成真实的DOM元素,并将其插入到页面中,完成渲染
十一、npm run 发生了什么
- 在package.json里 scripts找到对应的指令
- 安装依赖的时候,会根据第三方依赖中的package.json里面的bin配置,在node_modules下面的.bin目录生成一个可执行文件(软连接)
- npm run 的时候会自动给脚本加上路径都加上了node_moudles/.bin前缀,如果没找到可执行文件就会全局找,再没有就会报错
十二、new Vue()发生了什么
1.用户传入的配置(option)和系统配置的合并
2.初始化相关属性:children、refs、_watcher、_isMounted等
3.初始化事件中心,例:@定义事件
4.解析插槽,定义vm._c处理template默认,定义vm.$createElement处理手写render模式
5.挂载beforeCreate生命周期
6.初始化组件的inject注入配置项
7.构建响应式系统(props、methods、data、computed、watch)
8.解析组件配置项上的provide对象
9.挂载create生命周期
10.最后调用$mount进行页面挂载
十三、首屏加载速度慢怎么解决
- 减小入口文件体积:常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加
- UI框架按需加载:组件按需引用
- 开启GZip压缩:1.直接在 nginx 服务端配置开启 gzip 2.webpack 来开启 gzip,并在nginx 加上支持 gizp 的配置
- 组件重复打包: webpack配置CommonsChunkPlugin里minChunks数量,抽离使用N次及以上的包,放进公共依赖文件,避免了重复加载组件
- ssr
——————————————————vue3——————————————————————
一、watch 和 watchEffect区别
- 语法不同:
-
- watch 需要接收至少两个回调函数作为参数,可以在第三个参数中配置对数据进行深度侦听和立即侦听;
- watchEffect 直接接受一个函数作为参数,内部会自动追踪函数中使用的响应式数据。
- 侦听的对象不同:
-
- watch 侦听指定的响应式数据或计算属性的变化
- watchEffect 会自动侦听函数内部使用的响应式数据变化。
- 触发时机不同:
-
- watch 在侦听的数据发生变化后触发回调函数,可以根据需求设置立即执行或延迟执行;
- watchEffect 会在组件渲染时立即执行一次,并在其内部使用的响应式数据变化时自动重新执行。
- 响应式数据更新时的处理方式不同:
-
- watch 的回调函数接收新值和旧值作为参数,可以根据需要进行逻辑处理;
- watchEffect 的回调函数不能接收参数。
二、生命周期
● onBeforeMount()
● onMounted()
● onBeforeUpdate()
● onUpdated()
● onBeforeUnmount()
● onUnmounted()
三、为什么要用 Proxy 替代 defineProperty
- Proxy支持代理的对象类型更加广泛,而Object.defineProperty只能对对象的属性进行代理。Proxy可以代理整个对象,包括数组、Map、Set等等。
- Proxy可以监听到更多的操作,包括属性的删除、原型链上的操作等。而Object.defineProperty只能监听到属性的get和set操作,对象属性的添加和删除。
- Proxy的性能比Object.defineProperty更好,defineProperty需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题。
四、v-if 和 v-for 的优先级改变
在 vue2 中 v-for 的优先级更高,但是在 vue3 中优先级改变了。v-if 的优先级更高。
五、vue3中新增了哪些新组件
- Fragment(虚拟容器,template支持多个根节点);
- Teleport(传送门,“传送”到该组件的 DOM 结构外层的位置去,例如全屏的模态框);
- Suspense(在Suspense组件中包裹异步组件,提供一个fallback选项,可以在异步组件加载过程中展示一个占位符,直到异步组件加载完成后才显示真正的内容)。
六、vue3中组件通信
- Props 和 Events
- Provide 和 Inject
- Vuex
七、Composition API与Options API的区别.
- Options API data属性中定义数据,methods中定义属性,computed中定义计算属性,watch中监听属性改变,还有一些声明周期钩子同一个功能的逻辑就会被拆分的很散难以阅读和理解。
- Composition API 可以根据逻辑功能来组织代码。比如可以把一个功能所用到的 API 放在一起,这样可以让代码高内聚和低耦合,进而提高了代码的逻辑的复用。
- Composition API 中见不到 this 的使用,减少了 this 指向不明的情况。
- Composition API 几乎是函数,会有更好的类型推断,对于 TS 的支持更友好。
八、vue2为什么只能有一个根节点,而vue3可以是多根节点
- vue2:vdom是一个单根树形结构,patch方法在遍历的时候从根节点开始遍历,它要求只有一个根节点
- vue3:引入了fragment,这是一个抽象的节点,如果发现组件是多根的会自动创建一个fragment节点,把多根节点视为自己的children