Vue 面试题整理

1.css 只在当前组件起作用?
答: 在 style 标签中写入 scoped 即可 例如:<style scoped></style>

2.v-if 和 v-show 区别?
答:v-if 按照条件是否渲染,v-show 是 display 的 block 或 none;
v-if 操作的是元素的创建和插入,v-show 操作的是元素的 display 属性。v-show 具有更高的初始渲染开销,
v-if 具有更高的切换开销。因此在程序运行过程中条件很少发生改变时使用 v-if,需要频繁的切换则使用 v-show,
v-if 用于后台的权限列表,v-show 用于前台数据展示和选项卡

3.route 和 router 的区别?
答: route 是路由信息对象,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数。
而 router 是“路由实例”对象包括了路由的跳转方法,钩子函数等。

4.vue.js 的两个核心是什么?
答: 数据驱动、组件系统

5.vue 几种常用的指令?
答: v-for、v-if、v-bind、v-on、v-show、v-else、v-model

6.vue 常用的修饰符?
答: .prevent: 提交事件不再重载页面;
.stop: 阻止单击事件冒泡;
.self: 当事件发生在该元素本身而不是子元素的时候会触发;
.capture: 事件侦听,事件发生的时候会调用

7.v-on 可以绑定多个方法吗?
答: 可以

8.vue 中 key 值的作用?
答: key 的作用主要是为了高效的更新虚拟 DOM。
当页面的数据发生变化时,Diff 算法只会比较同一层级的节点:
如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。
如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。

9.什么是 vue 的计算属性?
答: 在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,计算属性还可以依赖多个 Vue 实例的数据,
只要其中任一数据变化,计算属性就会重新执行,视图也会更新。在模板中放入太多的逻辑会让模板过重且难以维护。
在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。
好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部 this 指向 vm 实例;
④在 template 调用时,直接写计算属性名即可;⑤常用的是 getter 方法,获取数据,也可以使用 set 方法改变数据;
⑥相较于 methods,不管依赖的数据变不变,methods 都会重新计算,但是依赖数据不变的时候 computed 从缓存中获取,不会重新计算。

10.vue 等单页面应用及其优缺点?
答: 优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。
MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。
缺点:不支持低版本的浏览器,最低只支持到 IE9;不利于 SEO 的优化(如果要支持 SEO,
建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮
需要自行实现前进、后退。

11.怎么定义 vue-router 的动态路由? 怎么获取传过来的值
答: 在 router 目录下的 index.js 文件中,对 path 属性加上 /:id,使用 this.$route.params.id 获取。

12.vue 初始化页面闪动问题
答: 首先:在 css 里加上[v-cloak] {
display: none;
}。
如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display:'block'}"

13.如何获取 dom?
答: ref="domName" 用法:this.$refs.domName

14.$nextTick 的使用?
答: 当你修改了 data 的值后是不能立刻获取这个 dom 元素更新后的值的,
你需要使用 $nextTick 这个回调,让修改后的 data 值渲染更新到 dom元 素之后在才能成功获取。

15.vue 组件中 data 为什么必须是一个函数?
答: 首先对象是引用数据类型,如果data是一个对象那么就会造成,使用同一个地址多个 data 数据复用,
如果 data 是一个函数,那么每次调用的时候都会返回一个新的对象,这样每个组件会维护各自的 data 数据。

16.v-if 和 v-for 的优先级?
答: 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运用于每个
v-for 循环中。所以,不推荐v-if和v-for同时使用。
如果 v-if 和 v-for 一起用的话,vue 中的的会自动提示 v-if 应该放到外层去。

17.assets 和 static 的区别?
答: 相同点:assets 和 static 两个都是存放静态资源文件。存放项目中所需要的资源文件图片,字体图标,
样式文件等
不相同点:assets 中存放的静态资源文件在项目打包时,会将其中的静态资源文件进行打包上传,
static 中放置的静态资源文件就不会走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传到服务器。
在打包时会提高一定的效率,但是文件体积也会较大。在服务器中就会占据更多的空间。

