vue-面试题

一、对MVVM的理解

MVVMModel-View-ViewModel的简写,是一个软件架构设计模式,是一种简化用户界面的事件驱动编程方式,由微软WPFSilverlight的架构师于2005年发表的

MVVM源自经典的Model-View-ControllerMVC)模式,MVVM的出现极大促进了前端开发和后端业务逻辑的分离,极大提高了前端开发的效率,其核心是ViewModel层,负责转换Model中的数据,对数据进行处理和解析,向上与视图层进行双向数据绑定,向下与数据层通过接口请求进行数据交互

对其构成的三部分进行介绍:

  1. View:视图层,也就是用户界面,前端主要由HTMLCSS来构成
  2. Model:数据模型,泛指后端进行各种业务逻辑处理和数据操控,对于前端来说就是后端提供的api接口
  3. ViewModel:视图逻辑层,由前端开发人员组织生成和维护的

ViewModel层,前端开发者对从后端Model获取的数据进行转换处理和解析,做二次封装,生成符合View层使用的视图数据模式。需要注意的是ViewModel所封装出来的数据模型包括视图的状态和行为两部分,而Model层的数据模型是只包含状态的,比如页面这一块展示什么;但是页面加载进行时发生什么,点击页面发生什么,页面滚动的时候发生什么这些都属于视图行为(用户交互),视图状态和行为都封装在ViewModel层,这样的封装使得ViewModel可以更完整的去描述View

MVVM框架实现了双向绑定,这样的ViewModel的内容会实时展现在View层,前端开发者不必再去操作dom去更新视图,框架已经把最脏最累的一块已经做好了,我们开发者只需要处理和维持ViewModel,更新数据视图也会自动更新。这样的View层展现的不再是Model层的数据,而是ViewModel层的处理后的数据,由ViewModel负责和Model交互,完全解耦了ViewModel,这个解耦是至关重要的,是前后端分离的重要一环

二、MVCMVPMVVM的区别

MVCView-用户界面,Controller-控制器,Model-数据保存;

  • 用户或View传送指令给ControllerController完成业务逻辑,要求Model改变状态,Model将新数据发送到View,用户得到反馈

  • View非常厚,业务逻辑都部署在ViewController非常薄,只能起到路由的作用

  • 通信是单向的:v-c-m-v
    在这里插入图片描述

MVPView-用户界面,Presenter-控制器,Model-数据保存;

  • ViewModel不发生联系,都通过Presenter传递
  • View非常薄,不部署任何业务逻辑,Presenter非常厚,所有逻辑部署都在Presenter
  • 各部分之间的通信是双向的

在这里插入图片描述

MVVM:如第一条

在这里插入图片描述

MVC,MVP 和 MVVM 的图示

三、Vue的生命周期
什么是生命周期?

从创建到销毁的过程,被称为生命周期;从开始创建、初始化数据,编译模板,挂载DOM,更新渲染,销毁这一系列过程,被称为vue的生命周期

作用是什么?

生命周期过程中有对应的钩子函数,开发者可以在对应内周期过程中做合适的事情,在vue实例的过程中形成良好的代码逻辑

有哪些钩子函数?

主要有8个钩子函数:

  1. 创建前后
    • beforeCreate:初始化空的Vue实例对象,无法访问datamethodscomputedwatch
    • created:实例化数据对象datamethods,进行数据初始化,无法访问DOM
  2. 挂载前后
    • beforeMount:模板编译完成,为虚拟的DOM节点,可对数据进行修改,不触发updated
    • mounted:实例el挂载完成,可访问真实DOM,完成数据双向绑定,可通过$refsDOM进行操作
  3. 更新前后
    • beforeUpdate:发生在虚拟DOM打补丁之前,适合在更新之前访问现有DOM,可进行数据更改,但是不会重渲染
    • updated:新的DOM已更新,避免在这个钩子函数操作数据,防止死循环
  4. 销毁前后
    • beforeDestroy:实例还可获取,this还可调用,常用于销毁定时器、解绑事件
    • destroy:实例及其所有子实例均被销毁,数据绑定拆除、监听移除等
这些钩子是如何实现的?

其实这些钩子函数就是回调函数而已,创建组件过程会调用相应的钩子方法。主要是通过callHook方法来调用的(源码可读),核心是一个发布订阅者模式,将钩子订阅好(内部才去数组方式存储),在对应的阶段进行发布

五、Vue组件间的参数传递(组件通信)

主要有三类通信:父子组件通信、兄弟组件通信、隔代组件通信

