vue-interview(7/8/9)
7. 谈谈你对MVC、MVP和MVVM的理解?
答题思路:此题涉及知识点很多,很难说清、说透,因为mvc、mvp这些我们前端程序员自己甚至都没
用过。但是恰恰反映了前端这些年从无到有,从有到优的变迁过程,因此沿此思路回答将十分清楚。
Web1.0****时代
在web1.0时代,并没有前端的概念。开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常由
多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、C#/Java/PHP代码,系
统整体架构可能是这样子的:
picture
这种架构的好处是简单快捷,但是,缺点也非常明显:JSP代码难以维护
为了让开发更加便捷,代码更易维护,前后端职责更清晰。便衍生出MVC开发模式和框架,前端展示以
模板的形式出现。典型的框架就是Spring、Structs、Hibernate。整体框架如图所示:
picture
使用这种分层架构,职责清晰,代码易维护。但这里的MVC仅限于后端,前后端形成了一定的分离,前
端只完成了后端开发中的view层。
但是,同样的这种模式存在着一些:
\1. 前端页面开发效率不高
\2. 前后端职责不清
web 2.0****时代
自从Gmail的出现,ajax技术开始风靡全球。有了ajax之后,前后端的职责就更加清晰了。因为前端可
以通过Ajax与后端进行数据交互,因此,整体的架构图也变化成了下面这幅图:
picture
通过ajax与后台服务器进行数据交换,前端开发人员,只需要开发页面这部分内容,数据可由后台进行
提供。而且ajax可以使得页面实现部分刷新,减少了服务端负载和流量消耗,用户体验也更佳。这时,
才开始有专职的前端工程师。同时前端的类库也慢慢的开始发展,最著名的就是jQuery了。
当然,此架构也存在问题:缺乏可行的开发模式承载更复杂的业务需求,页面内容都杂糅在一起,一旦
应用规模增大,就会导致难以维护了。因此,前端的MVC也随之而来。
前后端分离后的架构演变——MVC、MVP和****MVVM
MVC
前端的MVC与后端类似,具备着View、Controller和Model。
Model:负责保存应用数据,与后端数据进行同步
Controller:负责业务逻辑,根据用户行为对Model数据进行修改
View:负责视图展示,将model中的数据可视化出来。
三者形成了一个如图所示的模型:
picture
这样的模型,在理论上是可行的。但往往在实际开发中,并不会这样操作。因为开发过程并不灵活。例
如,一个小小的事件操作,都必须经过这样的一个流程,那么开发就不再便捷了。
在实际场景中,我们往往会看到另一种模式,如图:
picture
这种模式在开发中更加的灵活,backbone.js框架就是这种的模式。但是,这种灵活可能导致严重的问题:
\1. 数据流混乱。如下图:
picture
\2. View比较庞大,而Controller比较单薄:由于很多的开发者都会在view中写一些逻辑代码,逐渐的
就导致view中的内容越来越庞大,而controller变得越来越单薄。
既然有缺陷,就会有变革。前端的变化中,似乎少了MVP的这种模式,是因为AngularJS早早地将
MVVM框架模式带入了前端。MVP模式虽然前端开发并不常见,但是在安卓等原生开发中,开发者还是
会考虑到它。
MVP
MVP与MVC很接近,P指的是Presenter,presenter可以理解为一个中间人,它负责着View和Model之
间的数据流动,防止View和Model之间直接交流。我们可以看一下图示:
picture
我们可以通过看到,presenter负责和Model进行双向交互,还和View进行双向交互。这种交互方式,
相对于MVC来说少了一些灵活,VIew变成了被动视图,并且本身变得很小。虽然它分离了View和
Model。但是应用逐渐变大之后,导致presenter的体积增大,难以维护。要解决这个问题,或许可以
从MVVM的思想中找到答案。
MVVM
首先,何为MVVM呢?MVVM可以分解成(Model-View-VIewModel)。ViewModel可以理解为在
presenter基础上的进阶版。如图所示:
picture
ViewModel通过实现一套数据响应式机制自动响应Model中数据变化;
同时Viewmodel会实现一套更新策略自动将数据变化转换为视图更新;
通过事件监听响应View中用户交互修改Model中数据。
这样在ViewModel中就减少了大量DOM操作代码。
MVVM在保持View和Model松耦合的同时,还减少了维护它们关系的代码,使用户专注于业务逻辑,兼
顾开发效率和可维护性。
总结
这三者都是框架模式,它们设计的目标都是为了解决Model和View的耦合问题。
MVC模式出现较早主要应用在后端,如Spring MVC、ASP.NET MVC等,在前端领域的早期也有应
用,如Backbone.js。它的优点是分层清晰,缺点是数据流混乱,灵活性带来的维护性问题。
MVP模式在是MVC的进化形式,Presenter作为中间层负责MV通信,解决了两者耦合问题,但P层
过于臃肿会导致维护问题。
MVVM模式在前端领域有广泛应用,它不仅解决MV耦合问题,还同时解决了维护两者映射关系的
大量繁杂代码和DOM操作代码,在提高开发效率、可读性同时还保持了优越的性能表现。
8. 你了解哪些Vue性能优化方法?
答题思路:根据题目描述,这里主要探讨Vue代码层面的优化
路由懒加载
const router = new VueRouter({
routes: [
{
path: '/foo',
component: () => import('./Foo.vue')
}
]
});
keep-alive缓存页面
<template>
<div id="app">
<keep-alive>
<router-view/>
</keep-alive>
</div>
</template>
使用v-show复用DOM
<template>
<div class="cell">
<!--这种情况用v-show复用DOM,比v-if效果好-->
<div v-show="value" class="on">
<Heavy :n="10000"/> </div>
<section v-show="!value" class="off">
<Heavy :n="10000"/> </section>
</div>
</template>
v-for 遍历避免同时使用 v-if
<template>
<ul>
<li v-for="user in activeUsers" :key="user.id"> {{ user.name }} </li>
</ul>
</template>
<script>
export default {
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}
}
</script>
长列表性能优化
如果列表是纯粹的数据展示,不会有任何改变,就不需要做响应化
export default {
data: () => ({ users: [] }),
async created() {
const users = await
axios.get("/api/users");
this.users = Object.freeze(users)
}
};
如果是大数据长列表,可采用虚拟滚动,只渲染少部分区域的内容
<recycle-scroller class="items" :items="items" :item-size="24" >
<template v-slot="{ item }">
<FetchItemView :item="item" @vote="voteItem(item)" />
</template>
</recycle-scroller>
参考vue-virtual-scroller、vue-virtual-scroll-list
[https://github.com/Akryum/vue-virtual-scroller]
[https://github.com/Akryum/vue-virtual-scroller-list]
事件的销毁
Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。
created() {
this.timer = setInterval(this.refresh, 2000)
},
beforeDestroy() {
clearInterval(this.timer)
}
图片懒加载
对于图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域
内的图片先不做加载, 等到滚动到可视区域后再去加载。
<img v-lazy="/static/img/1.png">
第三方插件按需引入
像element-ui这样的第三方组件库可以按需引入避免体积太大。
import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select)
无状态的组件标记为函数式组件
<template functional>
<div class="cell">
<div v-if="props.value" class="on"></div>
<section v-else class="off"></section>
</div>
</template>
<script>
export default {
props: ['value']
}
</script>
子组件分割
<template>
<div>
<ChildComp/>
</div>
</template>
<script>
export default {
components: {
ChildComp: {
methods: {
heavy () {
/* 耗时任务 */
}
},
render (h) {
return h('div', this.heavy())
}
}
}
}
</script>
变量本地化
<template>
<div :style="{ opacity: start / 300 }">
{{ result }}
</div>
</template>
<script>
import { heavy } from '@/utils'
export default {
props: ['start'],
computed: {
base () {
return 42
},
result () {
const base = this.base
// 不要频繁引用this.base
let result = this.start
for (let i = 0; i < 1000; i++) {
result += heavy(base)
}
return result
}
}
}
</script>
9. 你对Vue3.0的新特性有没有了解?
根据尤大的PPT总结,Vue3.0改进主要在以下几点:
更快
虚拟DOM重写
优化slots的生成
静态树提升
静态属性提升
基于Proxy的响应式系统
更小:通过摇树优化核心库体积
更容易维护:TypeScript + 模块化
更加友好
跨平台:编译器核心和运行时核心与平台无关,使得Vue更容易与任何平台(Web、
Android、iOS)一起使用
更容易使用
改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告
更好的调试支持
独立的响应化模块
Composition API
虚拟 DOM 重写
期待更多的编译时提示来减少运行时开销,使用更有效的代码来创建虚拟节点。
组件快速路径+单个调用+子节点类型检测
跳过不必要的条件分支
JS引擎更容易优化
优化slots生成
vue3中可以单独重新渲染父级和子级
确保实例正确的跟踪依赖关系
避免不必要的父子组件重新渲染
静态树提升****(Static Tree Hoisting)
使用静态树提升,这意味着 Vue 3 的编译器将能够检测到什么是静态的,然后将其提升,从而降低了渲
染成本。
跳过修补整棵树,从而降低渲染成本
即使多次出现也能正常工作
静态属性提升
使用静态属性提升,Vue 3打补丁时将跳过这些属性不会改变的节点。
基于 Proxy 的数据响应式
Vue 2的响应式系统使用 Object.defifineProperty 的getter 和 setter。Vue 3 将使用 ES2015 Proxy 作为
其观察机制,这将会带来如下变化:
组件实例初始化的速度提高100%
使用Proxy节省以前一半的内存开销,加快速度,但是存在低浏览器版本的不兼容
为了继续支持 IE11,Vue 3 将发布一个支持旧观察者机制和新 Proxy 版本的构建
高可维护性
Vue 3 将带来更可维护的源代码。它不仅会使用 TypeScript,而且许多包被解耦,更加模块化。

浙公网安备 33010602011771号