Vue面试题整理汇总

1、面试官:简述MVVM?

MVVM表示的是 Model-View-ViewModel,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。以前是操作DOM结构更新视图,现在是数据驱动视图。

MVVM的优点:

1.低耦合。视图(View)可以独立于Model变化和修改,一个Model可以绑定到不同的View上,当View变化的时候Model可以不变化,当Model变化的时候View也可以不变;

2.可重用性。你可以把一些视图逻辑放在一个Model里面,让很多View重用这段视图逻辑。

3.独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。

4.可测试。

2、面试官:请描述下你对vue生命周期的理解?在created和mounted这两个生命周期中请求数据有什么区别呢?

每个Vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动作或者事件

Vue生命周期总共可以分为8个阶段:创建前后,载入前后,更新前后,销毁前销毁后,以及一些特殊场景的生命周期

生命周期

描述

beforeCreate

组件实例被创建之初,此时data和methods中的数据都还没有初始化,无法用vm访问

created

组件实例已经完全创建,data中有值,未挂载,可以用vm访问

beforeMount

组件挂载之前,页面呈现的是未经Vue编译的DOM结构,可以取数据

Mounted

组件挂载到实例上去之后,此时可以操作DOM,页面呈现的是经Vue编译的DOM结构

beforeUpdate

组件数据发生变化,更新之前,数据是新的,但页面是旧的。

updated

组件数据更新之后,页面和数据保持同步

beforeDestroy

组件实例销毁之前,此时可以手动销毁一些方法

destroyed

组件实例销毁之后

activated

keep-alive 缓存的组件激活时

deactivated

keep-alive 缓存的组件停用时调用

errorCaptured

捕获一个来自子孙组件的错误时被调用

题外话:数据请求在created和mouted的区别

created是在组件实例一旦创建完成的时候立刻调用,这时候页面dom节点并未生成;mounted是在页面dom节点渲染完毕之后就立刻执行的。触发时机上created是比mounted要更早的,两者的相同点:都能拿到实例对象的属性和方法。 讨论这个问题本质就是触发的时机,放在mounted中的请求有可能导致页面闪动(因为此时页面dom结构已经生成),但如果在页面加载前完成请求,则不会出现此情况。建议对页面内容的改动放在created生命周期当中。

3、面试官:你对SPA单页面的理解

单页应用SPA是一种网络应用程序或网站的模型,它通过动态重写当前页面来与用户交互,这种方法避免了页面之间切换打断用户体验。在单页应用中,所有必要的代码(HTML、JavaScript和CSS)都通过单个页面的加载而检索,或者根据需要(通常是为响应用户操作)动态装载适当的资源并添加到页面页面在任何时间点都不会重新加载,也不会将控制转移到其他页面。

我们熟知的JS框架如react,vue,angular都属于SPA

4、面试官:v-show和v-if有什么区别?使用场景分别是什么?

在 vue 中 v-show 与 v-if 的作用效果是相同的,都能控制元素在页面是否显示

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

区别:

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

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

3、v-show 由false变为true的时候不会触发组件的生命周期

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法

性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

v-show与v-if的使用场景

如果需要非常频繁地切换,则使用 v-show 较好

如果在运行时条件很少改变,则使用 v-if 较好

5、面试官:Vue实例挂载的过程

1、new Vue的时候调用会调用_init方法

定义 $set、$get、$delete、$watch 等方法

定义 $on、$off、$emit、$off等事件

定义 _update、$forceUpdate、$destroy生命周期

2、调用$mount进行页面的挂载

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

4、定义updateComponent更新函数

5、执行render生成虚拟DOM

6、update将虚拟DOM生成真实DOM结构,并且渲染到页面中

6、面试官:v-if和v-for的优先级是什么?

v-if指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true值的时候被渲染 。

v-for指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组或者对象,而 item 则是被迭代的数组元素的别名

在 v-for 的时候,建议设置key值,并且保证每个key值是独一无二的,这便于diff算法进行优化。

