谈一谈 nextTick 的原理
在下次 DOM 更新循环结束之后执行延迟回调。nextTick主要使用了宏任务和微任务。根据执行环境分别尝试采用
- Promise
- MutationObserver
- setImmediate
- 如果以上都不行则采用setTimeout
定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列
Vue 组件 data 为什么必须是函数 ?
new Vue()实例中,data 可以直接是一个对象,为什么在 vue 组件中,data 必须是一个函数呢?
因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染,产生副作用。
所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。new Vue 的实例是不会被复用的,因此不存在以上问题。
简版:组件是复用的,所以需要保证每个组件都单独的维护一份状态,所以需要写成函数返回一个对象。
vm.$set()实现原理是什么?
受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 无法检测到对象属性的添加或删除。
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。
对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性。
简版:通过$set可以对指定的属性 通过 Object.defineProperty 增加get 和set 从而让其具备响应式。
什么是MVVM框架
MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。
简版:我的理解是数据驱动视图,通过状态的修改MVVM的框架就会去主动的更新视图。
响应式数据原理(Vue2.x & Vue3.0)
Vue2.x在初始化数据时,会使用Object.defineProperty重新定义data中的所有属性,当页面使用对应属性时,首先会进行依赖收集(收集当前组件的watcher),如果属性发生变化会通知相关依赖进行派发更新(发布订阅模式)。
vue3.0采用es6中的proxy代替Object.defineProperty做数据监听。
Proxy与Object.defineProperty的优劣对比?
Proxy的优势如下:
- Proxy可以直接监听对象而非属性
- Proxy可以直接监听数组的变化
- Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的
- Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
- Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利
Object.defineProperty的优势如下:
- 兼容性好,支持IE9
vue中组件通信的方式
- 父传子:props
- 子传父:$emit、ref $parent
- 兄弟:EventBus
- vuex
- 跨组件: provide inject
另外一个版本
- props
- $on$emit
- $parent、$children、$refs
- bus
- vuex
- provide、inject
- $attrs、$listeners
虚拟dom
- 由于dom操作耗时十分长,且dom对象的体积很大,单个div的dom属性就有294个之多;
- Virtual DOM 就是用一个原生的 JS 对象去描述一个 DOM 节点,所以它比创建一个 DOM 的代价要小很多。
- VNode 是对真实 DOM 的一种抽象描述,它的核心定义无非就几个关键属性,标签名、数据、子节点、键值等,其它属性都是用来扩展 VNode 的灵活性以及实现一些特殊 feature 的。由于 VNode 只是用来映射到真实 DOM 的渲染,不需要包含操作 DOM 的方法,因此它是非常轻量和简单的。
- Virtual DOM到真实的dom需要经过以下过程:VNode 的 create、diff、patch
简版:我的理解就是一个js的对象,这个对象可以映射出真实的dom的结构。 通过虚拟dom可以加快状态变化前后的dom的区别,加快视图更新的效率。
v-model双向数据绑定原理
简版:v-model本质上是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件
- text 和 textarea 元素使用 value 属性和 input 事件
- checkbox 和 radio 使用 checked 属性和 change 事件
- select 字段将 value 作为 prop 并将 change 作为事件
为什么v-for的key尽量不要使用index
当数据进行更改的时候,会通过key来判断虚拟dom树是否进行了更改。如果发现了相同的dom-key就可以直接复用。减少了渲染的性能损耗。数据只做展示,用index是没问题的。如果涉及到删除,添加,就不行了,因为index不再唯一了。
vue能监听到数组变化的方法有哪些?为什么这些方法能监听到呢?
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
这些方法,都是在框架内重写过的,并不是原生的方法了,新的方法 里面增加了监听。
v-if和v-for嵌套使用的问题
v-if和v-for的优先级:
在vue2中v-for优先级高
在vue3中v-if优先级高
但是无论如何两个组合在一起使用官方都不推荐
因此同时出现,会导致先for循环子元素,在判断每个子元素的if情况。
想要先执行if,在满足的条件下再循环子元素,可以在v-for的元素外层加一个有if指令的template标签
Vue 的⽗组件和⼦组件⽣命周期钩⼦执⾏顺序是什么?
渲染过程: ⽗组件挂载完成⼀定是等⼦组件都挂载完成后,才算是⽗组件挂载完,所以⽗组件的mounted在⼦组件mouted之后
⽗beforeCreate -> ⽗created -> ⽗beforeMount -> ⼦beforeCreate -> ⼦created -> ⼦beforeMount -> ⼦mounted -> ⽗mounted
⼦组件更新过程:
- 影响到⽗组件: ⽗beforeUpdate -> ⼦beforeUpdate->⼦updated -> ⽗updted
- 不影响⽗组件: ⼦beforeUpdate -> ⼦updated
⽗组件更新过程:
- 影响到⼦组件: ⽗beforeUpdate -> ⼦beforeUpdate->⼦updated -> ⽗updted
- 不影响⼦组件: ⽗beforeUpdate -> ⽗updated
销毁过程: ⽗beforeDestroy -> ⼦beforeDestroy -> ⼦destroyed -> ⽗destroyed
看起来很多好像很难记忆,其实只要理解了,不管是哪种情况,都⼀定是⽗组件等待⼦组件完成后,才会执⾏⾃⼰对应完成的钩⼦,就可以很容易记住
v-show 和 v-if 有哪些区别?
- v-if 会在切换过程中对条件块的事件监听器和⼦组件进⾏销毁和重建,如果初始条件是false,则什么都不做,直到条件第⼀次为true时才开始渲染模块。
- v-show 只是基于css进⾏切换,不管初始条件是什么,都会渲染。