1. 单页面应用与多页面应用对比
| 单页面应用(SinglePage Web Application,SPA) | 多页面应用(MultiPage Application,MPA) |
组成 | 一个外壳页面和多个页面片段组成 | 多个完整页面构成 |
资源共用(css,js) | 共用,只需在外壳部分加载 | 不共用,每个页面都需要加载 |
刷新方式 | 页面局部刷新或更改 | 整页刷新 |
url 模式 | a.com/#/pageone | a.com/pageone.html |
用户体验 | 页面片段间的切换快,用户体验良好 | 页面切换加载缓慢,流畅度不够,用户体验比较差 |
转场动画 | 容易实现 | 无法实现 |
数据传递 | 容易 | 依赖 url传参、或者cookie 、localStorage等 |
搜索引擎优化(SEO) | 需要单独方案、实现较为困难、不利于SEO检索 可利用服务器端渲染(SSR)优化 | 实现方法简易 |
试用范围 | 高要求的体验度、追求界面流畅的应用 | 适用于追求高度支持搜索引擎的应用 |
开发成本 | 较高,常需借助专业的框架 | 较低 ,但页面重复代码多 |
维护成本 | 相对容易 | 相对复杂 |
From: https://juejin.im/post/5a0ea4ec6fb9a0450407725c
2. Virtual DOM
用JS表示DOM结构,比较两棵虚拟DOM树的差异:在用JS对象表示DOM结构后,当页面状态发生变化而需要操作DOM时,我们可以先通过虚拟DOM计算出对真实DOM的最小修改量,然后再修改真实DOM结构。
2.1 如何比较差异?
对同级别节点进行比较,比较的常用方法是深度优先遍历。将节点之间的差异分类。在深度优先遍历的过程中,每个节点都有一个编号,如果对应的节点有变化,只需要把相应变化的类别记录下来,生成数据结构patches,使用patches对真实DOM做最小化的修改。
From: https://foio.github.io/virtual-dom/
3. Vue中 key 值的作用?
key的作用主要是为了高效的更新虚拟DOM。
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
From: https://www.zhihu.com/question/61064119
4. Vue的data为什么是函数?
每一个vue组件都是一个vue实例,通过new Vue()实例化,引用同一个对象,如果data直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变。而data是函数的话,每个vue组件的data都因为函数有了自己的作用域,互不干扰。
From: https://www.jianshu.com/p/b821d3401314
5. 模板中的组件名大小写规范?
From: https://cn.vuejs.org/v2/style-guide/index.html#模板中的组件名大小写-强烈推荐
6. scoped 的原理?
<style scoped>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
编译后结果:
<style>
.example[data-v-5558831a] {
color: red;
}
</style>
<template>
<div class="example" data-v-5558831a>hi</div>
</template>
PostCSS给一个组件中的所有DOM添加了一个独一无二的动态属性,然后,给CSS选择器额外添加一个对应的属性选择器来选择该组件中dom,这种做法使得样式只作用于含有该属性的DOM——组件内部DOM
From: https://segmentfault.com/a/1190000017508285
7. $route和$router的区别
$router为VueRouter实例,主要是实现路由跳转使用。想要导航到不同URL,则使用$router.push方法
From: https://www.jianshu.com/p/55d41142a147
8. 为什么vuex中使用要使用mutation来修改state,而不是直接修改?
因为state是实时更新的,mutations无法进行异步操作,而如果直接修改state的话是能够异步操作的,当你异步对state进行操作时,还没执行完,这时候如果state已经在其他地方被修改了,这样就会导致程序存在问题了。所以state要同步操作,通过mutations的方式限制了不允许异步。
From: https://segmentfault.com/q/1010000008640206/a-1020000008640969
9. vuex中使用commit提交mutation来修改state的原因解析:
在vuex中,最好设置成严格模式,并且按照文档的要求,通过commit提交mutation的方式来修改state,而不要直接修改state。不然,控制台会报错,并且vue调试工具不会记录state的变化,无法调试。
From: https://blog.csdn.net/zhq2005095/article/details/78359883
10. Vue实现原理?
采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
- 利用Proxy或Object.defineProperty生成的Observer针对对象/对象的属性进行"劫持",在属性发生变化后通知订阅者
- 解析器Compile解析模板中的Directive(指令),收集指令所依赖的方法和数据,等待数据变化然后进行渲染
- Watcher属于Observer和Compile桥梁,它将接收到的Observer产生的数据变化,并根据Compile提供的指令进行视图渲染,使得数据变化促使视图变化
From: https://juejin.im/post/5acd0c8a6fb9a028da7cdfaf
11. 实现双向绑定Proxy比defineproperty优劣如何?
- Object.defineProperty的第一个缺陷,无法监听数组变化。
- Object.defineProperty的第二个缺陷,只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,如果属性值也是对象那么需要深度遍历。
- Proxy可以直接监听对象而非属性。Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改。
- Proxy可以直接监听数组的变化。
From: https://juejin.im/post/5acd0c8a6fb9a028da7cdfaf
12. 为什么defineProperty不能检测到数组长度的“变化”?
对于defineProperty来说,处理数组与对象是一视同仁的,只是在初始化时去改写get和set达到监测数组或对象的变化,对于新增的属性,需要手动再初始化。对于数组来说,只不过特别了点,push、unshift值也会新增索引,对于新增的索引也是可以添加observe从而达到监听的效果;pop、shift值会删除更新索引,也会触发defineProperty的get和set。对于重新赋值length的数组,不会新增索引,因为不清楚新增的索引有多少,根据ecma规范定义,索引的最大值为2^32 - 1,不可能循环去赋值索引的。
From: https://juejin.im/post/5b0d0212f265da08da29e50f
13. 如何解决Vue首屏加载慢的问题?
- 使用CDN资源,减小服务器带宽压力
- 路由懒加载
- 将一些静态js css放到其他地方(如OSS),减小服务器压力
- 按需加载三方资源,如iview,建议按需引入iview中的组件
- 使用nginx开启gzip减小网络传输的流量大小
- 若首屏为登录页,可以做成多入口,登录页单独分离为一个入口
- 使用uglifyjs-webpack-plugin插件代替webpack自带UglifyJsPlugin插件
From: https://segmentfault.com/a/1190000016155447
14. vue-cli 3.0 如何使用CDN区分开发、生产、预发布环境?
From: https://www.jianshu.com/p/9d6c1efebcd9