深度监听对象
有如下数据,实现对obj的深度监听
data() {
return {
obj: {
name: '张三',
age: 21,
}
}
}
结合computed
将要监听的属性使用computed计算出来,然后监听这个计算属性,如下
computed: {
oName() {
return this.obj.name
}
},
watch: {
oName(newValue) {
console.log('name值变为'+newValue)
}
}
深度监听
利用Vue自身的深度监听,设置深度监听为true,如下
watch: {
obj: {
deep: true,
handler: (newValue) => {
console.log('name值变为'+newValue)
}
}
}
什么是MVVM
传统的MVC(Model-View-Controller)中,当数据Model发生变化时由控制器Controller控制视图View的更新。
随着前端页面越来越复杂以及单页应用的出现,MVC模型已经不再适应前端的开发,MVVM(Model-View-ViewModel)应运而生 ,MVVM中Model和View没有直接联系,通过ViewModel进行交互,而且是双向的,这样开发时就不再需要关注View,只需要对数据进行处理就可以了
响应式数据的原理
Vue在初始化时,会给data中属性通过Object.defineProperty()重新定义所有属性,当页面取到对应的属性是会进行依赖收集,如果属性发生变化会通知相关依赖进行更新
Vue如何检测数组变化
- 使用函数劫持的方法,重写数组方法
- Vue将data中的数组进行了原型链重写,指向了自己顶一个数组原型链方法,在调用数组API时,可以通知依赖更新,如果数组中存在引用类型,,会对引用类型再次进行监控
为什么Vue采用异步渲染
如果不采用异步更新,那么每次数据变化都会引起组件的重新渲染,为了性能考虑,Vue会在本轮数据更新后再去异步渲染
nextTick原理
nextTick 方法主要是使用了宏任务和微任务,定义了一个异步方法.多次调用 nextTick 会将方法存入 队列中,通过这个异步方法清空当前队列。 所以这个 nextTick 方法就是异步方法
Computed和Watch的区别
Computed和Watch都是watcher,区别在于Computed具有缓存功能
Watch中的deep: true怎么实现的
当用户指定了 watch 中的deep属性为 true 时,如果当前监控的值是数组类型。会对对象中的每 一项进行求值,此时会将当前 watcher 存入到对应属性的依赖中,这样数组中对象发生变化时也 会通知数据更新
生命周期
ajax请求放在哪个生命周期中
在created的时候,视图中的 dom 并没有渲染出来,所以此时如果直接去操 dom 节点,无法找到相 关的元素
在mounted中,由于此时 dom 已经渲染出来了,所以可以直接操作 dom 节点 ;一般情况下都放到 mounted 中,保证逻辑的统一性,因为生命周期是同步执行的, ajax 是异步执行的
服务端渲染不支持mounted方法,所以在服务端渲染的情况下统一放到created中
何时需要使用beforeDestroy
- 可能在当前页面中使用了 $on 方法,那需要在组件销毁前解绑。
- 清除自己定义的定时器
- 解除事件的绑定 scroll mousemove ….
Vue中模板编译原理
- 第一步是将
模板字符串
转换成element ASTs
(解析器) - 第二步是对
AST
进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器) - 第三步是 使用
element ASTs
生成render
函数代码字符串(代码生成器)
Vue中v-if和v-show的区别
v-if 如果条件不成立不会渲染当前指令所在节点的 dom 元素
v-show 只是切换当前 dom 的显示或者隐藏(display: none)
为什么V-for和v-if不能连用
v-for 会比 v-if 的优先级高一些,如果连用的话会把 v-if 给每个元素都添加一下,会造成性能问题
如果需要连用,可以使用计算属性,先处理要遍历的数据,筛选之后再遍历
<template>
<ul>
<li v-for="computeData"></li>
</ul>
</template>
<script>
data() {
return {
initData: [
{flag: true, name: 'aaa'},
{flag: false, name: 'bbb'},
]
}
},
computed: {
computeData() {
this.initData.map((item) => {
return item.flag
})
}
}
</script>
diff算法的时间复杂度
两个树的完全的 diff 算法是一个时间复杂度为 O(n³) , Vue 进行了优化O(n³) 复杂度的问题转换成 O(n) 复杂度的问题(只比较同级不考虑跨级问题) 在前端当中, 你很少会跨越层级地移动Dom元素。 所 以 Virtual Dom只会对同一个层级的元素进行对比
diff原理
- 先同级比较,在比较子节点
- 先判断一方有儿子一方没儿子的情况
- 比较都有儿子的情况
- 递归比较子节点
v-for中为什么要有key
组件中的 data为什么是一个函数
同一个组件被复用多次,会创建多个实例。这些实例用的是同一个构造函数,如果 data 是一个对象的 话。那么所有组件都共享了同一个对象。为了保证组件的数据独立性要求每个组件必须通过 data 函数 返回一个对象作为组件的状态
一个组件被使用多次,用的都是同一个构造函数。为了保证组件的不同的实例data不冲突,要求 data必须是一个函数,这样组件间不会相互影响
Vue中事件绑定的原理
Vue 的事件绑定分为两种一种是原生的事件绑定,还有一种是组件的事件绑定
- 原生 dom 事件的绑定,采用的是 addEventListener 实现
- 组件绑定事件采用的是 $on 方法 原理
Vue中常见性能优化
1.编码优化:
不要将所有的数据都放在data中,data中的数据都会增加getter和setter,会收集对应的 watcher
vue 在 v-for 时给每项元素绑定事件需要用事件代理
SPA 页面采用keep-alive缓存组件
拆分组件( 提高复用性、增加代码的可维护性,减少不必要的渲染 )
v-if 当值为false时内部指令不会执行,具有阻断功能,很多情况下使用v-if替代v-show
key 保证唯一性 ( 默认 vue 会采用就地复用策略 )
Object.freeze 冻结数据
合理使用路由懒加载、异步组件
尽量采用runtime运行时版本
数据持久化的问题 (防抖、节流)
2.Vue加载性能优化:
第三方模块按需导入 ( babel-plugin-component )
3.用户体验:
app-skeleton 骨架屏
app-shell app壳
pwa serviceworker
4.SEO优化:
预渲染插件 prerender-spa-plugin
服务端渲染 ssr
5.打包优化:
使用 cdn 的方式加载第三方模块 多线程打包 happypack splitChunks 抽离公共文件 sourceMap 生成
6.缓存,压缩
客户端缓存、服务端缓存 服务端 gzip 压缩