父子组件通信
  1. props + $emit:比较常用就不介绍了
  2. refs + $parent / $children:比较常用就不介绍了
隔代组件通信
  1. provide + inject:主要解决跨级组件的通信问题,使用场景是子组件获取上级组件的状态,跨级组件间建立一种主动提供和依赖注入的关系

    • provide:父组件提供变量或方法

      provide(){
      	return {
      		title:'父组件的标题'
      	}
      }
      
    • inject:字组件注入依赖

      inject:['title']
      
  2. $attrs + $listeners:主要用于多级组件嵌套需要传递数据时

    • $attrs :(除了classstyle)包含父作用域中不被props识别且获取的的特性绑定,在组件上通过v-bind="$attrs"传入内部组件,通常配合interitAttrs选项使用
    • $listeners:(不含.native修饰器的)包含父作用域中v-on事件监听器,在组建上通过v-on="$listeners"传入内部组件
    • 简单来说:$attrs$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非props属性,$listeners里存放的是父组件中绑定的非原生事件
通用方式:适用于父子组件通信、兄弟组件通信、隔代组件通信
  1. EventBus$emit / $on,通过空的vue实例作为中央事件总线(事件中心),用来触发事件和监听事件,从而实现通信

    let event = new Vue()
    event.$emit('sendData',data) //触发事件的组件中编写
    event.$on('sendData',data => {console.log('拿到数据处理事情')}) //接收数据变化的组件
    
  2. Vuex:状态管理库,将应用状态都存储在store中,各组件都通过getter获取数据、mutation(通过action提交mutation)更改数据

