mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,经过 Object.defineProperty()
来劫持各个属性的 setter、getter,在数据变更时发布消息给订阅者,触发相应的监听回调。
css
几个要点:
一、实现一个数据监听器 Observer,可以对数据对象的全部属性进行监听,若有变更可拿到最新值并通知订阅者
二、实现一个指令解析器 Compile,对每一个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
三、实现一个 Watcher,做为链接 Observer 和 Compile 的桥梁,可以订阅并收到每一个属性变更的通知,执行指令绑定的相应回调函数,从而更新视图
四、mvvm 入口函数,整合以上三者html
具体步骤:前端
当 Vue 进入初始化阶段时,一方面 Vue 会遍历 data 中的属性,并用 Object.defineProperty 将它转化成 getter/setter 的形式,实现数据劫持(暂不谈 Vue3.0 的 Proxy);另外一方面,Vue 的指令编译器 Compiler 对元素节点的各个指令进行解析,初始化视图,并订阅 Watcher 来更新试图,此时 Watcher 会将本身添加到消息订阅器 Dep 中,此时初始化完毕。
当数据发生变化时,触发 Observer 中 setter 方法,当即调用 Dep.notify(),Dep 这个数组开始遍历全部的订阅者,并调用其 update 方法,Vue 内部再经过 diff 算法,patch 相应的更新完成对订阅者视图的改变。vue
响应式系统简述:node
详细实现见 面试官: 你对虚拟DOM原理的理解?react
考点: Vue 的变化侦测原理
前置知识: 依赖收集、虚拟 DOM、响应式系统
现代前端框架有两种方式侦测变化,一种是pull,一种是pushwebpack
pull: 其表明为React,咱们能够回忆一下React是如何侦测到变化的,咱们一般会用setStateAPI显式更新,而后React会进行一层层的Virtual Dom Diff操做找出差别,而后Patch到DOM上,React从一开始就不知道究竟是哪发生了变化,只是知道「有变化了」,而后再进行比较暴力的Diff操做查找「哪发生变化了」,另一个表明就是Angular的脏检查操做。nginx
push: Vue的响应式系统则是push的表明,当Vue程序初始化的时候就会对数据data进行依赖的收集,一但数据发生变化,响应式系统就会马上得知。所以Vue是一开始就知道是「在哪发生变化了」,可是这又会产生一个问题,若是你熟悉Vue的响应式系统就知道,一般一个绑定一个数据就须要一个Watcher,一但咱们的绑定细粒度太高就会产生大量的Watcher,这会带来内存以及依赖追踪的开销,而细粒度太低会没法精准侦测变化,所以Vue的设计是选择中等细粒度的方案,在组件级别进行push侦测的方式,也就是那套响应式系统,一般咱们会第一时间侦测到发生变化的组件,而后在组件内部进行Virtual Dom Diff获取更加具体的差别,而Virtual Dom Diff则是pull操做,Vue是push+pull结合的方式进行变化侦测的。web
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。若是数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每一个元素,而且确保它在特定索引下显示已被渲染过的每一个元素。key 的做用主要是为了高效的更新虚拟DOM。
beforeCreate
和created
beforeMount
和mounted
beforeUpdate
和updated
beforeDestory
和destoryed
activated
和deactivated
使用Object.assign(),vm.$data能够获取当前状态下的data,vm.$options.data能够获取到组件初始化状态下的data。
Object.assign(this.$data, this.$options.data())
官方文档:vue-router钩子函数
router.beforeEach
router.beforeResolve
router.afterEach
beforeEnter
beforeRouteEnter
、beforeRouteUpdate
、beforeRouteLeave
route
和 router
的区别是什么?route
是“路由信息对象”,包括path
,params
,hash
,query
,fullPath
,matched
,name
等路由信息参数。
router
是“路由实例对象”,包括了路由的跳转方法(push
、replace
),钩子函数等。
1.监听数据变化的实现原理不一样
Vue 不须要特别的优化就能达到很好的性能,而对于 React 而言,须要经过 PureComponent/shouldComponentUpdate 这个生命周期方法来进行控制。若是你的应用中,交互复杂,须要处理大量的 UI 变化,那么使用 Virtual DOM 是一个好主意。若是你更新元素并不频繁,那么 Virtual DOM 并不必定适用,性能极可能还不如直接操控 DOM。
为何 React 不精确监听数据变化呢?这是由于 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而 React 更强调数据的不可变。
2.数据流的不一样
不过因为咱们通常都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,所以不少时候咱们感觉不到这一点的区别了。
3.模板渲染方式的不一样
在表层上,模板的语法不一样
在深层上,模板的原理不一样,这才是他们的本质区别:
对这一点,我我的比较喜欢 React 的作法,由于他更加纯粹更加原生,而 Vue 的作法显得有些独特,会把 HTML 弄得很乱。举个例子,说明 React 的好处:react 中 render 函数是支持闭包特性的,因此咱们 import 的组件在 render 中能够直接调用。可是在 Vue 中,因为模板中使用的数据都必须挂在 this 上进行一次中转,因此咱们 import 一个组件完了以后,还须要在 components 中再声明下,这样显然是很奇怪但又不得不这样的作法。
1. 为何须要 nextTick
Vue 是异步修改 DOM 的而且不鼓励开发者直接接触 DOM,但有时候业务须要必须对数据更改--刷新后的 DOM 作相应的处理,这时候就可使用 Vue.nextTick(callback)这个 api 了。
2. 理解原理前的准备
首先须要知道事件循环中宏任务和微任务这两个概念(这其实也是面试常考点)。请阅大佬文章--完全搞懂浏览器 Event-loop
常见的宏任务有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering
常见的微任务有 process.nextTick(Nodejs),Promise.then(), MutationObserver;
3. 理解 nextTick
而 nextTick 的原理正是 vue 经过异步队列控制 DOM 更新和 nextTick 回调函数前后执行的方式。若是你们看过这部分的源码,会发现其中作了不少 isNative()的判断,由于这里还存在兼容性优雅降级的问题。可见 Vue 开发团队的深思熟虑,对性能的良苦用心。
若是你比较了解了前面的事件循环原理,推荐你看看这篇文章 请阅大佬文章--全面解析 Vue.nextTick 实现原理
有五种,分别是 State
、Getter
、Mutation
、Action
、Module
而后找到 build/webpack.base.conf.js 文件,在 module.exports = { } 中添加如下代码
externals: { 'vue': 'Vue', 'vue-router': 'VueRouter', 'element-ui': 'ELEMENT', },
这样 webpack 就不会把 vue.js, vue-router, element-ui 库打包了。声明一下,我把 main.js 中对 element 的引入删掉了,否则我发现打包后的 app.css 仍是会把 element 的 css 打包进去,删掉后就没了。
而后你打包就会发现 vendor 文件小了不少~
import
或者require
懒加载。你打包就会发现,多了不少 1.xxxxx.js;2.xxxxx.js 等等,而 vendor.xxx.js 没了,剩下 app.js 和 manifest.js,并且 app.js 还很小,我这里是 100k 多一点。
找到 config/index.js,修改成 productionSourceMap: false
这个优化是两方面的,前端将文件打包成.gz文件,而后经过nginx的配置,让浏览器直接解析.gz文件。
若是首页真的有瓶颈,能够考虑用 node 单独作服务端渲染,而下面的子页面仍用 spa 单页的方式交互。
这里不推荐直接用 nuxt.js 服务端渲染方案,由于这样一来增长了学习成本,二来服务端的维护成本也会上升,有时在本机测试没问题,在服务端跑就有问题,为了省心,仍是最大限度的使用静态页面较好。
参考连接:
vue首屏加载优化
vue项目首屏加载优化实战
关于Vue 3.0有幸看过尤大的关于3.0版本的RFC Vue Function-based API RFC。大体说了三个点,第一个是关于提出的新API setup()
函数,第二个说了对于Typescript的支持,最后说了关于替换Object.defineProperty
为 Proxy 的支持。
详细说了下关于Proxy代替带来的性能上的提高,由于传统的原型链拦截的方法,没法检测对象及数组的一些更新操做,但使用Proxy又带来了浏览器兼容问题。
首先须要知道 vue-cli 是什么?它是基于 Vue.js 进行快速开发的完整系统,也能够理解成是不少 npm 包的集合。其次,vue-cli 完成的功能有哪些?
.vue 文件 --> .js 文件
ES6 语法 --> ES5 语法
Sass,Less,Stylus --> CSS
对 jpg,png,font 等静态资源的处理
热更新
定义环境变量,区分 dev 和 production 模式
...
若是开发者须要补充或修改默认设置,须要在 package.json 同级下新建一个 vue.config.js 文件
更多vue面试题:
面试必备的13道能够触类旁通的Vue面试题
vue 248个知识点(面试题)为你保驾护航
2019前端面试系列——CSS面试题
2019前端面试系列——JS面试题
2019前端面试系列——JS高频手写代码题
2019前端面试系列——Vue面试题
2019前端面试系列——HTTP、浏览器面试题