1.当 v-for 和 v-if 处于同一个节点时,v-for 的优先级比v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。如果要遍历的数组很大,而真正要展示的数据很少时,这将造成很大的性能浪费(Vue2.x)

2.这种场景建议使用 computed,先对数据进行过滤

7、面试官:组件中的data为什么是一个函数?

1.一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。

2.如果data是对象的话,对象属于引用类型,会影响到所有的实例造成数据污染。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。

8、面试官:动态给vue的data添加一个新的属性时会发生什么?怎样解决?

直接添加属性数据虽然更新了,但页面并没有更新

因为vue2是用Object.defineProperty实现数据响应式,当我们访问或者设置数据的时候都能够触发setter与getter,但是我们为obj添加新属性的时候,却无法触发事件属性的拦截

原因是一开始obj的旧属性被设成了响应式数据,而后面新增的属性并没有通过Object.defineProperty设置成响应式数据

解决方案:

若想实现数据与视图同步更新,可采取下面三种解决方案:

Vue.set()     //Vue.set( target, propertyName, value )
Object.assign()  //创建一个新的对象,合并原对象和混入对象的属性
$forcecUpdated()   //在Vue中做一次强制更新

9、面试官:Vue中组件和插件有什么区别?

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

插件通常用来为Vue 添加全局功能

两者的区别主要表现在以下几个方面:

1、编写形式 2、注册形式 3、使用场景

编写形式:组件的编写形式为<template><script><style>的vue单文件形式

而vue插件的实现应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象

注册形式:vue组件注册主要分为全局注册与局部注册,插件的注册通过Vue.use()的方式进行注册

使用场景

组件 (Component) 是用来构成你的 App 的业务模块,它的目标是App.vue

插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身

简单来说,插件就是指对Vue的功能的增强或补充

10、面试官:双向数据绑定是什么

单向绑定:把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。因此,我们不需要进行额外的DOM操作,只需要进行Model的操作就可以实现视图的联动更新。(v-bind形式)

双向绑定:把Model绑定到View的同时也将View绑定到Model上,这样就既可以通过更新Model来实现View的自动更新,也可以通过更新View来实现Model数据的更新。所以,当我们用JavaScript代码更新Model时,View就会自动更新,反之,如果用户更新了View,Model的数据也自动被更新了。(v-model形式)

主要靠ViewModel的监听器和解析器实现数据双向绑定

11、面试官:Vue组件之间的通信方式都有哪些?

vue中8种常规的通信方案:

1、通过props 传递(父组件传子组件)

父组件在使用子组件标签中通过字面量来传递值,如<son:msg="msgData" ></son>

子组件设置props属性,定义接收父组件传递过来的参数。 如props:["msg"]

2、通过$emit 触发自定义事件(子组件传父组件)

子组件通过$emit触发自定义事件,$emit第二个参数为传递的数值

this.$emit('add',good) // 触发父组件的方法,并传递参数good

父组件绑定监听器获取到子组件传递过来的参数

<Children@add="cartAdd($event)" />

3、使用ref (子组件传父组件)

父组件在使用子组件的时候设置ref

父组件通过设置子组件ref来获取数据

<Childrenref="foo" />

this.$refs.foo // 获取子组件实例,通过子组件实例我们就能拿到对应的数据

4、全局事件总线(父子组件、非父子组件)

eventBus事件总线适用于父子组件、非父子组件等之间的通信

创建一个全局事件总线EventBus

发送组件通过$emit触发自定义事件,$emit第二个参数为传递的数值

接收组件通过$on监听自定义事件

5、依赖注入(provide/ inject)(父子组件、祖孙组件)

在祖先组件定义provide属性,返回传递的值

在后代组件通过inject接收组件传递过来的值

6、vuex

Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。

7、$parent/ $children

使用$parent可以让组件访问父组件的实例

使用 $children 可以让组件访问子组件的实例

8、$attrs/ $listeners

适用场景:祖先传递数据给子孙

