Vue中面经

总结一下vue中的高频面试题,平时看到的知识比较散,自己正好也需要汇总一下自己的知识盲点,为接下来的面试做准备。

SSR SPA和MPA

Server-Side Rendering 我们称其为SSR,意为服务端渲染。

在普通的SPA中,一般是将框架及网站页面代码发送到浏览器,然后在浏览器中生成和操作DOM(这里也是第一次访问SPA网站在同等带宽及网络延迟下比传统的在后端生成HTML发送到浏览器要更慢的主要原因),但其实也可以将SPA应用打包到服务器上,在服务器上渲染出HTML,发送到浏览器,这样的HTML页面还不具备交互能力,所以还需要与SPA框架配合,合理地运用SSR技术,不仅能一定程度上解决首屏慢的问题,还能获得更好的SEO。

由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程。

  • Vue SSR是一个在SPA上进行改良的服务端渲染
  • 通过Vue SSR渲染的页面,需要在客户端激活才能实现交互
  • Vue SSR将包含两部分:服务端渲染的首屏,包含交互的SPA

主要解决了以下两种问题:

  • seo:搜索引擎优先爬取页面HTML结构,使用ssr时,服务端已经生成了和业务想关联的HTML,有利于seo
  • 首屏呈现渲染:用户无需等待页面所有js加载完成就可以看到页面视图(压力来到了服务器,所以需要权衡哪些用服务端渲染,哪些交给客户端)

SPA是单页面应用,而MPA是多页面应用,single-page and multi-pages

SPA仅有一个主页面,通过动态重写主页面来与用户实现交互;
MPA有多个主页面,当访问另一个页面时,要重新加载css等文件。

单页面与多页面的对比

image.png

单页应用优缺点

优点:

  • 具有桌面应用的即时性、网站的可移植性和可访问性
  • 用户体验好、快,内容的改变不需要重新加载整个页面
  • 良好的前后端分离,分工更明确

缺点:

  • 不利于搜索引擎的抓取
    SPA是客户端渲染,通过加载执行JS来创建DOM元素构建页面,但是爬虫只是请求静态资源,不会执行JS文件,所以抓取不到DOM结构,也分析不出来有用的信息
  • 首次渲染速度相对较慢
    用户首次加载需要先下载SPA框架及应用程序的代码,然后再渲染页面。

总结:如何给SPA做SEOSSR
前后端分离降低了前端和后端的耦合度,提高了开发效率;
SPA是前后端分离中前端的一种解决方案;
SEO对与很多网站很重要而普通的SPA又不利于SEO;
SSR的出现一定程度上解决了SPA中首屏慢的问题,又极大减少了普通SPA对于SEO的不利影响。

v-show和v-if

两者作用都是控制元素的显隐

  • 当表达式为true的时候,都会占据页面的位置
  • 当表达式都为false时,都不会占据页面位置\

不同之处

  • 控制手段不同

    v-show隐藏则是为该元素添加css--display:nonedom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除

  • 编译过程不同

    v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换

  • 编译条件不同
    v-showfalse变为true的时候不会触发组件的生命周期。
    v-iffalse变为true的时候,触发组件的beforeCreatecreatebeforeMountmounted钩子,由true变为false的时候触发组件的beforeDestorydestoryed方法。

总结
v-if 相比 v-show 开销更大的(直接操作dom节点增加与删除);如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

v-if和v-for哪个优先级更高

  1. Vue 2 中,v-for 优先于 v-if 被解析;但在 Vue 3 中,则完全相反,v-if 的优先级高于 v-for
  2. v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true值的时候被渲染。
  3. v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,要设置key值,并且保证每个key值是独一无二的,这便于diff算法进行优化两者在用法上

注意:1. 把 v-ifv-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)
要避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环

key的作用?

  1. key的作用主要是为了更高效的更新虚拟DOM

  2. diff 算法需要比对虚拟 dom 的修改,然后异步的渲染到页面中,当出现大量相同的标签时,vnode 会首先判断 key 和标签名是否一致,如果一致再去判断子节点一致,使用 key 可以帮助 diff 算法提升判断的速度,在页面重新渲染时更快消耗更少。实际使用中在渲染一组列表时key必须设置,而且必须是唯一标识。