18.vue 和 jQuery 的区别?
答: jQuery 是使用选择器($)选取 DOM 对象,对其进行赋值、取值、事件绑定等操作。数据和界面是在一起的。
Vue 则是通过 Vue 对象将数据和 View 完全分离开来了。对数据进行操作不再需要引用相应的 DOM 对象。

19.delete 和 Vue.delete 删除数组的区别?
答: delete 只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
Vue.delete 直接删除了数组,改变了数组的键值。

20.Vue-router 跳转和 location.href 有什么区别?
答: 使用 location.href='/url' 来跳转,简单方便,但是刷新了页面;
使用 history.pushState('/url'),无刷新页面,静态跳转;
引进 router,然后使用 router.push('/url') 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom 的消耗。

21.vue slot?
答: 当组件当做标签被使用的时候,如果组件内部需要嵌套内容的时候,使用 template 进行包裹内容,在组件内部使用 slot 标签进行接收。

22.你们 vue 项目是打包了一个 js 文件,一个 css 文件,还是有多个文件?
答: 根据 vue-cli 脚手架规范,一个 js 文件,一个 CSS 文件。

23.Vue 里面 router-link 在电脑上有用,在安卓上没反应怎么解决?
答: Vue 路由在 Android 机上有问题,babel 问题,安装 babel polypill 插件解决。

24.Vue2 中注册在 router-link 上事件无效解决方法?
答: 使用 @click.native。原因:router-link 会阻止 click 事件,.native 指直接监听一个原生事件。

25.router-link 在 IE 和 Firefox 中不起作用(路由不跳转)的问题?
答: 方法一:只用 a 标签,不适用 button 标签;方法二:使用 button 标签和 Router.navigate 方法

26.vue-router 是什么?它有哪些组件?
答: vue 用来写路由的一个插件。router-link、router-view

27.active-class 是哪个组件的属性?
答: vue-router 模块的 router-link 组件的属性。

28.vue-router 有哪几种导航钩子?
答: 三种,
第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
第二种:组件内的钩子:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
第三种:单独路由独享组件:beforeEnter

29.vuex 有哪几种属性?
答: 有五种,分别是 State、 Getter、Mutation 、Action、 Module
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex

30.Vue.js 中 ajax 请求代码应该写在组件的 methods 中还是 vuex 的 actions 中?
答: 如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放在 vuex 中。
如果被其他地方复用,将请求放在 action 里,方便复用。

31.keep-alive 缓存组件的理解?
答: 多个组件共用一个挂载点,并且可以动态切换,使用 keep-alive 包裹的组件,
可以缓存,下一次在加载时可以直接从缓存中读取。
当使用了 keep-alive 内置组件后组件会增加 Actived 和 deactived 两个生命周期,
组件显示,处于活跃状态是 actived,缓存状态是 deactived。

32.什么是 MVVM?
答: MVVM 是 Model-View-ViewModel 的缩写,Model 代表数据模型,定义数据操作的业务逻辑,
View 代表视图层,负责将数据模型渲染到页面上,ViewModel 通过双向绑定把 View 和 Model 进行同步交互,
不需要手动操作 DOM 的一种设计思想。

33.MVVM 和 MVC 区别?和其他框架(jquery)区别?那些场景适用?
答: MVVM 和 MVC 都是一种设计思想,主要就是 MVC 中的 Controller 演变成 ViewModel,
MVVM 主要通过数据来显示视图层而不是操作节点,解决了 MVC 中大量的 DOM 操作使页面渲染性能降低,
加载速度慢,影响用户体验问题。主要用于数据操作比较多的场景。

