data 为什么必须是函数?
new Vue()实例中,data 可以直接是一个对象,为什么在 vue 组件中,data 必须是一个函数呢?
因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染,产生副作用。
所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
Vue 如何实现组件间通信?
Vue.use() 原理及使用
如何开发vue插件
自定义指令
分享8个非常实用的Vue自定义指令
watch 和 computed 和 methods 区别是什么?
Vue.set 是做什么用的?
虚拟dom
vue中 key 值的作用?
key值:用于管理可复用的元素。 因为Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。 这么做使Vue变得非常快,但是这样也不总是符合实际需求。
vue和react都是采用diff算法来对比新旧虚拟节点,从而更新节点。在vue的diff函数交叉对比中,当新节点跟旧节点头尾交叉对比没有结果时,会根据新节点的key去对比旧节点数组中的key,从而找到相应的旧节点(这里对应的是key=>index的map映射)。如果没有找到就认为是一个新增的节点。而如果没有key,那么就会采用遍历查找的方式去找到对应的旧节点。一种是map映射,另一种是遍历查找。相比而言,map映射的速度更快
keep-alive
它是一个动态组件,同时也是vue的内置组件,当组件在切换的过程中,keep-alive可以将状态保存在内存中,防止重复渲染dom。
会增加两个生命周期:
组件激活时:actived() 该钩子在服务器渲染期间不能被调用
组件停用时:deactivated() 该钩子在服务器渲染期间不能被调用
mixin的实现(手写vue的mixin方法)
mixin和页面执行顺序问题
vue常用的修饰符
v-on 指令常用修饰符:
-
.stop - 调用 event.stopPropagation(),禁止事件冒泡
-
.prevent - 调用 event.preventDefault(),阻止事件默认行为
-
.native - 监听组件根元素的原生事件
-
.once - 只触发一次回调
native 修饰符的使用:
MVVM observe compile watch
响应式原理 依赖收集 监听数组
双向数据绑定原理
Vue是如何设计响应式系统的?(依赖收集)
核心实现类:
Observer : 它的作用是给对象的属性添加 getter 和 setter,用于依赖收集和派发更新
Dep : 用于收集当前响应式对象的依赖关系,每个响应式对象包括子对象都拥有一个 Dep 实例(里面 subs 是 Watcher 实例数组),当数据有变更时,会通过 dep.notify()通知各个 watcher。
Watcher : 观察者对象 , 实例分为渲染 watcher (render watcher),计算属性 watcher (computed watcher),侦听器 watcher(user watcher)三种
Watcher 和 Dep 的关系:
watcher 中实例化了 dep 并向 dep.subs 中添加了订阅者,dep 通过 notify 遍历了 dep.subs 通知每个 watcher 更新。
依赖收集:
-
initState 时,对 computed 属性初始化时,触发 computed watcher 依赖收集
-
initState 时,对侦听属性初始化时,触发 user watcher 依赖收集
-
render()的过程,触发 render watcher 依赖收集
-
re-render 时,vm.render()再次执行,会移除所有 subs 中的 watcer 的订阅,重新赋值。
派发更新:
-
组件中对响应的数据进行了修改,触发 setter 的逻辑
-
调用 dep.notify()
-
遍历所有的 subs(Watcher 实例),调用每一个 watcher 的 update 方法。
原理:
当创建 Vue 实例时,vue 会遍历 data 选项的属性,利用 Object.defineProperty 为属性添加 getter 和 setter 对数据的读取进行劫持(getter 用来依赖收集,setter 用来派发更新),并且在内部追踪依赖,在属性被访问和修改时通知变化。
每个组件实例会有相应的 watcher 实例,会在组件渲染的过程中记录依赖的所有数据属性(进行依赖收集,还有 computed watcher,user watcher 实例),之后依赖项被改动时,setter 方法会通知依赖与此 data 的 watcher 实例重新计算(派发更新),从而使它关联的组件重新渲染。
一句话总结:
vue.js 采用数据劫持结合发布-订阅模式,通过 Object.defineproperty 来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发响应的监听回调
template 和 render(jsx) 有什么联系?
什么是 nextTick ? $nextTick是如何设计的?
vue是数据驱动DOM,只要监听到数据变化,Vue将开启一个队列,
并缓存在同一事件循环中发生的所有数据变更,
如果同一个Watcher被多次触发,只会被推入到队列中一次,
避免了不必要的重复计算和频繁的DOM操作,
然后在下一个事件循环"tick"中(注意下一个tick可能是当前的tick微任务执行阶段执行,也可能在下一个tick执行,主要取决于nextTick函数使用的是Promise/MutationObserver还是setTimeout),
Vue刷新队列并执行更新视图等操作,所以DOM更新是异步执行的.
对vue生命周期的理解
vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁,这就是一个组件所谓的生命周期。
生命周期共分为8个阶段 创建前/后,载入前/后,更新前/后,销毁前/后
创建前/后:在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。created阶段,vue实例的数据对象data有了,el还没有。
载入前后:在beforeMount阶段,vue实例的el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染
更新前/后:当data变化时,会触发beforeUpdate和updated方法
销毁前/后:beforeDestroy在实例销毁前调用,实例仍然完全可用。destroyed在实例销毁之后调用,调用后所有事件监听器会被移除,所有子实例也会被销毁。
<keep-alive> 包裹动态组件时 , 会有activated 和 deactivate 生命周期钩子:
activated deactivated 只要页面切换加载组件就会执行一次
第一次进入:beforeRouterEnter -> created -> … ->activated-> … ->deactivated
后续进入时:beforeRouterEnter -> activated -> deactivated
如果每次进入组件,需要更新某些数据,此时需要把这些方法写在 actived 中
当离开组件时,需要终止某些方法,需要在 deactivated 操作,比如:进入页面发起ajax,在ajax的加载没有完成时退出该页面,此时就需要将 loading(我的ajax 和 loading 是分别控制的) 置为 false
data () {
return {
rendered: false,
}
}
1.beforeCeate(){
console.log(this.$el); // undefined
console.log(this.rendered); // undefined
}
2.created() {
console.log(this.$el); //undefined
console.log(this.rendered); // false
}
3.beforeMount() {
console.log(this.$el);//undefined
}
4.mounted() {
console.log(this.$el);
}
vue-cli如何进行工程升级??
前言:此命令谨慎使用,实际开发中如需升级建议直接使用 vue-cli 脚手架搭建,只需要了解即可!
推荐使用:
//升级插件
npm-check-updates
首先安装插件,建议用 npm 源安装,测试时用 cnpm 安装未下载成功:(全局安装才有效,亲试)
npm install npm-check-updates -g
然后在待升级工程的目录结构下,命令行输入:
ncu
执行效果图:
然后升级所有版本,命令行输入:
ncu -a
再输入:
npm install
参考文章如下:
juejin.im/post/684490…