vue面试题

757 阅读9分钟

vue面试题

day1

vue.js 是什么

vue是一个数据驱动构建用户界面渐进式框架, 尽可能通过简单的API实现响应式的数据绑定组合的视图组件

核心是响应的数据绑定系统组件化的开发模式

简述vue.js的优点

1.轻量级的框架

2.简单易学上手快

3.双向数据绑定

4.组件化的开发模式

5.视图、数据、结构分离

6.虚拟DOM

7.运行速度快

对于MVVM的理解

  • 首先MVVM是Model-View-ViewModel的缩写

  • MVVM是一种设计思想

  • Model代表数据模型,数据和业务逻辑都在model层中定义

  • View代表UI组件,负责数据的展示

  • ViewModel监听模型数据的改变和控制视图行为,简单来说就是一个双向数据绑定,ViewModel的作用就是把Model对象封装成可以显示和接受输入的界面数据对象

  • View和Model之间没有直接的联系,而是通过viewmodel进行交互的,Model和ViewModel之间的交互式双向的,因此view数据的变化会同步到Model,而Model数据的变化也会立即反应到View上

什么是vue的生命周期

生命周期就是vue实例从创建到销毁的过程 从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、销毁等一系列过程,称之为vue的生命周期

vue的生命周期

vue的生命周期分为8个阶段: 创建前/创建后 挂载前/挂载后 更新前/更新后 销毁前/销毁后

所有的生命周期钩子自动绑定this上下文到实例中,因此可以访问数据,对属性和方法运算。不能使用箭头函数来定义一个生命周期。因为箭头函数绑定了父上下文,会报错。

  • beforeCrete创建前: 在实例初始化之后,数据观测(data observer)和event/watcher事件配置之前被调用

  • creted创建后: 在实例创建完成后被立即调用。在这一步,实例已完成以下配置:数据观测(data observer),属性和方法的运算,watch/event事件回调。挂载还没开始,$el属性不可用

  • beforeMount挂载前: 在挂载开始之前被调用:相关的render函数首次被调用

  • mounted挂载后: 实例被挂载后调用,这是el被新创建的vm.el替换了。如果跟市里挂载到了一个文档内的元素上,当mounted被调用时vm.el也在文档内。mounted不会保证所有的子组件也都一起被挂载,如果希望整个视图都渲染完毕,可以在mounted内部使用vm.$nextTick

  • beforeUpdate更新前: 数据更新时被调用,发生在虚拟DOM更新之前,这里适合在更新之前访问现有的DOM,比如手动移出已添加的事件监听器

  • updated更新后: 由于数据更改导致虚拟DOM重新渲染,在这之后会调用该钩子。当这个钩子被调用时,组件DOM已经更新,所以现在可以执行依赖DOM的操作。但是应该避免在此时更改状态,最好使用计算属性和watch来替代

  • beforeDstory销毁前: 实例销毁之前调用。这一步实例仍然可用

  • destoryed销毁后: 实例销毁后调用。被调用后,该对应vue实例的所有指令都被解绑,所有事件监听器都被移除。所有的子实例也都被销毁

一上来就执行的只有前四个 beforeCreate created beforeMount mounted

服务器端渲染只有beforeCreate created执行

vue生命周期的作用是什么

生命周期中有多个事件钩子,让我们在控制整个vue实例的过程中更容易形成好的逻辑

第一次页面加载会触发哪几个钩子函数

breforeCrete creted beforeMount mounted

DOM渲染在哪个周期就已经完成了

DOM渲染在mounted中就已经完成了

day2

vue实现数据双向绑定的原理

Object.defineProperty() vue 实现双向绑定的主要采用数据劫持结合发布订阅模式的方式。 通过Object.defineProperty()来劫持各个属性的getter,setter,在数据变动时发布消息给订阅者,触发相应的监听回调。当一个普通的javascript对象传给vue实例来作为它的dota选项时,vue将遍历它的属性,用Object.defineProperty将他们转为getter/setter.用户看不到getter/setter 但是在内部他们让vue 追踪以来,在属性被访问和修改时通知变化