设置批量向下传属性$attrs和 $listeners

包含了父级作用域中不作为 prop 被识别 (且获取)的特性绑定

可以通过v-bind="$attrs" 传⼊内部组件

12、面试官:Vue中的$nextTick有什么作用?

vue的dom更新是异步的,并不是数据发生改变之后dom就立即改变,而是等同一事件循环中的所有数据变化完成之后,在统一进行视图的更新。

$nextTick()使用的场景:

created阶段的dom是没有生成渲染的,这个时候我们要在这个生命周期里面获取dom的话,就可以使用nextTick方法就获取

mounted阶段,如果需要操作渲染后的视图,要使用nextTick方法,因为在mounted钩子里面不会承诺其子组件也挂载完毕

$nextTick()原理及其使用

将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

13、面试官:说说你对vue的mixin的理解,有什么应用场景?

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

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

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

在Vue中我们可以局部混入和全局混入

14、面试官:说说你对slot的理解?slot使用场景有哪些?

vue中的插槽是一个非常好用的东西,slot简单说就是一个占位的,在vue当中插槽包含三种,一种是默认插槽(匿名),一种是具名插槽,还有一种就是作用域插槽 ,匿名插槽就是没有名字的只要默认的都填到这里,具名插槽指的是具有名字的,作用域插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。

子组件用<slot>标签来确定渲染的位置,父组件使用

通过插槽可以让用户可以拓展组件,去更好地复用组件和对其做定制化处理

15、面试官:Vue.observable你有了解过吗?说说看

Observable翻译过来我们可以理解成可观察的

在Vue中的定义:

Vue.observable,让一个对象变成响应式数据。Vue 内部会用它来处理data 函数返回的对象

返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器

在 Vue 2.x 中,被传入的对象会直接被 Vue.observable 变更,它和被返回的对象是同一个对象

使用场景

在非父子组件通信时,可以使用通常的bus或者使用vuex,但是实现的功能不是太复杂,而使用上面两个又有点繁琐。这时,observable就是一个很好的选择

16、面试官:你知道vue中key的原理吗?说说你对它的理解

key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度,更高效的更新虚拟DOM;

vue和react都是采用diff算法来对比新旧虚拟节点,从而更新节点。在vue的diff函数中,会根据新节点的key去对比旧节点数组中的key,从而找到相应旧节点。如果没找到就认为是一个新增节点。而如果没有key,那么就会采用遍历查找的方式去找到对应的旧节点。一种一个map映射,另一种是遍历查找。相比而言。map映射的速度更快。

17、面试官:说说你对keep-alive的理解是什么?

keep-alive是vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们

<keep-alive>
  <component ></component>
</keep-alive>

场景:当我们在某些场景下不需要让页面重新加载时我们可以使用keepalive

如tabs标签页 后台导航,vue性能优化

原理:Vue.js内部将DOM节点抽象成了一个个的VNode节点,keep-alive组件的缓存也是基于VNode节点的而不是直接存储DOM结构。它将满足条件(pruneCache与pruneCache)的组件在cache对象中缓存起来,在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染。

18、面试官:Vue常用的修饰符有哪些?有什么应用场景

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

1、表单修饰符 2、事件修饰符3、鼠标按键修饰符 4、键值修饰符 5、v-bind修饰符

一、表单修饰符

lazy: 在我们填完信息,光标离开标签的时候,才会将值赋予给value (v-model.lazy)

trim: 自动过滤用户输入的首空格字符,而中间的空格不会过滤 (v-model.trim)

number:自动将用户的输入值转为数值类型 (v-model.number)

二、事件修饰符

stop:阻止了事件冒泡,相当于调用了event.stopPropagation方法 (@click.stop)

prevent:阻止了事件的默认行为,相当于调用了event.preventDefault方法(@.prevent)

self:只当在 event.target 是当前元素自身时触发处理函数 (@click.self)

once:绑定了事件以后只能触发一次,第二次就不会触发 (@click.once)

