vue2.0经典高频面试题@小四

2018-12-16  本文已影响0人  王云飞_小四_wyunfei

1、vue是一套渐进式框架的理解

2、Vue常用的指令

3、v-if VS v-show区别

4、Vue常用修饰符

5、v-on可以监听多个方法吗

可以,代码如下:

<input type="text" :value="name" @input="onInput" @focus="onFocus" @blur="onBlur" />

6、vue中key值的作用

虚拟DOM见“68题” ,diff算法见“69题”

7、$nextTick的作用

8、Vue组件中的data为什么必须是函数

当我们定义一个 组件时( <button-counter>),你可能会发现它的 data 并不是像这样直接提供一个对象:

data: {
  count: 0
}

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
  return {
    count: 0
  }
}

9、v-for和v-if的优先级

当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用。

10、详述组件通信

11、keep-alive组件的作用

当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题。例如我们来展开说一说这个多标签界面:


未使用keep-alive.gif

你会注意到,如果你选择了一篇文章,切换到 Archive 标签,然后再切换回 Posts,是不会继续展示你之前选择的文章的。这是因为你每次切换新标签的时候,Vue 都创建了一个新的 currentTabComponent 实例。

重新创建动态组件的行为通常是非常有用的,但是在这个案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive> 元素将其动态组件包裹起来。

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>
使用了keep-alive.gif

现在这个 Posts 标签保持了它的状态 (被选中的文章) 甚至当它未被渲染时也是如此

12、Vue生命周期详解

13、Vue如何监听键盘事件中的按键

14、Vue中的过滤器有什么用?

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示

15、单页面应用和多页面应用区别及优缺点

单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。

多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新

  1. 用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
  2. 前后端分离
  3. 页面效果会比较炫酷(比如切换页面内容时的专场动画)
  1. 不利于seo
  2. 导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理)
  3. 初次加载时耗时多
  4. 页面复杂度提高很多
姓名 单页面应用(SinglePage Web Application,SPA) 多页面应用(MultiPage Application,MPA)
组成 一个外壳页面和多个页面片段组成 多个完整页面构成
资源共用(css,js) 共用,只需在外壳部分加载 不共用,每个页面都需要加载
刷新方式 页面局部刷新或更改 整页刷新
url 模式 a.com/#/pageone a.com/pageone.html
用户体验 页面片段间的切换快,用户体验良好 页面切换加载缓慢,流畅度不够,用户体验比较差
转场动画 容易实现 无法实现
数据传递 容易 依赖 url传参、或者cookie 、localStorage等
搜索引擎优化(SEO) 需要单独方案、实现较为困难、不利于SEO检索 可利用服务器端渲染(SSR)优化 实现方法简易
试用范围 高要求的体验度、追求界面流畅的应用 适用于追求高度支持搜索引擎的应用
开发成本 较高,常需借助专业的框架 较低 ,但页面重复代码多
维护成本 相对容易 相对复杂

16、什么是计算属性?什么情况使用?

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护,例如:

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。

所以,对于任何复杂逻辑,你都应当使用计算属性。

17、vue-cli提供了几种脚手架模板

六种
https://github.com/vuejs/vue-cli/tree/v2#vue-cli--

18、computed、methods的区别

两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。这就意味着只要值还没有发生改变,多次访问 定义的计算属性会立即返回之前的计算结果,而不必再次执行函数。
相比之下,每当触发重新渲染时,调用方法(methods)将总会再次执行函数。
我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

19、什么是自定义指令,有哪些钩子函数及自定义指令的使用场景

有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
一个指令定义对象可以提供如下几个钩子函数 (均为可选):

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用。

20、父组件获取异步动态数据传递给子组件

在父组件中使用axios获取异步数据传给子组件,但是发现子组件在渲染的时候并没有数据,在created里面打印也是空的,结果发现一开始子组件绑定的数据是空的,在请求数据没有返回数据时,子组件就已经加载了,并且他绑定的值也是空的,问题找到了,怎么解决呢?

  1. 开始的时候让子组件隐藏,然后等数据返回的时候,让子组件显示
    通过v-if,也就是判断数据是否为空,为空就不渲染,也能解决了
  2. 为不能读取的属性添加一个默认值,就可以很好的解决了

21、vue-router导航解析流程

22、vue-router实现原理