vue的数据双向绑定将MVVM作为数据绑定的入口,整合Observer,Compile和watch三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令,最终watcher搭起observer和compile之间的通信桥梁,达到数据变化->视图更新;视图交互变化->数据model变更双向绑定效果

<body>
    <div id="app">
        <input type="text" id="txt"/>
        <p id="show"></p>
    </div>
</body>

<script>
var obj = {}

Object.defineProperty(obj,'txt',{
    get(){
        return obj
    },
    set(newValue){
        document.getElementById('txt').value=newValue;
        document.getElementById('show').innerHTML = newValue;
    }
})
document.addEventListner('keyup',function(){
    obj.txt = e.target.value
})
</script>

vue组件之间的通信

常见的使用场景可以分为三类:

  • 父子组件通信
  • 兄弟组件同喜
  • 跨级组件通信

具体组件方法:

1.父传子 props 2.子传父 emit 触发自定义事件
3.parent 4.children
5.provide/inject
6.ref/refs 7.attrs/listeners 8.eventBus 9.vuex 10.localStorage

v-show 与 v-if 区别

1.v-show是css切换diplay,v-if是完整的销毁和重新创建

2.频繁切换用v-show 运行较少改变时用v-if

3.v-if只有为true的时候才会真实的渲染DOM,v-show不管是否为真都会渲染真实DOM

请问 v-if 和 v-show 有什么区别

  • 共同点:

    v-if和v-show都是动态显示DOM元素

  • 不同点:

    1.编译过程:v-if是真正的条件渲染;v-show的元素始终会被渲染并保留DOM,v-show只是简单的切换display属性 2.编译条件:v-if是惰性的,如果初始渲染条件为假,则什么也不做,直到条件第一次变为真,才开始渲染条件块代码。v-show不管初始条件是什么,元素总是会被渲染,并且只是简单的基于css进行切换。 3.性能消耗:v-if有更高的切换消耗。v-show有更高的初始渲染消耗 4.应用场景:v-if适合运行时条件很少改变时使用。v-show适合频繁切换

绑定class的数组用法

  • 数组用法:<div v-bind="[class1,class2]"></div>
  • 对象用法:<div v-bind="{'orange':boolean,'green':boolean}"></div>
  • 行内用法:<div style="{color:color,fontSize:fontSize+'px'}"></div>

计算属性computed和watch的区别

计算属性是自动监听依赖值得变化,从来动态返回内容,监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些事 所以区别来源于用法,只是需要动态值,那就用计算属性 需要知道值得改变后执行业务逻辑,才用watch

当有一些数据需要随着另外一些数据变化的时候,建议用computed 当有一个通用的响应数据变化的时候,要执行一些业务逻辑或者异步操作时候建议用watch

computed是一个对象时,有哪些选项

有get和set两个选项

computed和methods有什么区别

methods是一个方法,他可以接收参数,而computed不能,computed是可以缓存的,methods不会

computed是否依赖其它组件的数据

computed可以依赖其它computed,甚至是其它组件的data

watch是一个对象时,它有哪些选项

handle deep:是否深度监控 immeditate 是否立即执行

组件中的data为什么是函数

因为组件是可以服用的,js里对象时引用的关系,这样作用域没有隔离,而new Vue的实例,是不会服用的,因此不存在引用对象的问题

v-model是怎样实现的

v-model 就是一个语法糖 分开写就是 v-bind="value" v-on:input="" 既绑定了数据,又添加了一个input事件监听

怎么理解单向数据流

父组件通过prop把数据传递到子组件,但是这个prop只能由父组件修改,子组件不能修改,否则会报错。子组件想修改时,只能通过$emit派发一个自定义事件,父组件接收之后,由父组件修改。

一般来说,对于子组件想修改父组件的场景,可以有两种方案:

在子组件的data中拷贝一份prop,data是可以修改的,但prop不能:

export default{
    props:{
        value:String
    },
    data(){
        return {
            currentVal:this.value
        }
    }
}

如果是对prop值得转换,可以使用计算属性:

export default{
    props:['size'],
    computed:{
        normalLizedSize(){
            return this.size.trim().toLowerCase()
        }
    }
}

day3