capture:使事件触发从包含这个元素的顶层开始往下触发

passive:在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符

native:让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用 v-on 只会监听自定义事件

三、鼠标按钮修饰符

left左键点击 right 右键点击 middle 中键点击 例(@click.left)

四、键盘修饰符

键盘修饰符是用来修饰键盘事件(onkeyup,onkeydown)的 (@keyup.keyCode)

五、v-bind修饰符

v-bind修饰符主要是为属性进行操作,简写为冒号

19、面试官:你有写过自定义指令吗?自定义指令的应用场景有哪些?

除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令,全局注册主要是通过Vue.directive方法进行注册,Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数

局部注册通过在组件options选项中设置directive属性

//注册一个全局自定义指令 `v-focus`
Vue.directive('focus',{
  // 当被绑定的元素插入到DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
  }
})
directives:{          //局部注册
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus

应用场景

1、表单防止重复提交2、图片懒加载3、一键 Copy的功能

20、面试官:Vue中的过滤器了解吗?过滤器的应用场景有哪些?

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

vue中的过滤器可以用在两个地方:双花括号插值和 v-bind 表达式,过滤器应该被添加在 JavaScript表达式的尾部,由“管道”符号指示

在组件的选项中定义本地的过滤器

filters:{
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() +value.slice(1)
  }
}
过滤器可以串联:
{
    
    {message | filterA | filterB }}

定义全局过滤器:

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  // ...
})

应用场景

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

21、面试官:什么是虚拟DOM?如何实现一个虚拟DOM?说说你的思路

什么是虚拟DOM

实际上它只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上

为什么需要虚拟DOM

操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验

而通过VNode,同样更新10个DOM节点,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,避免大量的无谓计算

虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种GUI

如何实现一个虚拟DOM

createElement创建 VNode 的过程,每个 VNode 有 children,children 每个元素也是一个VNode,这样就形成了一个虚拟树结构,用于描述真实的DOM树结构

22、面试官:你了解vue的diff算法吗?说说看

diff算法在什么时候运行呢?当我们当前组件所依赖的数值更新和组件创建时运行update函数,update函数会调用组件的render函数,render生成新的虚拟dom树,update将旧虚拟dom树替换成新的虚拟dom树,然后用一个变量将旧虚拟dom树保存起来,接下来调用patch函数进行diff比对

然后vue的diff会根据新旧domTree进行深度优先同层比对,如果父节点比对发现不同则父节点的所有子节点无需进行比对跟着父节点一起死去,如果父节点比对发现相同则继续往下比对父节点的子节点然后再进行下一个父节点的子节点进行比较,以此递归比较下去,比较时首先会比较标签名是否一致,然后会比较元素的key值是否相同,如果是input元素则还会比较type类型,如果都相同表示相同,如果有一个不相同表示不相同,vue的diff算法会在新旧dom树的头尾处记录头尾指针位置,相互聚拢,逐渐比较,来保证真实dom的高复用,当新虚拟dom树的头指针大于新虚拟dom树的尾指针则表示新虚拟dom树比对完成,diff结束,然后vue会根据新虚拟dom树的比对结果的真实dom树加入根节点中完成页面真实dom渲染完毕

23、面试官:Vue项目中有封装过axios吗?主要是封装哪方面的?

有封装过axios, axios每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍。这种重复劳动不仅浪费时间,而且让代码变得冗余不堪,难以维护。为了提高我们的代码质量,我们应该在项目中二次封装一下 axios 再使用

封装方面:

1、设置接口请求前缀:利用node环境变量来作判断,用来区分开发、测试、生产环境

2、设置请求头与超时时间

3、封装请求方法:先引入封装好的方法,在要调用的接口重新封装成一个方法暴露出去,把封装的方法放在一个api.js文件中

4、请求拦截器:请求拦截器可以在每个请求里加上token,做了统一处理后维护起来也方便

5、响应拦截器:可以在接收到响应后先做一层操作,如根据状态码判断登录状态、授权

