vue面试题

vue面试题

来源:https://juejin.im/post/5d59f2a451882549be53b170

一、说说你对SPA单页面的理解,它的优缺点是什么?

SPA(single-page application)仅在web页面初始化时加载相应的HTML、JavaScript和CSS.一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现HTML内容的变换,UI与用户的交互,避免页面的重新加载。
优点:

  • 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染:
  • 基于上面一点,SPA相对服务器压力小;
  • 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理
    缺点:
  • 初次加载耗时多:为实现单页web应用功能及显示效果,需要在加载页面的时候将javscript、css统一加载,部分页面按需加载;
  • 前进后退路由管理:由于单页应用在一个页面中显示所有内容,所不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
  • SEO难度较大:由于所有的内容都在一个页面中动态替换显示,所以在SEO上有着天然的弱势。

二、v-show和v-if的有什么区别?

v-if是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当的被销毁和重建;也是惰性的;如果在初始渲染时条件为假,则什么也不做–直到条件第一次变为真时,才会开始渲染条件块。
v-show就很简单,不管初始条件是什么,元素总是会被渲染,并且只有简单的基于CSS的“display”属性进行切换。
所以,v-if适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show则适用于需要非常频繁切换条件的场景。

三、class与style如何动态绑定

class可以通过对象语法和数组语法进行动态绑定:

  • 对象语法:
<div v-bind:class="{active:isActive,'text-danger':hanError}"></div>
data:{
isActive:true,
hasError:false
}
  • 数组语法
<div v-bind:class="[isActive?activeClass:'',errorClass]"></div>
data:{
activeClass:'active',
errorClass:'text-danger'
}

style也可以通过对象语法和数组语法进行动态绑定:

  • 对象语法:
<div v-bind:style="{coloe:activeColor,fontSize:fontSize + 'px'}"></div>

