Vue
MVVM
在MVC的基础上实现了view-model,即视图与数据的双向绑定,视图只是数据的映射,所有逻辑都是对数据的修改,不用直接操作DOM。
SPA单页应用
优点:
- 具有桌面应用的即时反馈,无需刷新页面就可以交互,又有web的跨平台
- 后续操作无需重新从服务器获取静态资源,服务器压力较小
- 路由由前端控制,更好的前后端分离
缺点:
- 首屏加载资源较多,速度较慢(按需加载、懒加载)
- 需要手动实现导航的前进后退
- 不利于SEO(需手动优化)
周期
new Vue() –> init –> $mount –> compiler –> render –> vnode –> patch –> DOM
常用题目
单向数据流
父组件使用用prop和子组件进行通信,父级prop更新传递给子组件进行更新,反之则不行。子组件中不能修改prop,只能通过$emit一个事件通知父组件,由父组件更新prop来修改。
computed和watch的区别
- 计算属性,依赖于参与计算的其他属性值,会对计算结果进行缓存,依赖的值发生变更才会重新计算,主要为了获取到最新的值。
- watch,当某个属性值发生变化时,触发对应的回调。更多的是在数据变化是执行异步操作/复杂操作, 而不是为了获取最新的值。
对象变更检测
Vue是在初始化实例时对data对象上的property执行getter/setter转换实现检测变更的,直接添加根级别的property将无法触发更新。
可以通过以下方式添加:
- Vue.set(vm.someObject, b, 2)/vm.$set(vm.someObject, b, 2)
- this.someObject = Object.assign({}, this.someObject, { b: 2 })
数组变更检测
直接修改数组中一项的值,或者修改数组的length,Vue无法检测到数据的变更。因为Vue是通过数据劫持实现监控数据的,只对数组本身进行了处理,对内容并没有处理。
通过以下方式Vue可以检测到变更:
- 变异方法,Vue对数组的方法进行了处理,调用时即可检测变更,eg:splice、push、shift、pop、slice等
- Vue.set()/vm.$set()
生命周期
- 创建实例
- 初始化事件/生命周期
- 初始化注入/校验,data和methods初始化完毕
- 编译模板,生成模板
- 挂载实例,创建vm.$e并l替换el
- 销毁实例
钩子函数
- beforeCreate,
- created,最早可以操作data和methods的地方
- beforeMount
- mounted,初始化完毕,渲染真是dom
- beforeUpdate,data变成最新值,但是还没有更新到dom
- updated
- beforeDestroy,data、methods、指令、过滤器、计算属性等可用
- destroyed
父组件监听子组件钩子
方法一:手动在子组件钩子中$emit
方法二:父组件使用@hook:mounted就可以实现
keep-alive
抽象组件,不会渲染任何DOM,动态组件<component :is="currentComponet"></component>
切换时每次都会重新渲染组件,无法保存状态,使用keep-alive组件包裹,就可以实现状态的保存。
- 对应activated和deactivated两个钩子函数
- 使用include/exclude属性传入正则/字符串,就可以设置哪些组件缓存/不缓存
为什么组件中data是一个函数返回一个对象,而new Vue()中data是一个对象
因为对象是引用类的数据,组件复用时,如果是data 是对象,修改单个组件时就会影响其他组件的值。
v-model
语法糖,例如input元素使用v-model相当于使用value和input事件修改value
用在组件上,默认使用名为value的prop和input的自定义事件
组件通信
- 父 -> 子,prop/ref/$children
- 子 -> 父,$emit/$parent
- 兄弟,EventBus
- 隔代,$attrs/$listeners,子组件上v-bind=”$attrs”会向下传递props属性中未获取的父组件传下来的props;$listeners包含了作用于当前组件的所有事件
- 隔代,provide/inject,provide传递数据,inject获取数据
- Vuex,状态管理模式,state存储状态,getter计算状态,mutation/action可预测的变更状态,响应式
SSR
服务端渲染,Vue在服务端渲染html页面推送到浏览器进行展示
- 更好的SEO
- 更快的首屏加载
- 只支持beforeCreate和created两个钩子
- 占用更多的服务器资源
Router
- hash模式,修改url的hash值(location.hash)实现跳转,hashchange更改页面内容
- history模式,HTML5 History API,pushState和replaceState修改url不会引起页面刷新,需要配置后台避免手动刷新404
- abstract模式,不依赖于浏览器,通过数组模拟浏览器历史记录和功能
双向绑定实现
- Observer监听器,对数据对象data进行遍历,使用Object.definePropery()添加getter和setter实现数据劫持,对data 的属性进行修改时就会触发setter
- Compiler解析器,解析模板指令,将模板中的变量替换为数据,解析指令给对应节点绑定更新函数,添加数据订阅器
- Watcher订阅者,订阅Observer中的数据变更,找到对应的更新函数并调用
- Dep订阅器,收集订阅者
数组变化检测
通过重写数组的push、pop、shift、unshift、splice、sort、reverse等方法实现数据劫持,不能修改Array.prototype上的方法,通过一个对象使用Object.create()原型继承的方式继承Array.prototype,将变异方法添加到新对象上,然后将data的数组属性的proto设置为新对象即可。
虚拟DOM的优缺点
优点:
- 短时间内多次修改操作可以合并成一次,较少渲染成本
- 框架的虚拟DOM对呀修改DOM进行了性能优化,比手动修改DOM开销更小
- 对比修改前后的虚拟DOM计算差异,避免渲染整个DOM树
- 实现双向数据绑定,修改数据即可自动修改视图,减少开发成本
- 跨平台,纯JS实现,不依赖浏览器,可以实现服务端渲染、weex开发等等
缺点:
- 多了一次运算,增加开销
- 虚拟DOM需要适配上层API,无法做到极致的性能优化
虚拟DOM实现原理
- 解析html,用js对象模拟DOM树,对真是DOM进行抽象
- dff算法,比较修改前后DOM树的差异
- patch算法,将差异部分应用到真正的DOM树
Key的作用
vnode的唯一标记,可以更准确、更快的diff操作
- 解决不需要就地复用的场景
- 直接通过key取节点比遍历更快
优化
- v-if和v-show
- v-for和v-if混用
- computed和watch
- 长列表优化,无限滚动/可见区域渲染
- 销毁事件
- 懒加载,路由、图片、组件等
- 三方插件按需引入
- CDN
- 压缩,webpack、nginx
- 组件化
- sourceMap优化
- 浏览器缓存机制优化
使用过程中遇到的最大的问题
- 数组变更检测,变异方法解决
- 异步回调中this指向问题,箭头函数/变量获取this
- setInterval销毁
3.0
proxy
创建一个代理替代一个对象,对目标对象的所有操作都可以在代理中进行拦截,对数组同样有效。
- 可以直接检测对象,而不是对象的属性,可以检测到对象的添加和删除
- 检测数组的索引和长度的变更
- 支持Set、Map、WeakMap和WeakSet