24、面试官:你了解axios的原理吗?

实现一个简易版axios,之后导出axios实例,得到最后的全局变量axios

classAxios {
    constructor() {
 
    }
    request(config) {
        return new Promise(resolve => {
            const {url = '', method = 'get',data = {}} = config;
            // 发送ajax请求
            const xhr = new XMLHttpRequest();
            xhr.open(method, url, true);
            xhr.onload = function() {
                console.log(xhr.responseText)
                resolve(xhr.responseText);
            }
            xhr.send(data);
        })
    }
}
//最终导出axios的方法,即实例的request方法
functionCreateAxiosFn() {
    let axios = new Axios();
    let req = axios.request.bind(axios);
    return req;
}
 
//得到最后的全局变量axios
letaxios = CreateAxiosFn();

25、面试官:SSR解决了什么问题?

Server-SideRendering 我们称其为SSR,意为服务端渲染

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

传统web开发:网页内容在服务端渲染完成,⼀次性传输到浏览器

单页应用SPA:单页应用优秀的用户体验,使其逐渐成为主流,页面内容由JS渲染出来,这种方式称为客户端渲染

SSR解决方案,后端渲染出完整的首屏的dom结构返回,前端拿到的内容包括首屏及完整spa结构,应用激活后依然按照spa方式运行

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

1、有利于seo

2、首屏呈现渲染:用户无需等待页面所有js加载完成就可以看到页面视图(压力来到了服务器,所以需要权衡哪些用服务端渲染,哪些交给客户端)

26、面试官:说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢?

使用vue构建项目,项目结构清晰会提高开发效率,熟悉项目的各种配置同样会让开发效率更高,在划分项目结构的时候,需要遵循一些基本的原则:

1、文件夹和文件夹内部文件的语义一致性

如pages文件夹,这个文件夹里面应该包含我们项目所有的路由模块,并且仅应该包含路由模块,而不应该有别的其他的非路由模块的文件夹

2、单一入口/出口

无论你的模块文件夹内部有多乱,外部引用的时候,都是从一个入口文件引入

3、就近原则,紧耦合的文件应该放到一起,且应以相对路径引用

4、公共的文件应该以绝对路径的方式从根目录引用

5、/src外的文件不应该被引入

目录结构:

build文件夹,用来存放项目构建脚本

config中存放项目的一些基本配置信息,最常用的就是端口转发

node_modules这个目录存放的是项目的所有依赖,即 npm install 命令下载下来的文件

src这个目录下存放项目的源码,即开发者写的代码放在这里

static用来存放静态资源

index.html则是项目的首页,入口页,也是整个项目唯一的HTML页面

package.json中定义了项目的所有依赖,包括开发时依赖和发布时依赖

src 中的文件目录如下

assets目录用来存放资产文件

components目录用来存放组件(一些可复用,非独立的页面),当然开发者也可以在 components 中直接创建完整页面。

推荐在 components 中存放组件,另外单独新建一个 page 文件夹,专门用来放路由页面。

router目录中,存放了路由的js文件

App.vue是一个Vue组件,也是项目的第一个Vue组件

main.js是整个项目的入口js

27、面试官:vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?

前端权限归根结底是请求的发起权,请求的发起可能有下面两种形式触发

1、页面加载触发 2、页面上的按钮点击触发

一、接口权限

登录完拿到token,将token存起来,通过axios请求拦截器进行拦截,每次请求的时候头部携带token

二、路由权限控制

初始化的时候先挂载不需要权限控制的路由,比如登录页,404等错误页。如果用户通过URL进行强制访问,则会直接进入404,相当于从源头上做了控制。登录后,获取用户的权限信息,然后筛选有权限访问的路由,在全局路由守卫里进行调用addRoutes添加路由

三、按钮权限

按钮权限也可以用v-if判断,也可以通过自定义指令进行按钮权限的判断

四、菜单权限