NextTick

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新。如果我们一直修改相同数据,异步操作队列还会进行去重
等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新。

举个例子

```
for(let i=0; i<100000; i++){
    num = i
}
```

如果没有 nextTick 更新机制,那么 num 每次更新值都会触发视图更新(上面这段代码也就是会更新10万次视图),有了nextTick机制,只需要更新一次。

如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()
组件内使用 vm.$nextTick() 实例方法只需要通过this.$nextTick(),并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

mixin

mixin(混入),提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。

本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如datacomponentsmethodscreatedcomputed等等

我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来

比如弹窗提示;alert警告

keep-alive

keep-alivevue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM

keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activateddeactivated):

  • 首次进入组件时:beforeRouteEnter > beforeCreate > created> mounted > activated > … … > beforeRouteLeave > deactivated
  • 再次进入组件时:beforeRouteEnter >activated > … … > beforeRouteLeave > deactivated

缓存后如何获取数据

看上方钩子即可:解决方案可以有以下两种:

  • beforeRouteEnter
  • actived

常用修饰符

vue中修饰符分为以下五种:

  • 表单修饰符

    lazy:在我们填完信息,光标离开标签的时候,才会将值赋予给`value`,也就是在`change`事件之后再
    进行信息同步
    trim:自动过滤用户输入的首空格字符,而中间的空格不会过滤
    number:自动将用户的输入值转为数值类型
    
  • 事件修饰符

         stop:阻止事件冒泡
         prevent:阻止了事件的默认行为,如URL点击跳转
         self:只当在 `event.target` 是当前元素自身时触发处理函数
         once:绑定了事件以后只能触发一次
         capture:使事件触发从包含这个元素的顶层开始往下触发
         passive:在移动端,当我们在监听元素滚动事件的时候,会一直触发`onscroll`事件会让我们
                  的网页变卡,因此我们使用这个修饰符的时候,相当于给`onscroll`事件整了一个
                  `.lazy`修饰符
         native:让组件变成像`html`内置标签那样监听根元素的原生事件
    
  • 鼠标按键修饰符

    鼠标按钮修饰符针对的就是左键、右键、中键点击

  • 键值修饰符

    键盘修饰符是用来修饰键盘事件(onkeyuponkeydown

  • v-bind修饰符

自定义指令

v-开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。

全局注册主要是通过Vue.directive方法进行注册,Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数。

    Vue.directive('focus', {
      // 当被绑定的元素插入到 DOM 中时……
      inserted: function (el) {
        // 聚焦元素
        el.focus()  // 页面加载完成之后自动让输入框获取到焦点的小功能
      }
    })

局部注册通过在组件options选项中设置directive属性
使用方法如下

<input v-focus />

几个常见的自定义指令

  • 表单防止重复提交
  • 图片懒加载
  • 一键 Copy的功能

过滤器(Vue3中已废弃)

vue3中,官方建议:用方法调用或计算属性替换过滤器。 推断可能原因是是vue3要精简代码,并且filter功能重复,filter能实现的功能,methods和计算属性基本上也可以实现。把filter这方面的vue源码给删掉,这样的话,更加方便维护。

过滤器实质不改变原始数据,只是对数据进行加工处理后返回过滤后的数据再进行调用处理,也可以理解其为一个纯函数,不过Vue3中已废弃filter

  • 部过滤器优先于全局过滤器被调用
  • 一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右

平时开发中,需要用到过滤器的地方有很多,比如单位转换、数字打点、文本格式化、时间格式化之类的等。

虚拟DOM

由于在浏览器中操作 DOM 是很昂贵的。频繁的操作 DOM,会产⽣⼀定的性能问题. 所以在vue中将真实的DOM节点抽离成⼀个虚拟的DOM树,这个虚拟的DOM树就是虚拟DOM 。

虚拟DOM将DOM树转换成一个JS对象树,diff算法逐层比较,删除,添加操作,但是,如果有多个相同的元素,可能会浪费性能,所以,react和vue-for引入key值进行区分。

vue是通过createElement生成VNode

虚拟DOM的优点

  1. 可以减少DOM操作:搭配diff算法,
  2. 能跨平台渲染:虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

DIff 算法(重点)

diff 算法是一种通过同层的树节点进行比较的高效算法,它避免了对树进行逐层搜索遍历,所以时间复杂度只有 O(n)。
有两个特点

  1. 比较只会在同层级进行, 不会跨层级比较。
  2. 在 diff 比较的过程中,循环从两边向中间收拢。 (仔细看看

vue项目中封装axios(重点)

axios 是一个轻量的 HTTP客户端。
基于 XMLHttpRequest 服务来执行 HTTP 请求,支持丰富的配置,支持 Promise,支持浏览器端和 Node.js 端。

有以下几个特性:

  • 从浏览器中创建 XMLHttpRequests
  • node.js 创建 http请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换JSON 数据
  • 客户端支持防御XSRF

为什么要封装axios

每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍。

重复劳动不仅浪费时间,而且让代码变得冗余不堪,难以维护。为了提高我们的代码质量,我们应该在项目中二次封装一下 axios 再使用。

请求拦截器: 根据请求的请求头设定,来决定哪些请求可以访问
请求拦截器可以在每个请求里加上token,做了统一处理后维护起来也方便

响应拦截器: 这块就是根据 后端返回来的状态码判定执行不同业务
响应拦截器可以在接收到响应后先做一层操作,如根据状态码判断登录状态、授权

Vue实例挂载的过程

  • new Vue的时候调用会调用_init方法

    • 定义 $set$get$delete$watch 等方法
    • 定义 $on$off$emit$off等事件
    • 定义 _update$forceUpdate$destroy生命周期
  • 调用$mount进行页面的挂载

  • 挂载的时候主要是通过mountComponent方法

  • 定义updateComponent更新函数

  • 执行render生成虚拟DOM

  • _update将虚拟DOM生成真实DOM结构,并且渲染到页面中

生命周期

image.png

beforeCreate -> created

  • 初始化vue实例,进行数据观测

created

  • 完成数据观测,属性与方法的运算,watchevent事件回调的配置
  • 可调用methods中的方法,访问和修改data数据触发响应式渲染dom,可通过computedwatch完成数据计算
  • 此时vm.$el 并没有被创建

created -> beforeMount

  • 判断是否存在el选项,若不存在则停止编译,直到调用vm.$mount(el)才会继续编译
  • 优先级:render > template > outerHTML
  • vm.el获取到的是挂载DOM

beforeMount

  • 在此阶段可获取到vm.el
  • 此阶段vm.el虽已完成DOM初始化,但并未挂载在el选项上

beforeMount -> mounted

  • 此阶段vm.el完成挂载,vm.$el生成的DOM替换了el选项所对应的DOM

mounted

  • vm.el已完成DOM的挂载与渲染,此刻打印vm.$el,发现之前的挂载点及内容已被替换成新的DOM

beforeUpdate

  • 更新的数据必须是被渲染在模板上的(eltemplaterender之一)
  • 此时view层还未更新
  • 若在beforeUpdate中再次修改数据,不会再次触发更新方法

updated

  • 完成view层的更新
  • 若在updated中再次修改数据,会再次触发更新方法(beforeUpdateupdated

beforeDestroy

  • 实例被销毁前调用,此时实例属性与方法仍可访问

destroyed

  • 完全销毁一个实例。可清理它与其它实例的连接,解绑它的全部指令及事件监听器
  • 并不能清除DOM,仅仅销毁实例

双向绑定(重点)

单向绑定:把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。
双向绑定:在单向绑定的基础上,用户更新了ViewModel的数据也自动被更新了,这种情况就是双向绑定。

双向绑定由三个重要部分构成

  • 数据层(Model):应用的数据及业务逻辑
  • 视图层(View):应用的展示效果,各类UI组件
  • 业务逻辑层(ViewModel):框架封装的核心,它负责将数据与视图关联起来

ViewModel
它的主要职责就是:数据变化后更新视图,视图变化后更新数据。
它还有两个主要部分组成

监听器(Observer):对所有数据的属性进行监听
解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

流程(重点)

  1. new Vue()首先执行初始化,对data执行响应化处理,这个过程发生Observe
  2. 同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile
  3. 同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数
  4. 由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher
  5. 将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

image.png

组件化

1.什么是组件化

一句话来说就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue中每一个.vue文件都可以视为一个组件

2.组件化的优势

  • 降低整个系统的耦合度
  • 调试方便
  • 提高可维护性

vue中解决跨域问题

跨域的问题之前我总结过几个方法。
vue项目中,主要针对CORSProxy这两种方案进行展开

CORS

CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应

CORS 实现起来非常方便,只需要增加一些 HTTP 头,让服务器能声明允许的访问来源,只要后端实现了 CORS,就实现了跨域

Proxy

代理(Proxy)也称网络代理,是一种特殊的网络服务,允许一个(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。

vue项目本地开发完成后部署到服务器后报404

场景vue项目在本地时运行正常,但部署到服务器中,刷新页面,出现了404错误

HTTP 404 错误意味着链接指向的资源不存在,问题在于为什么不存在?且为什么只有history模式下会出现这个问题?

Vue是属于单页应用(single-page application)

SPA是一种网络应用程序或网站的模型,所有用户交互是通过动态重写当前页面,即不管应用有多少页面,构建物都只会产出一个index.html

当我们在地址栏输入 www.xxx.com 时,这时会打开我们 dist 目录下的 index.html 文件,然后我们在跳转路由进入到 www.xxx.com/login

关键在这里,当我们在 website.com/login 页执行刷新操作,nginx location 是没有相关配置的,所以就会出现 404 的情况

为什么hash模式下没有问题

router hash 模式是用符号#表示的,如 website.com/#/login, hash 的值为 #/login

它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面

hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 website.com/#/login 只有 website.com 会被包含在请求中 ,因此对于服务端来说,即使没有配置location,也不会返回404错误。

解决方案

产生问题的本质是因为路由是通过JS来执行视图切换的,当进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404,所以只需要配置将任意页面都重定向到 index.html

这么做以后,服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件

为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面

vue3和vue2的一些主要区别。

  1. 速度更快

  2. 体积减少:通过webpacktree-shaking功能,可以将无用模块“剪辑”,仅打包需要的

  3. 更易维护:compositon Api

  4. 更接近原生

  5. 更易使用:响应式 Api 暴露出来

  6. 更好的Typescript支持

Vue 3 中需要关注的一些新功能包括

  1. framents: 在 Vue3.x 中,组件现在支持有多个根节点
  2. Teleport:
  3. composition Api: 组合式api,通过这种形式,我们能够更加容易维护我们的代码,将相同功能的变量进行一个集中式的管理
  4. createRenderer:构建自定义渲染器,能够将 vue 的开发模型扩展到其他平台

其他改变

  • destroyed 生命周期选项被重命名为 unmounted
  • beforeDestroy 生命周期选项被重命名为 beforeUnmount
  • [prop default工厂函数不再有权访问 this 是上下文
  • 自定义指令 API 已更改为与组件生命周期一致
  • data 应始终声明为函数
  • 来自 mixindata 选项现在可简单地合并
  • attribute 强制策略已更改
  • 一些过渡 class 被重命名
  • 组建 watch 选项和实例方法 $watch不再支持以点分隔的字符串路径。请改用计算属性函数作为参数。
  • <template> 没有特殊指令的标记 (v-if/else-if/elsev-forv-slot) 现在被视为普通元素,并将生成原生的 <template> 元素,而不是渲染其内部内容。
  • Vue 2.x 中,应用根容器的 outerHTML 将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。Vue 3.x 现在使用应用容器的 innerHTML,这意味着容器本身不再被视为模板的一部分。

移除的 API(重点)

  • keyCode 支持作为 v-on 的修饰符
  • $on$off$once 实例方法
  • 过滤filter
  • 内联模板 attribute
  • $destroy 实例方法。用户不应再手动管理单个Vue 组件的生命周期。

剩下的其它知识占位,先总结到这里

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

icecream_cheese

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值