怎么实现路由懒加载呢
这是一道应用题。当打包应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问时才加载对应组件,这样就会更加高效
回答范例
- 当打包构建应用时,Javascript 包会变得非常大,影响页面加载。利用路由懒加载我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样会更加高效,是一种优化手段
- 一般来说,对所有的路由都使用动态导入是个好主意
- 给选项配置一个返回 组件的函数就可以定义懒加载路由。例如:
- 结合注释 可以做代码分块
Vue complier 实现
- 模板解析这种事,本质是将数据转化为一段 ,最开始出现在后端,经过各种处理吐给前端。随着各种 的兴起,模板解析交由前端处理。
- 总的来说, 是将 转化成一个 字符串。
可以简单理解成以下步骤:
- 过程,将 利用正则转化成 抽象语法树。
- 过程,标记静态节点,后 过程跳过静态节点,提升性能。
- 过程,生成 字符串
assets和static的区别
相同点: 和 两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点
不相同点: 中存放的静态资源文件在项目打包时,也就是运行 时会将 中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在 文件中跟着 一同上传至服务器。 中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是 中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于 中打包后的文件提交较大点。在服务器中就会占据更大的空间。
建议: 将项目中 需要的样式文件js文件等都可以放置在 中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如 等文件可以放置在 中,因为这些引入的第三方文件已经经过处理,不再需要处理,直接上传。
Vue的性能优化有哪些
(1)编码阶段
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连用
- 如果需要使用v-for给每项元素绑定事件时使用事件代理
- SPA 页面采用keep-alive缓存组件
- 在更多的情况下,使用v-if替代v-show
- key保证唯一
- 使用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动态加载
- 图片懒加载
(2)SEO优化
- 预渲染
- 服务端渲染SSR
(3)打包优化
- 压缩代码
- Tree Shaking/Scope Hoisting
- 使用cdn加载第三方模块
- 多线程打包happypack
- splitChunks抽离公共文件
- sourceMap优化
(4)用户体验
- 骨架屏
- PWA
- 还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
v-show 与 v-if 有什么区别?
v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。
v-model 可以被用在自定义组件上吗?如果可以,如何使用?
可以。v-model 实际上是一个语法糖,如:
实际上相当于:
用在自定义组件上也是同理:
相当于:
显然,custom-input 与父组件的交互如下:
- 父组件将变量传入custom-input 组件,使用的 prop 名为;
- custom-input 组件向父组件传出名为的事件,父组件将接收到的值赋值给;
所以,custom-input 组件的实现应该类似于这样:
参考 前端进阶面试题详细解答
v-model 是如何实现的,语法糖实际是什么?
(1)作用在表单元素上 动态绑定了 input 的 value 指向了 messgae 变量,并且在触发 input 事件的时候去动态把 message设置为目标值:
(2)作用在组件上 在自定义组件中,v-model 默认会利用名为 value 的 prop和名为 input 的事件
本质是一个父子组件通信的语法糖,通过prop和$.emit实现。 因此父组件 v-model 语法糖本质上可以修改为:
在组件的实现中,可以通过 v-model属性来配置子组件接收的prop名称,以及派发的事件名称。
例子:
默认情况下,一个组件上的v-model 会把 value 用作 prop且把 input 用作 event。但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。js 监听input 输入框输入数据改变,用oninput,数据改变以后就会立刻出发这个事件。通过input事件把数据emit`过来的值。
Vue 组件间通信有哪几种方式?
Vue 组件间通信是面试常考的知识点之一,这题有点类似于开放题,你回答出越多方法当然越加分,表明你对 Vue 掌握的越熟练。Vue 组件间通信只要指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,下面我们分别介绍每种通信方式且会说明此种方法可适用于哪类组件间通信。
(1) 适用 父子组件通信
这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。
(2) 与 适用 父子组件通信
- :如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
- / :访问父 / 子实例
(3) 适用于 父子、隔代、兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
(4)/ 适用于 隔代组件通信
- :包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 传入内部组件。通常配合 inheritAttrs 选项一起使用。
- :包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 传入内部组件
(5) 适用于 隔代组件通信
祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
(6)Vuex 适用于 父子、隔代、兄弟组件通信
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
Vue 中的 key 到底有什么用?
key 是给每一个 vnode 的唯一 id,依靠 key,我们的 diff 操作可以更准确、更快速 (对于简单列表页渲染来说 diff 节点也更快,但会产生一些隐藏的副作用,比如可能不会产生过渡效果,或者在某些节点有绑定数据(表单)状态,会出现状态错位。)
diff 算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的 key 与旧节点进行比对,从而找到相应旧节点.
更准确 : 因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确,如果不加 key,会导致之前节点的状态被保留下来,会产生一系列的 bug。
更快速 : key 的唯一性可以被 Map 数据结构充分利用,相比于遍历查找的时间复杂度 O(n),Map 的时间复杂度仅仅为 O(1)
Vue computed 实现
- 建立与其他属性(如:、 )的联系;
- 属性改变后,通知计算属性重新计算
实现时,主要如下
- 初始化 , 使用 把这些属性全部转为 。
- 初始化 , 遍历 里的每个属性,每个 属性都是一个 实例。每个属性提供的函数作为属性的 ,使用 转化。
- 依赖收集。用于依赖发生变化时,触发属性重新计算。
- 若出现当前 计算属性嵌套其他 计算属性时,先进行其他的依赖收集
vuex是什么?怎么使用?哪种功能场景使用它?
是一个专为 应用程序开发的状态管理模式。 就是一个仓库,仓库里放了很多对象。其中 就是数据源存放地,对应于一般 vue 对象里面的 里面存放的数据是响应式的, 组件从 读取数据,若是 中的数据发生改变,依赖这相数据的组件也会发生更新它通过 把全局的 和 映射到当前组件的 计算属性
- 一般用于中大型 单页应用中对应用的状态进行管理,对于一些组件间关系较为简单的小型应用,使用 的必要性不是很大,因为完全可以用组件 属性或者事件来完成父子组件之间的通信, 更多地用于解决跨组件通信以及作为数据中心集中式存储数据。
- 使用解决非父子组件之间通信问题 是通过将 作为数据中心、各个组件共享 实现跨组件通信的,此时的数据完全独立于组件,因此将组件间共享的数据置于 中能有效解决多层级组件嵌套的跨组件通信问题
的 在单页应用的开发中本身具有一个“数据库”的作用,可以将组件中用到的数据存储在 中,并在 中封装数据读写的逻辑。这时候存在一个问题,一般什么样的数据会放在 中呢? 目前主要有两种数据会使用 进行管理:
- 组件之间全局共享的数据
- 通过后端异步请求的数据
包括以下几个模块
- : 使用单一状态树,即每个应用将仅仅包含一个 实例。里面存放的数据是响应式的, 组件从 读取数据,若是 中的数据发生改变,依赖这相数据的组件也会发生更新。它通过 把全局的 和 映射到当前组件的 计算属性
- :更改的中的状态的唯一方法是提交
- : 可以对 进行计算操作,它就是 的计算属性虽然在组件内也可以做计算属性,但是 可以在多给件之间复用如果一个状态只在一个组件内使用,是可以不用
- : 类似于 , 不同在于: 提交的是 ,而不是直接变更状态 可以包含任意异步操作
- :面对复杂的应用程序,当管理的状态比较多时;我们需要将的对象分割成模块()
:项目特别复杂的时候,可以让每一个模块拥有自己的、、、,使得结构非常清晰,方便管理
回答范例
思路
- 给定义
- 必要性阐述
- 何时使用
- 拓展:一些个人思考、实践经验等