vue几种常用的指令

  1. v-bind 简写":"
  2. v-on 简写"@"
  3. v-model
  4. v-for
  5. v-if
  6. v-else
  7. v-if-else
  8. v-show
  9. v-text
  10. v-html
  11. v-slot
  12. v-pre
  13. v-cloak
  14. v-once

vue常用的修饰符

v-on指令常用修饰符:

  • .stop 调用event.stopPropagation() 阻止事件冒泡
  • .prevent 调用event.preventDefault() 阻止事件默认行为
  • .capture 添加事件侦听器使用capture模式
  • .self 只当事件是从侦听器绑定的元素本身触发时才触发回调
  • .{keyCode | keyAlias}只当事件是从特定键触发时才触发回调
  • .native 监听是组件根元素的原生事件
  • .once 只触发一次回调
  • .left 点击鼠标左键触发
  • .right 点击鼠标右键触发
  • .middle 点击鼠标中键触发
  • .passive 以{passive:true}模式添加侦听器

v-bind指令常用修饰符:

  • .prop 被用于绑定DOM属性
  • .camel 将kebab-case特性转换为camelCase
  • .sync 语法糖 会扩展成为一个更新父组件绑定值得v-on侦听器

v-model指令常用修饰符:

  • .lazy 取代input监听change事件
  • .number 输入字符串转为数字
  • .trim 过滤首尾空格过滤

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

可以监听多个方法,但是同一种事件类型的方法,vue-cli会报错

vue中key值的作用

key值:用于管理可复用的元素。 因为vue会尽可能高效的渲染元素,通过会复用已有的元素而不是从头开始渲染。这么做使vue 变得非常快,但是也不是总是符合实际需求。

当前组件中使用v-for时,key现在是必须的。

要解释key的作用,你得先了解虚拟DOM的Diff算法 vue实现了一套虚拟DOM,使我们可以不直接操作DOM,只操作数据便可以重新渲染页面。 vue的虚拟DOM的Diff算法,其核心是基于两个简单的假设: 1.两个相同的组件产生类似的DOM结构,不用的组件产生不同的DOM结构。 2.同一层级的一组节点,他们可以用过唯一的id进行区分

当页面的数据发生变化时,Diff算法只会比较用一层级的节点:

  • 如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较找个节点以后的节点。
  • 如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新 当某一层有很多相同节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则

所以一句话key的作用主要是为了高效的更新虚拟DOM。 另外vue在使用相同标签名元素的过渡切换时,也会使用到key,其目的时为了让vue可以区分它们

vue事件中如何使用event对象

// html
<a data-id="12" @click="showEvent($event)">

// js
showEvent(event){
    console.log(event.target.dataset.id);
    event.stopPropagation()
    event.preventDefault()
}

nextTick的使用

因为vue时异步更新队列,$nextTick是用来知道什么时候DOM更新完成的

异步更新队列: vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一个事件循环中发生的所有数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和DOM操作。然后在下一个事件循环tick中,vue刷新队列并执行实际工作。所以用一个for循环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制,DOM就要重绘100次,这固然时一个很大的开销。

vue组件中的data为什么必须是函数

因为组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象, 返回一个唯一的对象,不要和其它组件共用一个对象。

v-for和v-if的优先级

当他们处于同一节点,v-for的优先级比v-if更高,这意味着v-if将分别重复运行与每个v-for循环中。

day4

vue中keep-alive组件的作用

keep-alive主要用于保留组件避免重新渲染

属性:

  • include:只有匹配到的组件会被缓存
  • exclude:任何匹配到的都不会被缓存

包裹动态组件时,会缓存不活动的组件实例,而不是销毁。和<transition></transition>类似, <keep-alive></keep-alive>时一个抽象组件,本身不会渲染一个DOM元素

vue如何监听键盘事件中的按键

按键修饰符: vue允许v-on在监听键盘事件时,添加按键修饰符:

  • .enter
  • .tab
  • .delete
  • .esc
  • .up
  • .down
  • .left
  • .right

可以通过全局config。keyCodes对象自定义按键修饰符别名:Vue.config.keyCodes.f1 = 112

系统修饰符:

  • .ctrl
  • .alt
  • .shift
  • .meta

鼠标按钮修饰符:

  • .left
  • .right
  • .middle

