Vue常见面试题总结


1、为何组件的data必须是一个函数

vue实例中的data属性既可以是一个对象,也可以是一个函数

组件中定义data属性,只能是一个函数

如果为组件data直接定义为一个对象 则会得到警告信息 警告说明:返回的data应该是一个函数在每一个组件实例中

在我们定义好一个组件的时候,vue最终都会通过Vue.extend()构成组件实例

vue组件可能会有很多个实例,采用函数返回一个全新data形式,
使每个实例对象的数据不会受到其他实例对象数据的污染



根实例对象data可以是对象也可以是函数(根实例是单例),不会产生数据污染情况

组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。
采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象

2.vue常用的指令

v-model 多用于表单元素实现双向数据绑定

v-for 格式: v-for="(item,index) in/of 数组json" 循环数组或json

v-show 显示内容 ,通过display=block/none来控制元素隐藏出现

v-hide 隐藏内容 同上

v-if 显示与隐藏 (dom元素的删除添加 同angular中的ng-if 默认值为false)

v-else-if 必须和v-if连用

v-else 必须和v-if连用 不能单独使用 否则报错 模板编译错误

v-bind 动态绑定 作用: 及时对页面的数据进行更改

v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面

v-text 解析文本

v-html 解析html标签

v-bind:class 三种绑定方法 1、对象型 ‘{red:isred}’ 
	2、三元型 ‘isred?“red”:“blue”’
	3、数组型 ‘[{red:“isred”},{blue:“isblue”}]’

v-once 进入页面时 只渲染一次 不在进行渲染

3.v-if与v-show的区别

都可以动态控制着dom元素的显示隐藏

v-if: **控制DOM元素的显示隐藏是将DOM元素整个添加或删除;**

v-show: **控制DOM 的显示隐藏是为DOM元素添加css的样式display,设置none或者是block,
DOM元素是还存在的**

1、性能对比

v-if有更高的切换消耗;
v-show有更高的初始渲染消耗

2、使用场景

v-if适合运营条件不大可能改变的场景下;
v-show适合频繁切换;

4.Vue的双向数据绑定原理(极简版)

vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。

主要由三部分:

observer主要是负责对Vue数据进行数据劫持,使其数据拥有get和set方法 
指令解析器负责绑定数据和指令,绑定试图更新方法 
watcher负责数据监听,当数据发生改变通知订阅者,调用视图更新函数更新视图

5.Vue组件通信

请参考详细内容

6.什么是vuex?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储和管理程序的所有组件的数据

1.vuex的核心由五部分组成

state: 数据

actions:可以包含异步操作

mutations: 唯一可以修改state数据的场所

getters: 类似于vue组件中的计算属性,对state数据进行计算(会被缓存)

modules:模块化管理store(仓库),每个模块拥有自己的 state、mutation、action、getter

2.详述Vuex运行机制

在组件中通过dispatch来调用actions中的方法
在actions中通过commit来调用mutations中的方法,
在mutations中可以直接操作state中的数据,
state的数据只要一发生改变立马响应到组件中

7.vue监听和深度监听watch

watch可以让我们监控一个值的变化,从而做出相应的反应。

通过watch属性可以监控data属性中name值的变化,定义监控时,name这个值对应的是一个监控处理函数name()。

将name属性和对话框绑定,并在对应页面绑定name值,然后在浏览器中测试,
页面上数据会随着对话框中输入值的变化而变化。

其中监控处理函数name有两个参数:

v1表示当前监控的值。
v2表示上一次监控的值。
如果监控的是一个对象,需要进行深度监控,才能监控到对象中属性的变化

8.Vue 中 methods,computed, watch 的区别

computed具有缓存性 ,依赖于属性值,只有属性发生改变的时候才会重新调用
methods是没有缓存的,只用调用,就会执行,一般结合事件来使用
watch没有缓存性 监听data中的属性 属性值只要发生变化就会执行 可以利用他的特性做一些异步的操作

9.MVVM和MVC

MVC: Model(模型) View(视图) Controller(控制器)

 简单的理解:视图请求数据,将请求发送至控制器,控制器再将请求发送给模型,模型去查找数据,
 找到之后传给控制器,控制器再传给视图进行渲染。

MVVM: Model 代表数据模型 View 代表UI视图 ViewModel负责监听,Model中数据的改变并且控制视图的更新