34.Vue的双向数据绑定原理是什么?
答: vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()
来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上
setter 和 getter,这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能
监听到了数据变化。
第二步:compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,
并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
第三步:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:
在自身实例化时往属性订阅器(dep)里面添加自己
自身必须有一个 update() 方法
待属性变动 dep.notice()通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。
第四步:MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的
model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,
达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。
js实现简单的双向绑定:

1 <body> 
2   <div id="app"> 
3     <input type="text" id="txt">
4     <p id="show"></p>
5   </div>
6 </body>
7 <script type="text/javascript">
8   var obj = {}
9   Object.defineProperty(obj, 'txt', {
10     get: function () {
11       return obj
12     },
13     set: function (newValue) {
14       document.getElementById('txt').value = newValue
15       document.getElementById('show').innerHTML = newValue
16     }
17   })
18   document.addEventListener('keyup', function (e) {
19     obj.txt = e.target.value
20   })
21 </script>

35.请说下封装 vue 组件的过程?
答: 首先,组件可以提升整个项目的开发效率能够把页面抽象成多个相对独立的模块,
解决了我们传统项目开发:效率低,难维护,复用性等问题。
然后,使用 Vue.extend 方法创建一个组件,然后使用 Vue.component 方法注册组件。
子组件需要数据,可以在 props 中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用 emit 方法。

36.聊聊你对 Vue.js 的模板编译的理解?
答: 简而言之,就是先转化成 AST 树,再得到的渲染函数返回 VNODE(Vue公司的虚拟DOM节点)
详情步骤:首先,通过编译器把模板编译成AST语法树(抽象语法树即源代码的抽象语法结构的树状表现形式),
编译是 createCompiler 的返回值,createCompiler 是用于创建编译器的。
负责合并选项。然后,AST 会经过生成(将AST语法树转化成渲染功能字符串的过程)得到渲染函数,渲染的返回值是 VNode,
VNode 是 Vue 的虚拟 DOM 节点,里面有(标签名,子节点,文本等等)。

37.vue 的优点是什么?
答: 低耦合。视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的 "View" 上,
当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
可重复性。你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 view 重用这段视图逻辑。
独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,
使用 Expression Blend 可以很容易设计界面并生成 xml 代码。
可测试。界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。

38.vue 生命周期的理解?
答: beforeCreate
在这个生命周期中,是无法访问到 data 中的属性和 methods 中的方法的,
因此这是生命周期的初始化阶段,可以在这个生命周期中加载 loading
created
在这个生命周期中,可以访问到 data 中的属性和 methods 中的方法的,
会将data的所有属性添加 getter/setter 方法,可以在这个生命周期进行前后端数据交互
beforeMount
在这个生命周期中,数据和模板还未结合,可以在这个生命周期对数据做最后的修改
mounted
在这个生命周期中,数据和模板相结合,可以在这个生命周期中获取真实的 DOM 结构,
可以做方法的实例化(swiper,echarts)
beforeupdate
在这个生命周期中,更新后的数据和模板还未结合,可以在这个生命周期对更新后的数据做最后的修改
updated
在这个生命周期中,更新后的数据和模板结合,可以在这个生命周期中获取更新后的 DOM 结构
beforedestroy
在这个生命周期中仍然可以获取真实的 DOM 结构,可以做事件的移除,事件的解绑
destroyed
在这个生命周期中访问不到真实的 DOM 结构,vue 实例与页面的关系断开

39.vue中组件通讯的方式有哪些?
答: 父传子:当子组件在父组件中当做标签被使用的时候,给当前子组件绑定一个自定义属性,在子组件的内部通过 props 接受父组件传递过来的数据
子传父:当子组件在父组件中当做标签被使用的时候,给当前子组件绑定一个自定义的方法,在子组件内部通过 this.$emit() 调用方法,传递数据
非父子:
eventBus
Vuex

40.组件之间的传值?
答: 父组件与子组件传值:

1 //父组件通过标签上面定义传值
2 <template> 
3   <Main :obj="data"></Main> 
4 </template> 
5 <script> 
6   //引入子组件
7   import Main form "./main"
8
9   exprot default{
10     name:"parent",
11     data(){
12       return {
13         data:"我要向子组件传递数据"
14       }
15     },
16     //初始化组件
17     components:{
18       Main
19     }
20  }
21 </script>
22
23 //子组件通过 props 方法接受数据
24 <template>
25   <div>{{data}}</div>
26 </template>
27 <script>
28   exprot default{
29     name:"son",
30     //接受父组件传值
31     props:["obj"]
32   }
33 </script>

子组件向父组件传递数据:

1 //子组件通过 $emit 方法传递参数
2 <template> 
3   <div @event="events"></div> 
4 </template> 
5 <script> 
6   //引入子组件
7   import Main form "./main"
8
9   exprot default{
10     methods:{
11       events:function(params){
12         console.log(params)
13       }
14     }
15   }
16 </script>
17
18
19 <template>
20   <div v-on:click="emitEvent">{{data}}</div>
21 </template>
22 <script>
23   exprot default{
24     name:"son",
25     //接受父组件传值
26     props:["data"],
27     methods: {
28       emitEvent() {
29         this.$emit('event', params) // 派发函数,并传递值,params 是你想传的值
30       }
31     }
32   }
33 </script>

41.说出至少 4 种 vue 当中的指令和它的用法?
答: v-if(判断是否隐藏)、v-for(把数据遍历出来)、v-bind(绑定属性)、v-model(实现
双向绑定)

42.简单说一下 Vue2.x 响应式数据原理?
答: Vue 在初始化数据时,会使用 Object.defineProperty 重新定义 data 中的所有属性,当页面使用对应属性时,
首先会进行依赖收集(收集当前组件的 watcher)如果属性发生变化会通知相关依赖进行更新操作(发布订阅)。

43.那你知道 Vue3.x 响应式数据原理吗?
答: Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,
并且有多达 13 种拦截方法。并且作为新标准将受到浏览器厂商重点持续的性能优化。

44.Proxy 只会代理对象的第一层,那么 Vue3 又是怎样处理这个问题的呢?
答: 判断当前 Reflect.get 的返回值是否为 Object,如果是则再通过 reactive 方法做代理,这样就实现了深度观测。

45.监测数组的时候可能触发多次 get/set,那么如何防止触发多次呢?
答: 我们可以判断 key 是否为当前被代理对象 target 自身属性,也可以判断旧值与新值是否相等,
只有满足以上两个条件之一时,才有可能执行 trigger。

46.vue2.x 中如何监测数组变化?
答: 使用了函数劫持的方式,重写了数组的方法,Vue 将 data 中的数组进行了原型链重写,指向了自己定义的数组原型方法。
这样当调用数组 api 时,可以通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。
这样就实现了监测数组变化。

47.你的接口请求一般放在哪个生命周期中?
答: 接口请求一般放在 mounted 中,但需要注意的是服务端渲染时不支持 mounted,需要放到 created 中。

48.Computed 和 Watch?
答: Computed 本质是一个具备缓存的 watcher,依赖的属性发生变化就会更新视图。适用于计算比较消耗性能的计算场景。
当表达式过于复杂时,在模板中放入过多逻辑会让模板难以维护,可以将复杂的逻辑放入计算属性中处理。
Watch 没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,
可以打开 deep:true 选项,这样便会对对象中的每一项进行监听。这样会带来性能问题,优化的话可以使用字符串形式监听,
如果没有写到组件中,不要忘记使用 unWatch 手动注销哦。

49.Vue2.x 和 Vue3.x 渲染器的 diff 算法分别说一下?
答: 简单来说,diff 算法有以下过程

  • 同级比较,再比较子节点
  • 先判断一方有子节点一方没有子节点的情况(如果新的 children 没有子节点,将旧的子节点移除)
  • 比较都有子节点的情况(核心 diff)
  • 递归比较子节点

