2.vue双向数据绑定的原理
VUE实现双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。
数据层和视图层中的数据同步。是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
3.vue生命周期
vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。
beforeCreate/created、beforeMount/mounted、beforeUpdate/updated、beforeDestroy/destroyed
4.axios底层实现(ajax)
原理:基于Promise的异步Ajax请求库
axios 原理还是属于 XMLHttpRequest, 因此需要实现一个ajax。
还需要promise对象来对结果进行处理。
5.组件传值
父传子:通过v-on绑定一个变量名称,然后再子组件里面用props接收。
子传父:子组件里面绑定一个方法,用$emit(函数名’func’,需要传递的参数)把参数传递给父组件。父组件里面定义好这个函数。
6.虚拟DOM树/抽象节点VNode
Vue.js将DOM抽象成一个以JavaScript对象为节点的虚拟DOM树,以VNode节点模拟真实DOM,可以对这颗抽象树进行创建节点、删除节点以及修改节点等操作,在这过程中都不需要操作真实DOM,只需要操作JavaScript对象后只对差异修改。
7.v-if和v-show的区别
举例:
v-show指令,元素隐藏时,只是增加了display:none的样式,而 v-if 指令则直接通过把该行删除来实现了隐藏效果。
8.v-for中key 值的作用
key的作用主要是为了高效的更新虚拟DOM
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素
在用v-for更新已渲染的元素列表时,会使用就地复用的策略,其实就是说列表数据修改的时候,它会根据key值去判断某个项是否修改,如果修改了就重新渲染,否则就复用之前的元素。
9.vue中插槽的作用
插槽就是Vue实现的一套内容分发的API,将元素作为承载分发内容的出口。
作用域插槽:作用域插槽其实就是带数据的插槽。可以把组件上的属性/值,在组件元素上使用!
插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。
具名插槽:就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。父组件通过 v-slot:[name]
的方式指定到对应的插槽中。
11.Vue-router 实现原理(Hash模式和History模式)
vue-router通过hash与History interface两种方式实现前端路由
更新视图但不重新请求页面,是前端路由原理的核心
在vue-router中,它提供mode参数来决定采用哪一种方式。
当你选择mode类型之后,程序会根据你选择的mode 类型创建不同的history对象(HashHistory或HTML5History或AbstractHistory)
更新页面流程如下:
1.HashHistory.push() 将新路由添加到浏览器访问历史的栈顶
1 $router.push() //调用方法
2 HashHistory.push() //根据hash模式调用,设置hash并添加到浏览器历史记录(添加到栈顶)(window.location.hash= XXX)
3 History.transitionTo() //监测更新,更新则调用History.updateRoute()
4 History.updateRoute() //更新路由
5 {app._route= route} //替换当前app路由
6 vm.render() //更新视图
2.History interface还可以对浏览器历史记录栈进行修改
window.history.pushState(stateObject, title, URL)
12.vue中兄弟组件的通信方式
//新建一个js文件, 这里叫做 bus.js;
//文件内容:
import Vue from 'vue';
export default new Vue();
//然后在你需要触发的 组件中引入 import bus from '文件路径'执行:bus.$emit('触发名称', 传输的数据 )
//------------------------------------------------------------------
//最后在你需要的通信的另一个组件中 mounted生命周期钩子中执行如下:
bus.$on('触发名称', res => {
//写你需要的方法
})
13.理解Vue的响应式系统
任何一个 Vue Component 都有一个与之对应的 Watcher 实例。
Vue 的 data 上的属性会被添加 getter 和 setter 属性。
当 Vue Component render 函数被执行的时候, data 就会被读, getter 方法会被调用, 此时 Vue 会去记录此 Vue component 所依赖的所有 data。(这一过程被称为依赖收集)
data 被改动时(主要是用户操作), 即被写, setter 方法会被调用, 此时 Vue 会去通知所有依赖于此 data 的组件去调用他们的 render 函数进行更新。
14.路由懒加载
15.vue中关于数组、对象的响应式问题
由于 JavaScript 的限制, Vue 不能检测以下变动的数组:
1. 利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
2. 修改数组的长度时,例如: vm.items.length = newLength
为了避免第一种情况,以下两种方式将达到像 vm.items[indexOfItem] = newValue 的效果, 同时也将触发状态更新:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice`
example1.items.splice(indexOfItem, 1, newValue)
避免第二种情况,使用 splice:
example1.items.splice(newLength)
只要在 data 中声明的基本数据类型的数据,基本不存在数据不响应问题,所以重点是数组和对象在vue中的数据响应问题,vue可以检测对象属性的修改,但无法监听数组的所有变动及对象的新增和删除,只能使用数组变异方法及$set方法。
Object.defindProperty虽然能够实现双向绑定了,但是还是有缺点,只能对对象的属性进行数据劫持,所以会深度遍历整个对象,不管层级有多深,只要数组中嵌套有对象,就能监听到对象的数据变化无法监听到数组的变化,Proxy就没有这个问题,可以监听整个对象的数据变化,所以用vue3.0会用Proxy代替definedProperty。
第一步:先获取原生 Array 的原型方法,因为拦截后还是需要原生的方法帮我们实现数组的变化。
第二步:对 Array 的原型方法使用 Object.defineProperty 做一些拦截操作。
第三步:把需要被拦截的 Array 类型的数据原型指向改造后原型。
注:直接修改数组中的元素视图上不会更新,如果要触发修改,可以用splice
替换或者用Vue.set(object,key,value)
set 这个方法只能用于data 里面的子数组对象,而不能直接用于data (这个根数据)或者vue 实例。
除了正常返回push、unshift和splice(插入)函数执行的result结果外,还通知了变化!ob.dep.notify()
所以对新增的数组元素实现了响应式的变化。
16.Proxy
针对上述问题,Vue3中利用Proxy
来代替Object.defineProperty
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。var proxy = new Proxy(target,handler)
如果都是同一类型的组件(即:两节点是同一个组件类的两个不同实例,比如:<div id="before"></div>与<div id="after"></div>),按照原策略继续比较Virtual DOM树即可
如果出现不是同一类型的组件,则将该组件判断为dirty component,从而替换整个组件下的所有子节点。
当节点处于同一层级时,Diff提供三种DOM操作:删除、移动、插入。
首先执行patch函数,patch函数接收两个参数oldVnode和Vnode分别代表新的节点和之前的旧节点,判断两节点是否值得比较,值得比较则执行patchVnode。
如果两个节点都是一样的,那么就深入检查他们的子节点。如果两个节点不一样那就说明Vnode完全被改变了,就可以直接替换oldVnode。
虽然这两个节点不一样但是他们的子节点一样怎么办?别忘了,diff可是逐层比较的,如果第一层不一样那么就不会继续深入比较第二层了。
然后执行patchVnode函数,这个函数做了以下事情:
18.Computed和watch