vue更新数组时触发视图更新的方法

  • pop()
  • push()
  • shift()
  • unshift()
  • splice()
  • reverse()
  • sort()

这几个方法会触发视图更新

替换数组:

filter() concat() slice() 这些不会改变原数组,但是会返回一个新的数组,当使用这些非变异方法时,可以用新数组替换旧数组

注意事项: 不要直接修改data的数据值,因为直接修改数组的某一项或者数组的长度,修改之后不是响应的值,页面不会更新。 可以使用Vue.set(vm.items,indexOfItem,newValue)或者vm.$set(vm.items,indexOfItem,newValue)

vue中对于对象的更改检测

由于javascript的限制,vue不能检测对象属性的添加或删除: 对于已创建的实例,vue不能动态添加根级别的响应式属性,但是可以用Vue.set(object,key,value)方法向嵌套对象添加响应式属性。

let vm = new Vue({
    data(){
        userProfile:{
            name:'hulongfei'
        }
    }
})

Vue.set(vm.userProfile,'age',29)

vm.$set(vm.userProfile,'age',29)

// 给已有对象赋予多个新属性
`Object.assign()`

vm.userProfile = Object.assign({},vm.userProfile,{
    age:29,
    like:'Vue Green'
})

非工程化项目初始化页面闪动问题


// css
[v-cloak]{
    display:none
}

// html
<div id="app" v-cloak>{{message}}</div>

// js
let vm = new Vue({
    data(){
        return{
            message:'this is text!'
        }
    }
})

v-cloak时解决初始化慢导致页面闪动的最佳实践,对于简单的项目很实用

v-for产生的列表,实现active的切换

通过设置当前currentIndex实现:

<template>
    <div class="toggleClassWrap">
        <ul>
            <li @click="currentIndex = index" :class="clicked:index === currentIndex" v-for="(item,index) in desc" :key="index">
                <a href="javascript:;">{{item.ctrlValue}}</a>
            </li>
        </ul>
    </div>
</template>

<script>
export default{
    data(){
        return {
            desc:[
                {
                    ctrlValue:'test1'
                },
                {
                    ctrlValue:'test2'
                },
                {
                    ctrlValue:'test3'
                },
                {
                    ctrlValue:'test4'
                }
            ],
            currentIndex:0
        }
    }
}
</script>

<style lang="less">
.clicked{
    color:red
}
</style>

v-model语法糖的使用

v-model仅仅是个语法糖

<input v-model="something"/>

<input :value="something" @input="something=$event.target.value"/>

<custom :value="sonmething" @input="something=$event.target.value'"></custom>

day5

vue单页应用机器优缺点

单页web应用(SPA): 就是只有一张web页面的应用。单页应用程序是加载单个HTML页面并在用户和应用程序交互时动态更新该页面的web应用程序。浏览器一开始会加载必须的HTML、CSS、JS所有操作都在这张页面上完成,都由js来控制。因此,对单页应用来说模块化的开发和设计显得相当重要。

单页应用的优点:

  1. 提供了更加吸引人的用户体验:具有桌面应用的即时性,网站的可移植性和可访问性。
  2. 单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性
  3. 单页应用没有页面之间的切换,就不会出现“白屏现象”也不会出现假死现象
  4. 单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。
  5. 良好的前后端分离。后端不负责模板渲染输出页面功能,后端API通用化,即同一套后端程序代码,不用修改就可以用web页面、手机、平板灯多种客户端

单页web应用的缺点:

  1. 首次加载耗时比较多
  2. SEO问题,不利于百度,360等搜索引擎收录
  3. 容易造成css命名冲突
  4. 前进,后退,地址栏,书签,都需要程序进行管理,页面的复杂度很高,需要一定的技能水平和开发成本高

什么是vue的计算属性

计算属性:

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

计算属性的缓存和方法调用有什么区别

  1. 计算属性必须返回结果
  2. 计算属性是基于它的依赖缓存的,一个计算属性所依赖的数据发生变化时,他才会重新取值
  3. 使用计算属性还是methods取决于是否需要缓存,当便利大数组和做大量计算式,应当使用计算属性,除非你不希望得到缓存
  4. 计算属性是根据依赖自动执行的,methods需要事件调用