这里指的路由并不是指我们平时所说的硬件路由器,这里的路由就是SPA(单页应用)的路径管理器。 换句话说,vue-router就是WebApp的链接路径管理系统。

vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。

那与传统的页面跳转有什么区别呢?

1.vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。
2.传统的页面应用,是用一些超链接来实现页面切换和跳转的。
在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系。
至于为啥不能用a标签,这是因为用Vue做的都是单页应用,就相当于只有一个主的index.html页面,所以你写的标签是不起作用的,必须使用vue-router来进行管理。

SPA(single page application):单一页面应用程序,有且只有一个完整的页面;当它在加载页面的时候,不会加载整个页面的内容,而只更新某个指定的容器中内容。

单页面应用(SPA)的核心之一是:

  1. 更新视图而不重新请求页面;
  2. vue-router在实现单页面前端路由时,提供了三种方式:Hash模式、History模式、abstract模式,根据mode参数来决定采用哪一种方式。

路由模式

vue-router 提供了三种运行模式:

● hash: 使用 URL hash 值来作路由。默认模式。

● history: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。

● abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。

Hash模式

vue-router 默认模式是 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,当 URL 改变时,页面不会去重新加载。

hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分(/#/..),浏览器只会加载相应位置的内容,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。
JavaScript实现SPA路由hash模式详解

History模式

HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 history.pushState API 来完成 URL 跳转而无须重新加载页面;

由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,只需要在配置路由规则时,加入"mode: 'history'",这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

//main.js文件中
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

当使用 history 模式时,URL 就像正常的 url,例如 yoursite.com/user/id,比较好… 不过这种模式有点问题,还需要后台配置支持。你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面,如果不这么做,直接访问页面空白

配置Apache

第一步:新建:.htaccess文件放在服务器根目录下 (命令type null>.htaccess)

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

除了 mod_rewrite,你也可以使用 FallbackResource

第二步: src/router/index.js
mode: 'history',
base: '/dist/',

第三步:访问:地址进行测试

abstract模式

abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。

根据平台差异可以看出,在 Weex 环境中只支持使用 abstract 模式。 不过,vue-router 自身会对环境做校验,如果发现没有浏览器的 API,vue-router 会自动强制进入 abstract 模式,所以 在使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用 abstract 模式。 (当然,你也可以明确指定在所有情况下都使用 abstract 模式)

23、vue-router有哪几种导航钩子

24、vue-router参数传递方法详述及区别

25、如何定义嵌套路由

26、router-link是什么及其常用属性配置

27、如何实现路由懒加载有什么好处

28、vue-router共有几种模式,有什么区别?

29、什么是Vuex及使用场景

30、vuex的常用属性有哪几个,分别是做什么的

31、简述vuex更新数据流程或机制

Vuex

用户在组件中发起动作,然后从API中拿数据,就会牵扯到异步操作,所以我们通过dispatch来提交一个action,在action里面发起ajax请求,拿到数据以后我们只需要通过commit提交mutations改变我的state状态就可以了,状态改变后视图就会改变因为Vuex是响应式的,这就是Vuex的运作流程机制

32、vuex中如何异步修改数据

Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。

33、axios、fetch和ajax有什么区别?

34、axios有哪些特点

35、组件样式中的scoped有什么用

36、vue中常用的UI组件库有哪些?

37、如何优化首屏加载速度

vue项目作为一个单页面应用,如果不对路由进行处理,在加载首页的时候,就会将所有组件全部加载,并向服务器请求数据,这必将拖慢加载速度;当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

路由懒加载

在Vue项目中,引入到工程中的所有js、css文件,编译时都会被打包进vendor.js,浏览器在加载该文件之后才能开始显示首屏。若是引入的库众多,那么vendor.js文件体积将会相当的大,影响首开的体验。

解决方法是,将引用的外部js、css文件剥离开来,不编译到vendor.js中,而是用资源的形式引用,这样浏览器可以使用多个线程异步将vendor.js、外部的js等加载下来,达到加速首开的目的。

外部的库文件,可以使用CDN资源,或者别的服务器资源等。

下面,以引入vue、vuex、vue-router为例,说明处理流程。

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  externals:{
    'vue':'Vue',
    'vue-router':'VueRouter',
    'vuex':'Vuex'
  },
  // 格式为'aaa':'bbb',其中,aaa表示要引入的资源的名字,bbb表示该模块提供给外部引用的名字,由对应的库自定。例如,vue为Vue,vue-router为VueRouter

去掉原有的引用直接使用就可以了,否则还是会打包

具体步骤为

1、引入
在bulid/webpack.base.conf.js文件中,增加externals,将引用的外部模块导入,如下:

module.exports = {
  entry: {
    app: './src/main.js'
  },
  externals:{
    'vue': 'Vue',
    'vue-router': 'VueRouter',
    'vuex':'Vuex'
  }

2、在index.html中引入cdn。推荐引入 百度静态资源库的
地址为:https://www.bootcdn.cn/

<body>
    <div id="app"></div>
    <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
  </body>

注意一点:
格式为 'aaa' : 'bbb', 其中,aaa表示要引入的资源的名字,bbb表示该模块提供给外部引用的名字,由对应的库自定。例如,vue为Vue,vue-router为VueRouter.

3、去掉原有的引用
main.js中

// import Vue from 'vue'
// import Router from 'vue-router'

去掉Vue.use(XXX),如:

// Vue.use(Router)

4、重新npm run build,会看到 vendor.js体积有所下降了
通过开发者模式的Network工具,可以看到vue.js、vuex.js、vendor.js等文件会分别由一个线程进行加载。且因为使用了CDN,减轻了带宽压力。

38、打包命令是什么?

39、打包后会生成哪些文件?

40、如何配置打包后生成的文件路径错误问题

41、简述MVVM、MVP、MVC模式及区别

42、MVVM模式的理解

43、Vue中的双向数据绑定是如何实现的

Vue双向数据绑定实现原理

分成两个进程,一个进程是对挂载目标元素模板里的v-model和{{ }}这两个指令进行编译(绿色)。另一个进程是对传进去的data对象里面的数据进行监听(红色)。

红色:

绿色:
指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,同样由Dep进行收集,然后由Dep通知到Watcher,最后更新视图。

节点介绍

43、Object.defineProperty()方法做什么用

44、vue-cli中常用的配置

45、简述vue内部运作机制

46、vuex内部运作机制

47、axios内部运作机制

48、vue-router内部运作机制

49、在vue-cli中怎么使用scss

50、vue和jquery有什么区别?

51、vue的双向数据绑定原理是什么?

52、你是怎么理解组件化开发的

53、简述vue-cli每个目录的作用

54、为什么选择vue?和其它框架对比的优劣势在哪?

55、route和router的区别

56、vue两个核心点是什么?

数据驱动、组件系统

57、用Vuex和不用vuex有什么区别?

58、第一次页面加载会触发哪几个钩子

59、v-model是什么?

60、vue中的数组和原生js中的数组有什么区别?

61、简述$set及使用场景

62、ajax应该放在组件中还是视图中或是vuex中

63、你觉得什么样的项目比较适合用vue框架

64、列举vue中触发视图更新的方法

65、Vue不能检测数组或对象变动问题的解决方法有哪些

66、vue-router,history模式下打包后访问空白

67、打包后访问某个视图,刷新404问题

68、详述虚拟DOM

第一种:
1、state数据
2、JSX模板
3、 数据 + 模板 结合,生成真实的DOM -> 视图
4、state发生了变化
5、数据 + 模板 结合,生成真实的DOM,替换原始的DOM

缺陷:
1、第一次生成了完整的DOM片段
2、第二次生成了完整的DOM片段
3、第二次的DOM替换第一次的DOM,非常耗费性能

第二种:
1、state数据
2、JSX模板
3、数据 + 模板 结合, 生成真实的DOM -> 视图
4、state发生变化
5、数据 + 模板 结合,生成真实的DOM,并不直接替换原始的DOM
6、新的DOM(DocumentFragment)和原始的DOM做比对,找差异
7、找出input框发生了变化
8、只用新的DOM中的input元素,替换掉老的DOM中input元素

缺陷:
虽然DOM只是局部替换,但是在比对时候的计算是比较耗费性能的,因此,性能的提升并不明显

第三种:
1、state数据
2、JSX模板
3、数据 + 模板 生成虚拟DOM(虚拟DOM就是一个JS对象,用它来描述真实DOM)(损耗一点性能)
虚拟DOM:['div', {id: 'abc'}, ['span', '', 'hello world']]
4、用虚拟DOM的结构生成真实的DOM -> 视图显示
真实DOM:<div id='abc'><span></span></div>
5、state发生了变化
6、数据 + 模板 生成新的虚拟DOM:['div', {id: 'abc'}, ['span', '', 'hi world']](极大提升性能)
7、比较原始虚拟DOM和新的虚拟DOM的区别,找到的区别是span中的内容发生了变化(极大提升了性能)
8、直接操作DOM,改变span中的内容

总结:
减少了真实DOM的创建及对比,创建都是JS对象,对比的也都是JS的对象,在JS底层实现了极大的性能飞越

组件生成流程:
JSX -> JS对象(虚拟DOM) -> 真实的DOM

用React.createElement改写JSX模板:
JSX:return <div><span>{ item }</span></div>
JSX -> JS对象(虚拟DOM) -> 真实的DOM
React.createElement('div', {}, React.createElement('span', {}, 'item'))
JSX -> createElement -> JS对象(虚拟DOM) -> 真实的DOM

虚拟DOM优点:
1、性能提升了
2、它使得跨端应用得以实现,Ract Native
React可以写原生应用了,得益于React中的虚拟DOM,如果没有虚拟DOM是不能写原生应用的。原生系统是不支持DOM不存在DOm这个概念的,但是支持虚拟DOM(虚拟DOM就是一个JS对象);虚拟DOM可以在浏览器端被解析为真实的DOM,在原生端可以被解析原生所支持的组件等格式

69、详述虚拟DOM中的diff算法

虚拟DOM对比时,会用到diff算法

虚拟DOM什么时候会被比对?
当数据发生变化的时候就会被比对
那什么时候数据会发生改变呢?
要么改变了state,要么改变了props(props的改变其实是他的父组件的state发生了改变)

setState方法,其实是异步的,为什么是异步的?实际为了提升React底层的性能,假设:调用三次setState变更三组数据,大家想页面会怎么做或者说React会怎么做?我们想的是React可能会做三次比对更新三次视图。又假设三次更新间隔非常小,这样会耗费性能,React可以把三次合并为一次,只去做一次虚拟DOM的比对,然后更新一次视图,这样的话就可以省去两次比对性能上的耗费。


同学们听我说.png

同层比对,如果一致,那么继续比对第二层,如果比对一样了,继续往下比对。
如果比对到不一样了,React会这么做,它不会再继续往下比对了,而是从不一样的这一层开始直接用新的覆盖掉就得DOM节点,这样的话岂不是性能并未得到最大提升?这样的话会造成重复节点的浪费,。那这样比对会有什么好处呢?同层比对带来的好处就是比对的算法特别简单,虽然可能会造成DOM上的重新渲染的浪费,但是大大的减少了虚拟DOM之间比对的算法上的性能消耗,所以React中采用了同层比对的算法。

遍历时候key的问题:


同学们听我说

假如:数组中有五条数据,渲染到页面,然后生成五个虚拟DOM树,接下来我往里面增加了一条数据于是数据发生变化会生成一个新的虚拟DOM树,然后我们会做两个虚拟DOM的比对也就是上下进行比对匹配关系,如果每一个虚拟DOM的节点没有一个key值,它就没有一个自己的名字,当我们在做两个虚拟DOM树的比对的时候节点和节点之间的关系就很难被确立,我们得做两层循环的比较,这样的话比较起来就很麻烦了,当然也是很耗费性能的。
我们可以这样优化,假如我们在做DOM节点的循环的时候,我们可以给每个节点起个名字,A、B、C、D、E在第二次循环的时候我们有六个,以前的ABCDE还存在还是叫做ABCDE,我又增加了一个节点Z进来这个时候比对就很简单了,我们根据他们的名字进行比对,马上就能知道ABCDE都一致,可以继续复用,只有Z不同,我们快速的建立关联后把Z增加到这个DOM树上就可以了。所以极大的提升了虚拟DOM比对的性能。
如果提升性能有个前提我们尽量不要用下标,因为大家看按照下标的话右图ABCDE,下面新的DOM树ABCDE和上面的其实不再是对应的关系了,对导致key值不稳定,key值是变化的,失去了存在的意义了。那用什么比较合适呢?唯一不变化的、稳定的值。

70.ajax、axios、fetch之间的详细区别以及优缺点

71. 异步组件

上一篇下一篇

猜你喜欢

热点阅读