Vue北京⾯试题
vue北京⾯试题
1、Vue 解决了什么问题
① 虚拟 dom:dom 操作时⾮常耗性能的,不再使⽤原⽣的 dom 操作节点,极⼤的解放 dom 操作,但具体操作的还是 dom,不过是换了⼀种⽅式。
② 视图、数据、结构分离:使数据的更改更为简单,不需要进⾏逻辑代码的修改,只需要操作数据就能完成相关操作。
③ 组件化:把⼀个单页应⽤中的各种模块拆分到⼀个⼀个单独的组件中,便于开发,以及后期的维护
2、MVVM 的理解
MVVM 就是 Model-View-ViewModel 的缩写,MVVM 将视图和业务逻辑分开。
react组件之间通信
View:视图层,Model 数据模型,⽽ ViewModel 是把两者建⽴通信的桥梁。
在 MVVM 框架下,View 和 Model 之间没有直接的联系,⽽是通过 ViewModel 进⾏交互。View 和 View
Model 之间以及 Model 和ViewModel 之间的交互都是双向的,因此 view 数据的变化会同步到 Model 中,⽽ Model 数据的变化也会⽴即反映到 View 上。可以说它们两者是实时更新的,互相影响。 ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,⽽ View 和 Model 之间的同步⼯作完全是⾃动的,因此开发者只需要关注业务逻辑,不需要⼿动操作 DOM,也不需要关注数据状态的同步问题,这些都由 MVVM 统⼀管理。
3、如何实现⼀个⾃定义组件,不同组件之间是如何通信的
请永远牢记 vue 是单向数据流
⾃定义组件:
创建⼦组件的⽂件,建⽴组件的模板,把架⼦搭起来,也就是在⼦组件中写好<template>视图层,<script>逻辑层<style>css样式层。然后定义好props⾥⾯的数据,实现⼦组件需要的逻辑代码后,也就封装好了,然后直接调⽤即可。调⽤的花import引⼊,同时在⽗组件<script>(逻辑层)中的components这个对象中写⼊组件名称,最后挂载到⽗组件的template中即可。
组件通信:
①props / $emit
⽗组件通过 props 的⽅式向⼦组件传递数据,⽽通过$emit ⼦组件可以向⽗组件通信。
②$children / $parent
this.$children[0].msg = "hello world" //⽗组件修改⼦组件data中的数据
this.$parent.mag //⼦组件拿到⽗组件 data 中的数据
$children的值是数组,$parent 的值是个对象复制代码
parent,
注意:children 它们的⽬的是作为访问数组的应急⽅法,更推荐⽤ props 和 events 实现⽗⼦组件通信。
③provide / inject
这是 vue2.2.0 新增的 api,简单来说就是⽗组件中通过 provide 来提供变量,然后再⼦组件中通过 inject 来注⼊变量。
//⽗组件
export default{
name:"A",
provide:{
for:"demo"
},
components:{
comB
}
}
//⼦组件
export default{
name:"B",
inject:["for"],
data(){
demo:this.for
}
}
④ref / refs
ref:如果在普通的 DOM 元素上使⽤,引⽤指向的就是 DOM 元素;如果⽤在⼦组件上,引⽤就指向组件实例,可通过实例直接调⽤组件的⽅法或访问数据。
//⽗组件
<template>
<component-a ref="comA"></component-a>
</template>
<script>
export default{
mounted(){
const comA = this.$refsA;
console.log(comA.name)//Vue.js
comA.sayHello() //hello
}
}
</script>
//⼦组件
export default{
data(){
return {
name:"Vue.js"
}
},
methods:{
sayHello(){
console.log("hello")
}
}
}
⑤eventBus(Bus 总线):
//⾸先在 src 中创建⼀个 Bus ⽂件夹 => index.js
import Vue from "vue";
export default new Vue({
})
//⼦组件 1(发送数据的组件)
<button @click="add()">点击</button>
import Bus from "@/Bus"
add(){
Bus.\$emit("add",t);
}
//⼦组件 2(接受数据的组件)
<p>{{tit}}</p>
import Bus from "@/Bus";
created(){
Bus.$on("add",(data) => {
this.tit = data;
})
}
⑥Vuex;
⑦LocalStorage;
⑧$attrs / $listeners
将数据挂在到⼦组件的标签上去后,在⼦组件中使⽤this.$attrs直接获取到所有挂载的数据,返回的是⼀个对象。
4、nextTick 的理解
使⽤ nextTick 的原因:Vue 是异步修改 DOM 的,并且不⿎励开发者直接接触 DOM,但是有时候需要必须对数据更改后的 DOM 元素做相应的处理,但是获取到的 DOM 数据并不是更改后的数据,这时候就需要 this.$nextTick();
原理:Vue 通过异步队列控制 DOM 更新和 nextTick 回调函数先后执⾏的⽅式。
使⽤:
//HTML
<button @click="change()">按钮</button><h1 ref="gss">{{msg}}</h1>
//JS
export default{
name:"app",
data(){
return {
msg:"123"
}
},
methods:{
change(){
this.msg = "456";
console.fs["gss"].innerHTML)//123
this.$nextTick(function(){
console.fs["gss"].innerHTML)//456
})
}
}
}
5、Vue 的⽣命周期(11 个钩⼦函数)
⑴beforeCreate(创建前):在此⽣命周期函数执⾏的时候,data 和 methods 中的数据都还没有初始化。
⑵created(创建后):在此⽣命周期函数中,data 和 methods 都已经被初始化好了,如果要调⽤ methods 中的⽅法,或者操作 data 中的数据,最早只能在 created 中操作。
⑶beforeMount(载⼊前):在此⽣命周期函数执⾏的时候,模板已经在内存中编译好了,但是尚未挂载
到页⾯中去,此时页⾯还是旧的。
⑷mounted(载⼊后):此时页⾯和内存中都是最新的数据,这个钩⼦函数是最早可以操作 dom 节点的⽅法。
⑸beforeUpdate(更新前):此时页⾯中显⽰的数据还是旧的,但是 data 中的数据是最新的,且页⾯并未和最新的数据同步。
⑹Updated(更新后):此时页⾯显⽰数据和最新的 data 数据同步。
⑺beforeDestroy(销毁前):当执⾏该⽣命周期函数的时候,实例⾝上所有的 data,所有的 methods 以及过滤器…等都处于可⽤状态,并没有真正执⾏销毁。
⑻destroyed(销毁后):此时组件以及被完全销毁,实例中的所有的数据、⽅法、属性、过滤器…等都已经不可⽤了。
//下⾯两个钩⼦函数⼀般配合使⽤
⑼activated(组件激活时):和上⾯的 beforeDestroy 和 destroyed ⽤法差不多,但是如果我们需要⼀个实例,在销毁后再次出现的话,⽤ beforeDestroy 和 destroyed 的话,就太浪费性能了。实例被激活时使⽤,⽤于重复激活⼀个实例的时候
⑽deactivated(组件未激活时):实例没有被激活时。
⑾errorCaptured(错误调⽤):当捕获⼀个来⾃后代组件的错误时被调⽤
6、虚拟 DOM 原理
虚拟 DOM,其实就是⽤对象的⽅式取代真实的 DOM 操作,把真实的 DOM 操作放在内存当中,在内存中的对象⾥做模拟操作。当页⾯打开时浏览器会解析 HTML 元素,构建⼀颗 DOM 树,将状态全部保存起来,在内存当中模拟我们真实的 DOM 操作,操作完后⼜会⽣成⼀颗 dom 树,两颗 DOM 树进⾏⽐较,根据 diff 算法⽐较两颗 DOM 树不同的地⽅,只渲染⼀次不同的地⽅。
补充:
diff 算法核⼼:
① 如何⽤ vnode ⽣成⼀个 dom 的节点
patch ⽅法 patch(container, vnode)patch(vnode, newVnode)
②vnode 和 newVnode 的对⽐
③ 修改改变的 dom 节点
replacechildrencreateElement 复制代码
7、双向绑定的原理?数据劫持?
vue 实现数据双向绑定主要是:采⽤数据劫持结合发布者-订阅者模式的⽅式。
通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。
当把⼀个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时。Vue 将遍历它的属性,⽤ Object.defineProperty 将它们转为getter/setter。⽤户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue 的数据双向绑定 将 MVVM 作为数据绑定的⼊⼝,整合 Observer,Compile 和 Watcher 三者。通过 Observer 来监听⾃⼰的model 的数据变化,通过 Compile 来解析编译模板指令(vue 中是⽤来解析 {{}})。最终利⽤ watcher 搭起 observer 和 Compile 之间的通信桥梁,达到数据变化 —>视图更新;
数据劫持:当我们访问或设置对象的属性的时候,都会触发相对应的函数,然后在这个函数⾥返回或设置属性的值。我们可以在触发函数的时候动⼀些⼿脚做点我们⾃⼰想做的事情,这也就是“劫持”操作。
8、Proxy 相⽐于 defineProperty 的优势
Vue3.0 摒弃了 Object.defineProperty,改为基于 Proxy 的观察者机制探索。
⾸先说⼀下 Object.defineProperty 的缺点:
①Object.defineProperty ⽆法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实施响应。
②Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进⾏遍历。Vue2.X ⾥,是通过递归 + 遍历
data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持⼀个完整的对象才是更好的选择。
⽽要取代它的 Proxy 有以下两个优点
可以劫持整个对象,并返回⼀个新对象。
有多种劫持操作(13 种)
补充:
Proxy 是 ES6 新增的⼀个属性,翻译过来的意思就是代理,⽤在这⾥表⽰由它来“代理”某些操作。Proxy 让我们能够以简洁易懂的⽅式控制外部对象的访问,其功能⾮常类似于设计模式中的代理模式。
Proxy 可以理解为,在⽬标对象之前设⼀层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了⼀种机制,可以对外界的访问进⾏过滤和改写。
使⽤ Proxy 的核⼼优点是可以交由它来处理⼀些⾮核⼼逻辑(如:读取或设置对象的某些属性前记录⽇志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。从⽽可以让对象只需要关注核⼼逻辑,达到关注点分离,降低对象复杂度等⽬的。
9、watch、computed 和 methods 的区别
methods 在重新渲染的时候每次都会被重新的调⽤;
computed 是⾃动监听依赖值的变化,从⽽动态返回内容,主要⽬的是简化模板内的复杂运算。所以区别来源于⽤法,只是需要动态值,那就⽤ computed ;需要知道值的改变后执⾏业务逻辑,才⽤ watch。
watch 也可以影响数据的变化,当绑定的数据⽅法变化时触发响应的函数,需要在数据变化时执⾏异步或开销较⼤的操作时使⽤watch。
10、virtual-dom 原理实现(虚拟 dom)
virtual-dom(简称 vdom)的概念⼤规模的推⼴还是得益于 react 的出现,virtual-dom 也是 react 这个框架的⾮常重要的特性之⼀。相⽐于频繁的⼿动去操作 dom ⽽带来性能问题,vdom 很好的将 dom 做了⼀层映射关系,进⽽将在我们本需要直接进⾏ dom 的⼀系列操作,映射到了操作 vdom,⽽ vdom 上定义了关于真实 dom 进⾏的创建节点,删除节点,添加节点等⼀系列复杂的 dom 操作,并将这些操作放到 vdom 中进⾏,这样就通过操作 vdom 来提⾼直接操作的 dom 的效率和性能。
在vue的整个应⽤⽣命周期当中,每次需要更新视图的时候便会使⽤vdom,vdom算法是基于**snabbdom**算法所做的修改。
实现:
①⽤js对象构造⼀个虚拟的dom树,插⼊到⽂档中;
②状态变更时,记录新树和旧树的差异;
③把上⾯的差异构建到真正的dom中。
12、vue-router
❄ 单页⾯路由跳转的⽅式:
①hash(哈希默认)模式:使⽤ URL hash 值来作路由。默认模式。
②history(mode:history)模式:依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
③abstract模式(严格模式):⽀持所有 JavaScript 运⾏环境,如 Node.js 服务器端。
根据mode参数来决定采⽤哪⼀种⽅式。
vue-router的实现原理(核⼼):更新视图但不重新请求页⾯。
❄ vue-router 登陆权限的判断

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。