正常 Diff 两个树的时间复杂度是 O(n^3),但实际情况下我们很少会进⾏跨层级的移动 DOM,所以 Vue 将 Diff 进行了优化,
从 O(n^3) -> O(n),只有当新旧 children 都为多个子节点时才需要用核心的 Diff 算法进行同层级比较。
Vue2 的核心 Diff 算法采用了双端比较的算法,同时从新旧 children 的两端开始进行比较,借助 key 值找到可复用的节点,
再进行相关操作。相比 React 的 Diff 算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。
Vue3.x 借鉴了 ivi 算法和 inferno 算法
在创建 VNode 时就确定其类型,以及在 mount/patch 的过程中采用位运算来判断一个 VNode 的类型,在这个基础之上再配合
核心的 Diff 算法,使得性能上较 Vue2.x 有了提升。(实际的实现可以结合 Vue3.x 源码看。)
该算法中还运用了动态规划的思想求解最长递归子序列。

50.虚拟 Dom 以及 key 属性的作用?
答: 由于在浏览器中操作 DOM 是很昂贵的。频繁的操作 DOM,会产生一定的性能问题。这就是虚拟 Dom 的产生原因。
Vue2 的 Virtual DOM 借鉴了开源库 snabbdom 的实现。
Virtual DOM 本质就是用一个原生的 JS 对象去描述一个 DOM 节点。是对真实 DOM 的一层抽象。(也就是源码中的 VNode类,
它定义在 src/core/vdom/vnode.js 中。)
VirtualDOM 映射到真实 DOM 要经历 VNode 的 create、diff、patch 等阶段。
「key 的作用是尽可能的复用 DOM 元素。」
新旧 children 中的节点只有顺序是不同的时候,最佳的操作应该是通过移动元素的位置来达到更新的目的。
需要在新旧 children 的节点中保存映射关系,以便能够在旧 children 的节点中找到可复用的节点。key 也就是 children 中节点的唯一标识。

51.Vue 中组件生命周期调用顺序说一下?
答: 组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。
组件的销毁操作是先父后子,销毁完成的顺序是先子后父。
加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父组件更新过程
父 beforeUpdate -> 父 updated
销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

52.SSR 了解吗?
答: SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。
优点: ①有着更好的 SEO。 ②首屏加载速度更快。
缺点: ①开发条件会受到限制,服务器端渲染只支持 beforeCreate 和 created 两个钩子。
②服务端渲染应用程序需要处于 Node.js 的运行环境。③服务器会有更大的负载需求。

53.你都做过哪些 Vue 的性能优化?
答: 编码阶段

  • 尽量减少 data 中的数据,data 中的数据都会增加 getter 和 setter,会收集对应的 watcher
  • v-if 和 v-for不能连放在一起用
  • 如果需要使用 v-for 给每项元素绑定事件时使用事件代理
  • SPA 页面采用 keep-alive 缓存组件
  • 在更多的情况下,使用 v-if 替代 v-show
  • key 保证唯一
  • 使用路由懒加载、异步组件
  • 防抖、节流
  • 第三方模块按需导入
  • 长列表滚动到可视区域动态加载
  • 图片懒加载
    SEO 优化
  • 预渲染
  • 服务端渲染 SSR
    打包优化
  • 压缩代码
  • Tree Shaking/Scope Hoisting
  • 使用 cdn 加载第三方模块
  • 多线程打包 happypack
  • splitChunks 抽离公共文件
  • sourceMap 优化
    用户体验
  • ⻣架屏
  • PWA
    还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启 gzip 压缩等。

54.hash 路由和 history 路由实现原理说一下?
location.hash 的值实际就是 URL 中 # 后面的东西。
history 实际采用了 HTML5 中提供的 API 来实现,主要有 history.pushState() 和 history.replaceState()

posted @ 2021-04-20 20:55  `Duet`  阅读(371)  评论(0编辑  收藏  举报