data:{
activeColor:'red',
fontSize:30
  • 数组语法:
<div v-bind:style="[styleColor,styleSize]"></div>
data:{
styleColor:{color:'red'},
styleSize:{fontSize:'23px'}
}

四、怎样理解vue的单向数据流?

所有的prop都使得其父子prop之间形成了一个单向下行绑定:父级prop的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外改变父组件的状态,从而导致应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件的所有prop都将会刷新为最新的值。这意味着不应该在一个子组件内部改变prop。如果这样做,vue会在浏览器的控制台中发出警告。
子组件想修改是,只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改。

有两种常见的视图改变一个prop的情形:

  • 这个prop用来传递一个初始值;这个子组件接下来希望将其作为一个本地的prop数据来使用。在这种情况下,最好定义一个本地的data属性并将这个prop用作其初始值:
props:['initialCounter'],
data:function(){
return{
counter:this.initialCounter
}
}
  • 这个prop以一种原始的值传入且需要进行转换,在这种情况下,最好使用这个prop的值来定义一个计算属性
props:['size'],
computed:{
normalizedSize:function(){
return this.size,trim().toLowerCase()
}
}

五、computed和watch的区别和运用的场景?

computed:是计算属性,依赖其他属性值,并且computed的值有缓存,只有它依赖的属性值发生变化,下一次获取computed的值时才会重新计算computed的值;
watch:更多的是【观察】的作用,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:

  • 当我们需要记性数值计算,并且依赖于其他数据时,应该使用computed,因为可以利用computed的缓存特性,避免每次获取值时,都要重新计算;
  • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用watch,使用watch选项允许我们执行异步操作(访问一个API),限制我们执行该操作的频率,并且在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

六、直接给一个数组项赋值,vue能检测到变化吗?

由于JavaScript的限制,vue不能检测到以下数组的变动

  • 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  • 当你修改数组的长度时,例如:vm.items.length = newLength
    为了解决第一个问题,Vue提供了以下操作方法:
// Vue.set
Vue.set(vm.items,indexOfItem,newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items,indexOfItem,newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem,1,newValue)

为了解决第二个问题,Vue提供了以下操作方法:

// Array.prototype.splice
vm.items.splice(newLength)

七、谈谈你对声明周期的理解?

(1)声明周期是什么?
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程,我们称之为Vue的生命周期
(2)各个生命周期的作用

生命周期描述
beforeCreate组件实例被创建之初,组件的属性生效之前
created组件实例已经完全创建,属性也绑定,但真实dom还没有生成,$el还不可用
beforeMount在挂载开始之前被调用:相关的render函数首次被调用
mountedel被创建的vm.$el替换,并挂载到实例上去之后调用该钩子
beforeUpdate组件更新之前调用,发生在虚拟DOM打补丁之前
update组件数据更新之后
activitedkeep-alive专属,组件被激活时调用
deactivatedkeep-alive专属,组件被销毁时调用
beforeDestory组件销毁前调用
destoryed组件销毁后调用

(3)声明周期示意图

在这里插入图片描述

八、vue的父组件和子组件生命周期钩子函数执行顺序?

vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下4部分:

  • 加载渲染过程
    父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount ->子mouted ->父mounted
  • 子组件更新过程
    父beforeUpdate->子beforeUpdate->子updated->父updated
  • 父组件更新过程
    父beforeUpdate->父updated
  • 销毁过程
    父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

九、在哪个生命周期内调用异步请求?

可以在钩子函数created、beforeMount、mounted中进行调用,因为在这三个钩子函数中,data已经创建,可以将服务端返回的数据进行赋值,但是推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求有以下几个优点:

  • 能更快获取到服务端数据、减少页面loading时间;
  • ssr不支持beforeMount、mounted钩子函数,所以放在created中有助于一致性;

十、在什么阶段才能访问操作DOM?

在钩子函数mounted被调用前,Vue已经将编译好的模板挂载到页面上,所以在mounted中可以访问操作DOM,

十一、父组件可以监听到子组件的生命周期吗?

比如有父组件Parent和子组件Child,如果父组件监听到子组件挂载mounted就做一些逻辑处理,可以通过以下写法实现:

// Parent.vue
<Child @mounted="doSomething" />

// Child.vue
mounted(){
this.$emit("mounted");
}

以上需要手动通过$emit触发父组件的事件,更简单的方式可以在父组件引用子组件时通过@hook来监听即可,如下所示:

// Parent.vue
<Child @hook:mounted="doSomething"></Child>

doSomething(){
console.log('父组件监听到了mounted钩子函数...');
},
// Child.vue
mounted(){
console.log('子组件触发mounted钩子函数...');
}

// 以上是输出顺序为:
// 子组件触发mounted钩子函数
// 父组件监听到了mounted钩子函数

当然@hook方法不仅仅是可以监听到mounted,其他的生命周期事件,例如created,updated等都可以监听。

十二、谈谈你对keep-alive 的了解?

keep-alive是vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染,有以下特性:

  • 一般结合路由和动态组件一起使用,用于缓存组件;
  • 提供include和exclude属性,两者都支持字符串或正则表达式,include表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被缓存,其中exclude的优先级不include高;
  • 对应两个钩子函数activated和deactivated,当组件被激活时,触发钩子函数activated,当组件移除时,触发钩子函数deactivated。

十三、组件中data为什么是一个函数?

为什么组件中的data必须是一个函数,然后return一个对象,而new Vue实例里,data可以直接是一个对象?

// data
data(){
return {
message:'子组件',
childName:this.name
}
}

// new Vue
new Vue({
el:'#app',
router,
template:'<App/>',
components:{App}
})

因为组件是用来复用的,且JS里对象是引用关系,如果组件中data是一个对象,那么这样作用域没有隔离,子组件中的data属性值会相互影响,如果组件中data选项是一个函数,那么每一个实例可以维护一份被返回的对象的独立的拷贝,组件实例之间的data属性值不会相互影响;而new Vue的实例,是不会被复用的,因此不存在引用对象的问题。

十四、v-model的原理?

我们在vue项目中主要使用v-model指令在表单input、textarea、select等元素上创建双向数据绑定,我们知道v-model本质上只不过是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text和textarea元素使用value属性和input事件;
  • check和radio使用checked属性和change事件;
  • select字段将value作为prop并将change作为事件
<input v-model="something">
相当于
<input v-bind:value="something" v-on:input="something=$event.target.value">

如果在自定义组件中,v-model默认会利用名为value的prop和input的事件,如下所示:

父组件:
<ModelChild v-model="message"></ModelChild>

子组件:
<div>{{value}}</div>

props:{
value:String
},
methods:{
test1(){
this.$emit('input','小红')
}
}

十五、Vue组件间通信有哪几种方式?

Vue组件间通信是面试常考的知识点之一,这题有点类似于开放题,回答出越多方法当然越加分,表明对Vue掌握的越熟练。Vue组件间通信只要指以下3类通信:父子组件通信、隔代组件通信、兄弟组件通信
(1)props/$emit适用 父子组件通信
这种方法是Vue组件的基础
(2)ref与$parent/$children适用 父子组件通信

  • ref:如果在普通DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例。
  • $parent/$children:访问父/子实例
    (3)EventBus($emit/$on)适用于父子、隔代、兄弟组件通信
    这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
    (4)$attrs/$listeners 适用于隔代组件通信
  • $attrs:包含了父作用域中不被prop所识别(且获取)的特定绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v-bind="$attrs"传入内部组件,通常配合inheritAttrs选项一起使用。
  • $linteners:包含了父作用域中的(不含.native修饰器的)v-on事件监听器。它可以通过v-on="$listeners"传入内部组件。
    (5)provide/inject适用于 隔代组件通信
    祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。provide/inject API主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
    (6)Vuex适用于 父子、隔代、兄弟组件通信
    Vuex是一个专为Vue.js应用程序开发的状态管理模式。每一个Vuex应用的核心就是store(仓库)。“store”基本上就是一个容器,它包含这你的应用中大部分的状态(state)。
    *Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的得到高效更新。
  • 改变store中的状态的唯一途径就是显示的提交(commit)mutation。这样使得我们可以方便的跟踪每一个状态的改变。

十六、你使用过vuex吗?

Vuex是一个专为Vue.js应用程序开发的状态管理模式。每一个Vuex应用的核心就是store(仓库)。“store”基本上就是一个容器,它包含这你的应用中大部分的状态(state)

  • vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应的得到高效更新。
  • 改变store中的状态的唯一途径就是显式地提交(commit)mutation.这样使得我们可以方便地跟踪每一个状态的变化。

主要包括以下几个模块:

  • state:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
  • Getter:允许组件从Store中获取数据,mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性。
  • Mutation:是唯一更改store中状态的方法,且必须是同步函数。
  • Action:用于提交mutation,而不是直接变更状态,可以包含任意异步操作。
  • Module:允许将单一的Store拆分为多个store且同时保存在单一的状态树中。

十七、通过Vue SSR吗? 说说 SSR?

Vue.js是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出Vue组件,进行生成DOM和操作DOM。然而,也可以将同一个组件渲染为服务端的HTML字符串,将他们直接发送到浏览器,最后将这些静态标记“激活”为客户端上完全可交互的应用程序。
即:SSR大致的意思就是vue在客户端将标签渲染成的整个html片段的工作在服务端完成,服务端形成的html片段直接返回给客户端这个过程就叫做服务端渲染。
(1)服务端渲染的优点:

  • 更好的SEO:因为SPA页面的内容是通过Ajax获取,而搜索引擎爬取工具并不会等待Ajax异步完成后再抓取页面内容,所以在SPA中抓取不到页面通过Ajax获取到的内容;而SSR是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面:
  • 更快的内容到达时间(首页加载更快):SPA会等待所有vue编译后的js文件都下载完成后,才开始
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值