复习回顾计划-vue篇
一、keep-alive
(一) keep-alive原理
- Vue 内部维护了一个 cache 对象,用于存储需要缓存的组件;
- 当一个组件第一次被 <keep-alive> 包裹时,Vue 会将组件的 vnode 缓存到 cache 对象中;
- 当组件被激活时,<keep-alive> 会从 cache 缓存中取出组件对应的 vnode,然后将它们渲染到页面上。
- 当子组件被停用时,<keep-alive> 会将组件对应的 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,事件监听,子组件 |
<keep-alive></keep-alive>独有的两个生命周期函数:
activated | 激活时---当页面缓存被缓存的时候,有activated钩子和created钩子函数时,两个钩子函数都会触发,且只会调用一次created |
deactivated | 失活时---当页面被缓存的时候,就不会触发destroyed生命钩子,而触发的是此钩子函数 |
在捕获一个来自后代组件的错误时被调用:
errorCaptured | 返回false可以阻止错误继续向上传递。这个钩子带有三个实参:错误对象、触发该错误的组件实例,以及一个说明错误来源类型的信息字符串 |
六、$set 的实现原理
- 判断目标对象是否为数组:
-
- 如果目标对象是数组,$set 方法会直接调用数组的 splice 方法实现对数组的变更。splice 方法可以用来向数组中添加新元素或删除已有元素,并会触发 Vue.js 监听到该数组的变化。
- 判断目标对象是否为响应式对象:
-
- 如果目标对象不是数组,$set 方法会先判断该对象是否已经是响应式的。如果是响应式的,直接使用 Vue.js 内部提供的 Observer 对象中的 defineReactive 方法将新属性转换为响应式属性。
- 如果不是响应式的,会先将该对象转换为响应式对象,再添加新属性。
七、$route 和 $router 的区别
- $router 是 Vue Router 的实例对象,它主要用于提供一些导航功能,例如路由跳转和导航守卫的方法等。
- $route 是当前访问的路由信息对象,它主要用于提供当前路由的一些相关数据,例如当前路由的名称、路径、参数、元信息等。
八、style 标签添加 scoped 属性原理
vue 使用了 CSS Modules 技术来实现组件的局部样式。具体来说,Vue 会为每个组件的样式添加一个唯一的标识符,然后在组件渲染时将样式的类名替换为带有标识符的类名。这样可以确保组件的样式不会与其他组件或者全局样式冲突。
九、组件通信
- props / $emit:这是最基本的父子组件传值的方式。父组件通过 props 属性传递数据,子组件通过 $emit 事件触发父组件的方法进行通信。可以通过 v-bind 和 v-on 简写为 :propName 和 @eventName。
- $parent / $children:通过 $parent 和 $children 访问父组件和子组件实例。但是这种方式不够优雅,并且存在一些潜在的问题,比如父子组件的嵌套结构变化时可能导致代码失效。
- provide / inject:父组件通过 provide 选项提供数据,子组件通过 inject 选项注入数据。这种方式可以跨越多个层级进行数据传递,但是不够直观,并且容易被滥用,影响代码的可维护性。
- $attrs / $listeners:$attrs 包含了父组件传递给子组件但子组件没有声明 prop 的属性,$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.初始化相关属性:$parent、$children、$root、$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