模拟面试题及答案
1.v-show和v-if区别
v-if如果条件不成立不会渲染当前指令所在节点的DOM元素v-show只是切换当前DOM的显示与隐藏
2.v-for中key的作用。
可以配合虚拟DOM提高更新的性能
3.vue中data为什么是function
避免组件中的数据互相影响。同一个组件被复用多次会创建多个实例,如果data 是一个对象的话,这些实例用的是同一个构造函数。为了保证组件的数据独立,要求每个组件都必须通过data 函数返回一个对象作为组件的状态。
4.vue中双向绑定的原理
1、vue双向数据绑定原理,又称vue响应式原理,是vue的核心,双向数据绑定是通过数据劫持结合发布者订阅者模式的方式来实现的,通过Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变
2、vue实现双向数据绑定的核心是Object.defineProperty()方法
3、Object.defineProperty(obj, prop, descriptor)方法,接收三个参数,分别为obj(定义其上属性的对象)prop(定义或修改的属性)descriptor(具体的改变方法),就是用这个方法来定义一个值,当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法
具体步骤:
第一步: 需要observer的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步: compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步: Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: 1、在自身实例化时往属性订阅器(dep)里面添加自己 2、自身必须有一个update()方法 3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步: MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
5.keep-alive的作用和被keep-alive声明的组件的生命周期
作用:在组件切换过程中将状态保留在内存中,防⽌重复渲染DOM,减少加载时间及性能消耗,提⾼⽤户体验性
在被keep-alive包含的组件/路由中,会多出两个生命周期的钩子:activated与deactivated。
Activated钩子调用时机:
官网说其是在服务器端渲染期间不被调用,说白了其就是在挂载后和更新前被调用的。但如果该组件中没有使用缓存,也就是没有被包裹的话,activated是不起作用的。
Deactivated钩子调用时机:keep-alive组件停用时调用
6.说一下vue的生命周期,以及生命周期都做了什么事情?
beforeCreate :实例初始化之后,数据观测之前调用
created:实例创建万之后调用。实例完成:数据观测、属性和方法的运算、watch/event 事件回调。无$el .
beforeMount:在挂载之前调用,相关render 函数首次被调用
mounted:了被新创建的vm.$el替换,并挂载到实例上去之后调用改钩子。
beforeUpdate:数据更新前调用,发生在虚拟DOM重新渲染和打补丁,在这之后会调用改钩子。
updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用改钩子。
beforeDestroy:实例销毁前调用,实例仍然可用。
destroyed:实例销毁之后调用,调用后,Vue实例指示的所有东西都会解绑,所有事件监听器和所有子实例都会被移除
- created:实例已经创建完成,因为他是最早触发的,所以可以进行一些数据、资源的请求。
- mounted:实例已经挂载完成,可以进行一些DOM操作。
- beforeUpdate:可以在这个钩子中进一步的更改状态,不会触发重渲染。
- updated:可以执行依赖于DOM的操作,但是要避免更改状态,可能会导致更新无线循环。
- destroyed:可以执行一些优化操作,清空计时器,解除绑定事件。
7.vue什么时候操作DOM比较合适?操作时发现有的组件获取不到,怎么办?
在vue中不建议操作DOM,但是如果我们在没办法的情况下,可以通过ref来进行DOM操作
mounted不能保证所有子组件被挂载,因此需要使用$nexttick
8.发送网络请求在哪个函数中?
一般放在mounted 中,保证逻辑统一性,因为生命周期是同步执行的,ajax 是异步执行的。单数服务端渲染ssr 同一放在created 中,因为服务端渲染不支持mounted 方法。
9.vue组件间传值有哪些方式
一丶父子组件传值 1.先在父组件中给子组件的自定义属性绑定一个 父组件的变量
2.在子组件的props属性中可以取出父组件给的值,props中的变量用法和data中变量用法完全一样,只不过值的来源不同
二丶子父组件传值
1.先在父组件中给子组件的 自定义属性 绑定一个父组件的函数
2.在子组件中 this.$emit(“父的处理函数”,this.数据) 触发父组件中的函数进行传参
三丶兄弟组件传值
事件总线:
就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件
1.创建全局空Vue实例:eventBus
2.具体页面使用$emit发布事件 - 传递值
3.具体页面使用$on订阅事件 - 接收组件值
注意:先进行监听,一旦emit发布事件后所有组件都可以监听到事件。所以传递参数的时候一定已经先进行了监听才能得到参数。比如在父组件中emit事件放在mounted钩子函数中,等待子组件创建并开始监听事件后再去触发emit发布事件。
4.$off()移除事件监听
事件订阅功能是eventBus对象完成的,与组件无关,如果用v-if销毁子组件的时候,会形成闭包,造成内存泄露,所有要在销毁组件的时候进行取消监听事件
四丶children与ref
1.$parent方法是在子组件中可以直接访问该组件的父实例或组件。
在父组件中定义一个切换显示页面执行中的显示方法。
在子组件中直接通过$parent去调用该方法
2.$children方法是在父组件中可以直接访问子组件的实例,但是不保证子组件的顺序。
3.ref 被用来给DOM元素或子组件注册引用信息。引用信息会根据父组件的 $refs 对象进行注册。如果在普通的DOM元素上使用,引用信息就是元素; 如果用在子组件上,引用信息就是组件实例。
在父组件中自定义一个表格组件,给子组件加上 ref属性 在父组件中就可以通过this.$refs.result去找到result子组件进行操作,比如把父组件的sdata直接放入子组件中
10.vue中改变数组内索引的值,数据不更新,如何处理
1:静默刷新(使用v-if的特性) 在修改值之后将元素销毁,然后在修改后的下一次DOM渲染完成时再显示出来,这样就会触发组件重新加载data的数据进行渲染,data中被修改的数据才是最新的
2:对于数组还可以使用splice方法(Vue对于数组的操作能识别变化的api包括splice):
this.arr.splice(你要修改的元素索引位置,1,修改后的值) 这是修改操作
this.arr.splice(你要添加到哪个元素的前面就写那个元素的索引+1,0,要添加的值) 这是添加操作
this.arr.splice(你要删除的元素索引,1) 这是删除操作
11.讲一下vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用**集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测**的方式发生变化。
vuex是采用集中式管理组件依赖的共享数据的一个工具,可以解决不同组件数据共享问题。
- 修改state状态必须通过**
mutations** - **
mutations**只能执行同步代码,类似ajax,定时器之类的代码不能在mutations中执行 - 执行异步代码,要通过actions,然后将数据提交给mutations才可以完成
- state的状态即共享数据可以在组件中引用
- 组件中可以调用action
12.插槽与作用域插槽的区别
插槽:
- 创建组件虚拟节点时,会将组件儿子的虚拟节点保存起来。当初始化组件时,通过插槽属性将儿子进行分类
{a:[vnode],b[vnode]} - 渲染组件时会拿对应的
slot属性的节点进行替换操作。(插槽的作用域为父组件)
作用域插槽:
- 作用域插槽在解析的时候不会作为组件的孩子节点。会解析成函数,当子组件渲染时,会调用此函数进行渲染。
- 普通插槽渲染的作用域是父组件,作用域插槽的渲染作用域是当前子组件。
13.那vue中是如何检测数组变化的呢?
数组就是使用object.defineProperty 重新定义数组的每一项,那能引起数组变化的方法我们都是知道的,pop 、push 、shift 、unshift 、splice 、sort 、reverse 这七种,只要这些方法执行改了数组内容,我就更新内容就好了,是不是很好理解。
- 是用来函数劫持的方式,重写了数组方法,具体呢就是更改了数组的原型,更改成自己的,用户调数组的一些方法的时候,走的就是自己的方法,然后通知视图去更新。
- 数组里每一项可能是对象,那么我就是会对数组的每一项进行观测,(且只有数组里的对象才能进行观测,观测过的也不会进行观测)
14.computed 和 watch 的区别和运用的场景?
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:
- 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
- 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
\