简单理解:视图请求数据,将请求发送至控制器,在控制器的两端具有监听机制,直接调用模型的数据,
 一端改变全部改变,利用数据劫持, 结合订阅者和发布者模式,实现数据的双向绑定
简单理解就是双向数据绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,
数据也会跟着同步变化。

10.vue中的修饰符

.stop 阻止事件冒泡; ​ 
.capture 设置事件捕获; ​ 
.self 只是监听触发改元素的事件; ​ 
.once 只触发一次; ​ 
.trim 去除文本框左右空格 ​ 
.bumber 把文本框的内容转换成数字 ​ 
.prevent - 阻止默认事件; ​ 
.native 触发js原生的事件 ​ 
.keyup.enter ;  .keyup.space

11.vue中如何自定义指令directive

我们看到的v-开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能,对普通 DOM元素进行底层操作,这时候就会用到自定义指令。除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令

1、 如何自定义指令

注册一个自定义指令有全局注册与局部注册
全局注册注册主要是用过Vue.directive方法进行注册 Vue.directive第一个参数
是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()  // 页面加载完成之后自动让输入框获取到焦点的小功能
  }
})

局部注册通过在组件options选项中设置directive属性
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus property,如下:
<input v-focus />

2、列举常用指令以及作用

v-html 解析输出变量,能解析html; ​ 
v-text 解析输出变量; ​ 
v-bind 给标签绑定属性; ​
v-on 给元素绑定事件; ​ 
v-pre 跨过当前的标签不解析 ​ 
v-cloak 解决差值表达式闪烁的问题; ​ 
v-model 实现数据的双向绑定,只能适用于表单元素; ​
v-for 可以循环遍历数据; ​
v-if 条件输出; ​
v-show 条件输出

3.钩子函数

自定义指令也像组件那样存在钩子函数:

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

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

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

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

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

4.使用自定义指令背景

1 输入框自动聚焦

2 下拉菜单

3 相对时间转换

12.Vue之filter

过滤器就是一个数据经过了这个过滤器之后出来另一样东西。

vue中的过滤器分为两种:局部过滤器和全局过滤器

全局过滤器通过 Vue.filter('filtername',fliterFn) 来定义,它定义好了之后,在所有的组件内都可以使用

局部过滤器,定义在组件内部 filters 属性上.它只能在此组件内部使用

13.vue路由,路由传参(parmas,query)

params和query的区别?

1.用法上的 刚query要用path来引入,params要用name来引入,接收参数都是类似的,
分别是this.$ route.query.name和this.$route.params.name 

2.展示上的 query更加类似于我们ajax中get传参,params则类似于post,
说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示 3.params是路由的一部分,必须要有。
query是拼接在url后面的参数,没有也没关系

14.keep-alive

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。

1.作用

在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,
减少加载时间及性能消耗,提高用户体验性

参数(Props)

include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例

对生命周期函数变化

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated

15.v-for中为何要使用key

key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,
更准确, 更快的找到对应的vnode节点

key的作用就是更新组件时判断两个节点是否相同。相同就复用,不相同就删除旧的创建新的
使用index作为key时,和不带key是一样,index作为key时每个列表的index更新前后都是一样的,
可以直接被复用,	用ID作为key是就不会被复用了,因为ID是唯一的标识。

16.vue中的slot(插槽)

1 、slot 基本用法

插槽指允许将自定义的组件像普通标签一样插入内容

2、具名插槽

给具体的插槽命名,并在使用的时候传入插槽的名称

3 、作用域插槽

将定义插槽的变量作用域到使用插槽中

17.vue之prop

单项数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,
但是反过来则不行。
每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
这意味着你不应该在一个子组件内部改变 prop。

单项数据流不允许修改

在组件中修改 prop 传递过来的数据 Vue 会发出警告,所以有两种常见的用法去修改 prop 传递过来的值
本地data中定义属性,并将 prop 作为初始值
使用computed 将prop 的值进行处理,

总结

prop 数据单项传递,父影响子,子不影响父
不能在组件中直接修改 prop 传递过来的值,Vue 会给出警告
prop 验证时,会在实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 
在 default 或 validator 函数中是不可用的
非 prop 特性,组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。

18.Vue中的$nextTick()

Vue 在更新 DOM时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,
视图需要等队列中所有数据变化完成之后,再统一进行更新