1、菜单与路由分离,菜单由后端返回

2、菜单和路由都由后端返回

28、面试官:Vue项目中你是如何解决跨域的呢?

跨域本质是浏览器基于同源策略的一种安全手段

同源策略指协议主机端口号都相同才可以进行访问

反之非同源请求,也就是协议、端口、主机其中一项不相同的时候,这时候就会产生跨域

解决跨域的方法有很多JSONP、CORS、Proxy

而在vue项目中,主要针对CORS或Proxy这两种方案进行展开

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

2、Proxy代理服务器

我们可以通过webpack为我们起一个本地服务器作为请求的代理对象,通过该服务器转发请求至目标服务器,得到结果再转发给前端

proxy:{
      '/api': { // '/api'是代理标识,用于告诉node,url前面是/api的就是使用代理的
      target:"http://xxx.xxx.xx.xx:8080", //目标地址,一般是指后台服务器地址
      changeOrigin: true, //是否跨域
      pathRewrite: {         // pathRewrite 的作用是把实际Request Url中的'/api'用""代替
           '^/api': "" 
      }

29、面试官:vue项目本地开发完成后部署到服务器后报404是什么原因呢?

前端常规布署只需要将vue项目构建后生成一系列的静态文件上传至目标服务器即可

HTTP404 错误意味着链接指向的资源不存在,只有history模式下会出现这个问题

在执行刷新操作时,在history模式下是没有相关配置的,所以就会出现 404 的情况

但在hash模式下没有问题因为hash 虽然出现在URL 中,但不会被包括在 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面

解决方案:

产生问题的核心是当我们进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404,所以我们只需要配置将任意页面都重定向到 index.html,把路由交由前端处理即可

30、面试官:你是怎么处理vue项目中的错误的?

主要的错误来源包括:

1、后端接口错误 2、代码中本身逻辑错误

后端接口错误可以通过axios的interceptor实现网络请求的response先进行一层拦截

代码逻辑问题

  1. 设置全局错误处理函数

Vue.config.errorHandler= function (err, vm, info) {
}

errorHandler指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例

2、生命周期钩子

errorCaptured是新增的一个生命钩子函数,当捕获到一个来自子孙组件的错误时被调用

31、Vue常用的指令都有哪些?并且说明其作用

1.v-model

作用: 多用于表单元素实现双向数据绑定

2.v-bind 动态绑定

为元素的属性动态绑定值,一般简写为 :

作用: 及时对页面的数据进行更改

3、v-for 动态渲染

v-for指令基于一个数组来渲染一个列表。建议设置key值,并且保证每个key值是独一无二的,这便于diff算法进行优化

4、v-show 显示内容

v-show的原理是动态为元素添加或移除 `display` 样式,来实现元素的显示和隐藏

5、v-if 显示与隐藏

v-if的原理是动态的在DOM树上创建或移除元素,实现元素的显示和隐藏

6.v-on 给标签绑定函数

可以缩写为@,例如绑定一个点击函数 函数必须写在methods 里面

7、v-text和v-html 解析文本

v-text:用于解析文本,但不能解析标签,并且会覆盖元素内部原有的内容!

v-html:可以把带有标签的字符串,渲染成真正的 HTML 内容!

32 、Vuex的理解及使用场景

Vuex是一个专为 Vue 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store

Vuex的状态存储是响应式的;当 Vue 组件从 store 中读取状态的时候:

1、若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新

2、改变 store 中的状态的唯一途径就是显式地提交mutation,这样使得我们可以方便地跟踪每一个状态的变化 Vuex主要包括以下几个核心模块:

3、State:定义了应用的状态数据

4、Getter:在 store 中定义“getter”(可以认为是 store 的计算属性),

就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来, 且只有当它的依赖值发生了改变才会被重新计算

5、Mutation:是唯一更改 store 中状态的方法,且必须是同步函数

6、Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作

7、Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中

猜你喜欢

转载自blog.csdn.net/weixin_55608297/article/details/129626400