六、Vue路由实现(两种路由模式:hashhistory

Vue路由的两种模式

七、vuex
vuex是什么?

一般来说,如果用到vue框架,必不可少的就是使用vuex这个核心插件。vuex是专门为vue服务的,用于管理页面间的数据状态、提供统一数据操作的生态系统,相当于数据库的MongoDBMySQL等,任何组件都可以从仓库中存取数据

vuex采用的是mcv架构中的model层,规定所有的数据都必须通过action-mutation-state这个流程来改变状态,然后再结合vue的数据双向绑定实现页面的更新

统一页面状态管理,可以让复杂的组件交互变得简单清晰,让组件间通信变得更方便,大大提高了vue项目的开发效率

如何使用?
//安装插件
npm install vuex --save
//在store目录下的index.js引入插件
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.store({
	state,
	getter,
	action,
	mutation,
	module
})
//最后在main.js中使用
import store from './store'
new Vue({
    el:'#app',
    store
})
有哪几种属性?
  1. state:数据源存放地,是响应式的数据
  2. getter: 可以认为是 store 的计算属性
  3. mutation:更改 store 状态的唯一方法就是提交mutation,接收事件类型和回调函数(必须是同步的),要遵守一些规则:
    • 最好提前在 store 中初始化所有所需属性
    • 如果需要在对象上添加新属性时,应该使用Vue.set(obj,'newProp',123)或者state.obj = {...state.obj,newProp:123}
  4. actionaction提交的是mutation,而不是直接变更状态,可以包含任何的异步操作
  5. module:对 store 划分为多个模块,便于管理
应用场景?

单页应用中,组件间的状态、音乐播放、登录状态、加入购物车等

actionmutation有什么区别

主要是一个函数能否包含异步操作的区别,action通过提交mutation来变更状态,而不是直接变更

八、vue-router
vue-router是如何实现的

路由就是用来和后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,进行不同页面的渲染等

vue-router 使用 paramsquery传参有什么区别

params传参路径接收需要paramsnamequerypath

//路由跳转
this.$router.push({name:'xxx',params:{xx:xxx}})
this.$router.push({path:'xxx',query:{xx:xxx}})
//或者
<router-link :to="{name:'xxx',params:{xx:xxx}}"></router-link>
<router-link :to="{path:'xxx',query:{xx:xxx}}"></router-link>

//参数接收
this.$route.params
this.$route.query

params:参数不显示在路径上,页面刷新参数丢失

query:参数会显示在路径上,页面刷新不会丢失参数

$route$router的区别

$router:访问当前路由器,是路由实例对象,包括路由跳转方法,钩子函数等,比如this.$router.push

$route:访问当前路由,是当前路由信息的对象,包括pathparamshashqueryfullPathmatchedname等信息

路由守卫

全局路由:beforeEachafterEachbeforeEnter

组件路由:beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave

九、VueAngularReact三者区别
VueAngular的区别

相同点:都支持指令,包括内置指令和自定义指令;都支持过滤器,包括内置过滤器和自定义过滤器;都支持双向数据绑定;不支持低端浏览器

不同点:Angular的学习成本高,入门需要更加深厚的js功底,vueapi都比较简单直观;在性能上,Angular依赖对数据做脏检查,watcher越多性能越慢;vue使用基于依赖追踪的观察并使用异步队列更新,所有数据都是独立触发的

VueReact的区别

相同点:React采用特殊的jsx语法,vue在组建中推崇编写.vue特殊文件格式,两者对文件内容都有一些约定;两者都需要编译后使用;中心思想相同(一切都是组件,组件实例之间可以嵌套,都提供合理的钩子函数,可以让开发者定制化的去处理需求);都支持加载插件,支持mixins特性

不同点:React采用的Virtual DOM会对渲染出来的结果做脏检查;vue在模板中提供了指令,过滤器等,可以方便快捷操作Virtual DOM

十、在vue组件中,如何让css只在当前组件起作用

style标签中添加scoped属性即可,如<style scoped></style>

十一、v-ifv-show的区别

v-if:真正的条件渲染,它会确保在切换过程中条件内的事件监听器和子组件适当的销毁和重建,也是惰性的,直到条件第一次变为真的时候,才会渲染条件块

v-show:不管条件为真为假,都会进行渲染,只是通过样式设置display属性来控制DOM的显示和隐藏

两者应用场景:v-if适用于条件较少改变不需要频繁切换条件的场景;v-show适用于频繁切换条件的场景

十二、nextTick是用来做什么的

nextTick用在下次DOM更新循环结束之后执行延迟回调,在修数据之后立即调用这个方法,获取更新后的DOM

十三、Vue组件中data为什么是函数

组件应该是可复用的vue实例,一个组件被创建好之后就可能被用于各个地方,不管组件被复用多少次,组件中的data数据都应该是相互隔离、互不影响的;

基于这一理念,如果data是一个对象,而对象又属于引用类型,如果某一处复用的组件内的data数据发生改变,其他复用地方的组件data也会发生改变,这是不应该的

如果data作为函数返回一个对象,那每一个实例之间的data属性相互独立,就不会相互影响了

十四、计算属性computed和事件methods有什么区别
  1. computed是响应式的,methods并非响应式
  2. computed定义的成员是像属性一样访问,而methods的成员必须是函数形式调用
  3. computed是带缓存的,只有当其依赖的属性发生变化时才会重新计算,methods里函数每次调用都会执行
  4. computed中的成员可以定义一个函数作为只读属性也可以定义get/set变成可读写属性,这点methods无法实现
十五、计算属性computed和监听器watch有什么区别
computed
  1. 依赖缓存,只有依赖的属性发生变化,才会进行计算
  2. 不支持异步,若包含异步操作,则监听无效
  3. 适用于一个属性依赖一个或多个属性
  4. 不能是data中的属性或者是父组件传过来的props中的属性,否则会报错
  5. 如果计算属性以函数形式调用默认走get方法,若设置对象形式设置get方法和set方法,当数据变化时,调用set方法
watch
  1. 不支持缓存,数据变化直接触发计算更新
  2. 支持异步
  3. 适合用于一个属性发生变化,改变多个属性
  4. 监听数据必须是data中声明过的属性或者父组件传过来的props属性,否则会报错
  5. 监听函数接收两个参数,一个参数是最新的值,另一个参数是旧值
十六、对比jQueryVue有什么不同

jQuery专注于视图层,通过操作DOM去实现页面的一些逻辑渲染;

Vue专注于数据层,通过数据的双向绑定,最终表现在DOM层,减少了DOM操作;且使用组件化思维,使得项目各组件职责清晰,提高了开发效率,方便重复利用,便于协同开发

十七、Vue怎么自定义指令

使用Vue中的api,如下所示

全局注册自定义指令:

Vue.directive('demo',{
	inserted: function(el){el.focus()},
	bind: function(el,binding,vnode){
		console.log(binding.value)
	}
})

局部注册自定义指令:

directives:{
	demo:{
		inserted: function(el){el.focus()}
	}
}
十八、Vue怎么自定义过滤器

使用Vue中的api,如下所示

//自定义过滤器
Vue.filter('my-filter',function(value){
	return value*2
})
//使用
<span v-text="num | my-filter"></span>
十九、对keep-alive的了解

keep-alive是一个抽象组件,自身不会渲染成一个DOM元素,也不会出现在组件的父组件链中;只能包含一个直属子组件(与一个组件只有一个根元素类似),当包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们;

可以用于缓存组件保留状态,避免重新渲染,具有以下特性:

  • include:表示只有名称匹配的组件会被缓存
  • exclude:表示任何名称匹配的组件都不会被缓存
  • max:表示最多可缓存的组件实例
  • 对应两个钩子函数:activateddeactivated,在组件激活和销毁时触发
二十、Vuekey的作用

key的特殊属性主要用在**Vue的虚拟DOM算法**,在新旧nodes对比辨识VNodes

如果不使用keyVue会使用一种最大限度减少动态元素并且尽可能的尝试就地修复或复用相同类型元素的算法,不设置key可能会在列表更新时引发一些隐蔽bug,或者使用过渡切换时无效果

如果使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素;有相同父元素的子元素必须有唯一的key,重复的key会造成渲染错误

使用key原理vuepatch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能;最常用的用例是结合v-for做循环渲染时

二十一、Vue的核心是什么

数据驱动、组件化

二十二、介绍单页面SPA应用、介绍优缺点

SPA(single page application)单页面应用:只有一个主页面的应用,在Web页面初始化时一次加载相应的htmlcssjavascript。用户切换不同的功能模块,是利用路由机制切换相关组件,实现的html内容的替换,仅刷新局部资源,避免整个页面的重新加载

优点

  1. 用户体验好,速度快,内容的改变不需要重新加载整个页面,避免不必要的重复渲染
  2. SPA相对服务器压力较小
  3. 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理

缺点

  1. 初次加载耗时过多,可对初次文件进行优化,按需加载
  2. 前进后退路由管理,由于一个页面显示所有内容,所以不能使用浏览器的前进后退功能,所有页面需要自己建立堆栈管理
  3. 只有一个页面,对SEO优化不友好
二十二点一、如何优化SPA应用首屏加载速度慢的问题

主要分为两大部分:资源加载优化和页面渲染优化

资源加载优化
  1. 减少资源大小
    • 使用代码压缩
    • 图片压缩
    • 代码拆分:比如路由懒加载,不同路由对应的组件分割成不同的代码块,切换路由时才会加载相应的组件,按需加载
  2. 减少http请求次数
    • 利用http强缓存
    • 使用本地存储
    • 合并请求(比如使用雪碧图等)
  3. 提高http请求响应速度
    • 使用CDN
    • 使用强缓存
    • 使用DNS:请求就近资源,减少网络传输时间,提高响应速度
  4. 优化资源加载的时机
    • 按需加载:比如UI框架按需加载,引入需要的组件,不要一次性全部引入
    • 路由懒加载:需要资源的时候才去加载,不一次性加载所有资源,节省时间
  5. 优化资源、内容加载的方式
页面渲染优化
  1. 优化http代码
    • js外链放在底部
    • css外链放在顶部
    • 减少DOM数量
  2. 优化jscss代码
    • 长任务分段执行
    • 减少重排重绘
    • 降低css选择器的复杂性
二十三、Vue有哪些指令

v-forv-ifv-showv-textv-htmlv-bindv-oncev-on

四、Vue实现数据双向绑定的原理

vue数据双向绑定是指:数据变化驱动视图,视图变化更新数据

实现数据双向绑定过程如下:

  1. 监听器Observer:对data数据对象进行遍历,利用Object.defineProperty()对各个属性进行gettersetter劫持
  2. 解析器Compile:解析vue模板指令,将模板中的变量都替换成数据,渲染页面,并为每个指令节点绑定更新函数,添加监听数据的订阅者Watcher,一旦数据有变动收到通知,调用更新函数进行数据更新
  3. 订阅者Watcher:是ObserverCompile之间通信的桥梁,主要任务是订阅Observer属性变化的消息,触发解析器Compile的对应更新函数
  4. 订阅器Dep:订阅器采用发布-订阅的设计模式,用来收集订阅着Watcher,对监听器Observe和解析器Compile进行统一管理

简单说:通过Observer来监听自己的数据变化,通过Compile来解析编译模板指令(vue中是用来解析{{}}),最终利用Watcher搭起ObserverCompile之间的通信桥梁,达到数据变化->视图更新;视图交互变化(input)->数据变更双向绑定效果

二十四、简述Vue的响应式原理(第四点比较:Vue实现数据双向绑定的原理)

当一个Vue实例创建时,Vue会遍历data返回对象的所有属性,用Object.defineProperty将他们转为getter/setter,并在内部追踪相关依赖,在属性被访问和修改时通知变化

每个组件实例都有相应的watcher 实例 ,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而使它关联的组件得以更新

二十五、解释单向数据流和双向数据绑定

单向数据流:顾名思义,数据流是单向的,数据以单一方向传输,便于追踪变化

比如父子组件,props的更新会向下传递到子组件,反过来则不行,这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解;其次就是UI改变,就要走action-state-view-action流程

双向数据绑定:数据之间是相通的,数据变更的操作隐藏在框架内部,优点是在表单交互较多的场景下,会简化大量与业务无关的代码;缺点是无法追踪局部状态的变化,增加了出错时debug的难度

二十六、Vue中如何在组件内部实现一个双向数据绑定

假设有一个输入框组件,用户在输入时,同步父组件页面中的数据

具体思路:父组件通过props传值给子组件,子组件通过$emit来通知父组件修改相应的props值,具体实现如下:

//子组件
const component = {
    props:['value'],
    template:`
		<div>
			<input type="text" @input="handleInput" :value="value"/>
		</div>
	`,
    data(){
        return{}
    },
    methods:{
        handleInput(e){
            this.$emit('input',e.target.value)
        }
    }
}

//父组件
new Vue({
    components:{CompOne:component},
    el:'#root',
    template:`
		<div>
			<!--><comp-one :value="value" @input="value = arguments[0]"></comp-one>->
			<comp-one v-model="value"></comp-one>//简化写法
		</div>
	`,
    data(){
        return{
            value:'123'
        }
    }
})
二十七、v-model的原理是什么

v-model本质上是语法糖,在表单inputtextareaselect等元素上创建双向数据绑定,负责监听用的输入事件以更新数据,对一些极端场景进行一些特殊处理

v-model在不同的表单元素上使用不同属性抛出不同事件

  1. texttextarea元素使用valueinput事件
  2. checkBoxradio使用checkedchange事件
  3. select使用value作为propchange事件

如果是自定义组件,v-model默认会利用名为valueprop和名为input的事件

二十八、Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决

如果给data中的对象属性添加一个新的属性,该属性可以添加成功,但是视图并未实时更新,因为其不是响应式属性;Vue实例在初始化的时候会遍历data中的所有属性利用Object.defineProperty为每一个属性添加getter/setter,并在内部追踪依赖,当数据被读取或者发生变更时会通知watcher重新计划,使得关联的组件进行更新

解决办法是使用this.$set,将其处理成一个响应式属性。

二十九、deleteVue.delete删除数组有何区别

delete使被删除的元素变为空,其他元素的键值不变

Vue.delete删除元素,并重新排序数组的键值

三十、网页从输入网站到渲染完成经历了哪些过程

大致分为8步:

  1. 浏览器地址栏输入URL并回车
  2. 浏览器查找当前URL是否存在缓存,并比较缓存是否过期
  3. DNS解析URL对应的ip
  4. 根据IP建立TCP连接(三次握手)
  5. 浏览器向服务器发起HTTP请求
  6. 服务器处理请求,返回数据,浏览器接收HTTP响应
  7. 生成DOM树,解析cssjs,渲染页面,直至显示完成
  8. 关闭TCP连接(四次挥手)
三十一、jQuery获取的DOM对象和原生的DOM对象有何区别

jQuery获取的DOM对象是数组对象;js原生获取的DOM对象是一个对象,是不同的对象类型

原生转jQuery

let div = document.getElementById('box')
let $div = $(div)

jQuery转原生

let $div = $('#box')
let div = $div[0]
三十二、jQuery如何扩展自定义方法
//方法一
(jQuery.fn.myMethod = function(){
	alert('myMethod')
})
//方法二
(function($){
	$.fn.extend({
		myMethod:function(){
		alert('myMethod')
		}
	})
})(jQuery)

//使用
$('#div').myMethod()
三十三、介绍一下vuemixins

mixins选项接受一个混入对象的数组,这些混入对象可以像正常的实例对象一样包含实例选项,这些选项最终被合并到实例的选项当中去

  1. 如果出现键名冲突的,实例中的会覆盖混入对象中的
  2. mixins被各组件调用,其属性和方法是独立,不相互影响的
  3. mixins中混合对象的钩子函数在组件钩子函数之前先调用

用处:可以定义公用的变量和方法,在每个组件中使用,变量和方法相互独立

与公共组件的区别

组件:在父组件引入子组件,相当于在父组件中开辟出一片独立的空间给子组件使用,根据props来传值,本质上是互相独立的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值