如果没有 nextTick 更新机制,那么每次更新值都会触发视图更新,有了nextTick机制,只需要更新一次,
所以nextTick本质是一种优化策略

1、使用场景

如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()
第一个参数为:回调函数(可以获取最近的DOM结构)
第二个参数为:执行函数上下文

组件内使用 vm.$ nextTick () 实例方法只需要通过this.$nextTick(),并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

$nextTick()会返回一个 Promise 对象,可以是用async/await完成相同作用的事情

2.小结:

把回调函数放入callbacks等待执行
将执行函数放到微任务或者宏任务中
事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调

19.vue修改数据页面不重新渲染

原因:

组件初始化时,对data中的item进行递归遍历,对item的每一个属性进行劫持,添加set,get方法。
我们后来新加的newProperty属性,并没有通过Object.defineProperty设置成响应式数据,
修改后不会视图更新。

解决方案

Vue 不允许在已经创建的实例上动态添加新的响应式属性
若想实现数据与视图同步更新,可采取下面三种解决方案:
**1. Vue.set()**
**2. Object.assign()**
**3. $forcecUpdated()**

Vue.set( target, propertyName/index, value )

参数:

target:要修改的对象或数组
propertyName/index:属性或下标
value:修改后的value值

Object.assign()

直接使用Object.assign()添加到对象的新属性不会触发更新
应创建一个新的对象,合并原对象和混入对象的属性


如果为对象添加少量的新属性,可以直接采用Vue.set()
如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象
如果你需要进行强制刷新时,可采取$forceUpdate() (不建议)

20.vue2与vue3的区别

1. vue2和vue3双向数据绑定原理发生了改变

vue2 的双向数据绑定是利用ES5 的一个 API 
Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。

vue3 中使用了 es6 的 ProxyAPI 对数据代理。

相比于vue2.x,使用proxy的优势如下:

1.defineProperty只能监听某个属性,不能对全对象监听

2.可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)

3.可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化

2. 更精准的变更通知。

比例来说:2.x 版本中,使用 Vue.set 来给对象新增一个属性时,这个对象的所有 watcher 都会重新运行;
3.x 版本中,只有依赖那个属性的 watcher 才会重新运行。

21.生命周期共有几个?分别在什么时候使用?

1.创建

beforeCreate() 在执行这个钩子的时候 只有一些实例本身的事件和生命周期函数 用户自定义不能使用 
created() 最早开始使用 data和methods中数据的钩子 

2.挂载

beforeMount() 指令已经解析完毕 内存中已经生成dom数
mounted()dom已经渲染完毕 页面和内存的数据已经同步 

3.更新

beforeUpdate() 当data的数据发生改变会执行这个钩子 内存中数据是新的 页面是旧的
updated() 内存和页面都是新的

4.销毁

beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的可以做一些释放内存的操作 
(内存:定时器,事件监听,订阅发布) 

destroyed()已经销毁完毕 滴死周畏 


9.activated 被 keep-alive 缓存的组件激活时调用。该钩子在服务器端渲染期间不被调用。

10.deactivated被 keep-alive 缓存的组件停用时调用。该钩子在服务器端渲染期间不被调用。

11.errorCaptured (2.5.0新增)当捕获一个来自子孙组件的错误时被调用。
此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个 包含错误来源信息的字符串。
此钩子可以返回 false 以阻止该错误继续向上传播。

22.Object.defineProperty()方法有何作用

Object.defineProperty() 方法 直接在一个对象上定义一个新的属性

他有三个参数

.Object.defineProperty(obj,prop,descriptor)

obj 是定义属性的对象
prop 是定义的属性名
descriptor 属性描述符 

1.数据描述符

configurable 是否重新配置(删除) 布尔
enumerable 是否可枚举 布尔 (for in for of object.keys())
value 默认值
writable 是否可写 布尔

2.访问(存取)描述符

get set
它的返回值是被操作的对象 也就是obj参数
有两个回调函数 get set 访问(存取)描述符

23.v-if和v-for的优先级

参考此篇文章

24.Vue中的$nextTick()

1.NextTick是什么

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

我们可以理解成,Vue 在更新 DOM时是异步执行的。
当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新

$nextTick()详解

25.Vue-router钩子函数和执行顺序

vue-router钩子函数
vue-router钩子函数及组件生命周期执行

26.axios的封装

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。

安装

npm install axios; 

引入

一般我会在项目的src目录中,在里面新建一个http.js和一个api.js文件。
http.js文件用来封装我们的axios,api.js用来统一管理我们的接口。
  1. 使用elementui
import { Message,MessageBox } from 'element-ui'
  1. 先要在http.js里面引入axios
import axios from 'axios'
  1. 环境的切换

在我们开发项目的时候会有多种环境,就比如开发环境、测试环境、生产环境,使用axios.defaults.baseURL可以设置axios的默认请求地址。

//在开发环境中的测试 development
if(process.env.NODE_ENV == 'development') {
	axios.defaults.baseURL = 'http://120.53.31.103:84/'
}
//在生产环境中的测试 production
if(process.env.NODE_ENV == 'production') {
	axios.defaults.baseURL = 'https://wap.365msmk.com/'
}
//还有一种环境 debug

  1. 设置响应超时时间

通过axios.defaults.timeout设置默认的请求超时时间。如果超出了响应时间,就会告知用户当前请求超时,请刷新等等

//响应超时的时间
axios.defaults.timeout = 5000;

  1. 设置接口请求拦截
//接口请求拦截
axios.interceptors.request.use(
	config => {
		config.headers = { DeviceType : 'H5' } //设置响应头部
		return config
	}
)

  1. 使用promise返回axios请求的结果

    post :

export function get(url,params){
	return new Promise((resolve,reject) => {
		axios.get(url,{
			params : params
		}).then(res => {
			resolve(res)
		}).catch(err => {
			reject(err)
		})
	})
}

get :

export function post(url,params){
	return new Promise((resolve,reject) => {
		axios.post(url,params)
		.then(res => {
			resolve(res.data)
		})
		.catch(err => {
			reject(err.data)
		})
	})
}

现在是api.js中的内容

  1. 首先是要在api.js中引入刚刚封装好的axios
import {get,post} from '../http/http.js'
//get post 同时都要引入
  1. 然后就可以根据接口文档来进行数据的获取啦
//封装接口的方法
export function getAppIndex() {
	return get('api/app/recommend/appIndex')
}

export function getBanner() {
	return get('api/app/banner')
}

export function getTel() {
	return post('api/app/smsCode',{
			//这里用的是params传参,直接写{}就可,不用再声明params啦
			mobile : 18567391972,
			sms_type : 'login'
	})
}

  1. 最后就可以去vue页面通过生命周期来获取数据

注意,这里不一定 非要使用async函数,这只是其中一种方法

async mounted() {
			// 明星讲师、精品课程等等
			let res = await getAppIndex();
			
			//添加到数组
			this.startList = res.data.data.list
			
			// 轮播图列表
			var banner = await getBanner();
			// console.log('轮播图'+ banner)
			if (banner.data.code == 200) {
				this.bannerList = banner.data.data
			}

			// 手机验证码接口
			let Tel = await getTel();
			// console.log('手机验证码'+ Tel)

			//
		},

27.虚拟DOM和diff算法

虚拟dom是利用js描述元素与元素的关系。; 好处:是可以快速的渲染和高效的更新元素,提高浏览器的性能

diff算法:
优点:最终表现DOM上的修改只是部分的变更,可以保证高效的渲染,提高网页的性能
缺点:首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHtml慢点


虚拟DOM表现为一个Object对象。并且最少包含标签名(tag)、属性(attrs)和子元素对象(children)三个属性
创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应

在vue中如何应用虚拟DOM

定义真实DOM

<div id="app">
    <p class="p">节点内容</p>
    <h3>{{ foo }}</h3>
</div>

实例化vue

const app = new Vue({
    el:"#app",
    data:{
        foo:"foo"
    }
})

vue源码中render函数渲染虚拟DOM

(function anonymous() {
 with(this){return _c('div',{attrs:{"id":"app"}},[_c('p',{staticClass:"p"},
       [_v("节点内容")]),_v(" "),_c('h3',[_v(_s(foo))])])}})


通过vnode,vue可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作,经过diff算法得出一些需要修改的最小单位,在更新视图,减少了dom操作,提高了性能

diff算法

diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,
最后用patch记录的消息去局部更新dom
(diff的过程就是调用patch函数,比较新旧节点,一边比较一边给真是的DOm打补丁)

在vue中,作用于虚拟DOM渲染成真实dom的新旧VNode节点比较

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值