MVVM 和 VUE
- 如何理解mvvm
- 如何实现mvvm
- 是否读过vue源码
题目
- 说一下使用jQuery和使用mvvm框架的区别
- 说一下对mvvm的理解
- vue如何实现响应式
- vue如何解析模板
- vue的整个实现流程
jQuery和vue的区别:
- 数据和视图分离,解耦(开放封闭原则)
- 以数据驱动视图,只关心数据变化,DOM操作被封装
对mvvm的理解
- mvc(modal, view, controller)
- mvvm(modal, view, viewModal)
viewModal: 连接modal和view的桥梁
mvvm是借鉴了后端的mvc发展而来的,把controller变成了viewModal
vue实现的三要素
- 响应式:vue如何监听到data中每个属性的变化?
- 模板引擎:vue的模板如何被解析,指令如何处理?
- 渲染:vue的模板如何被渲染成html,以及渲染过程?
vue中如何实现响应式?
响应式就是:修改data属性之后,vue立即监听到。data属性被代理到vm上。使用
Object.defineProperty
来定义访问器属性。
let obj = {};
let name = 'tom';
Object.defineProperty(obj, 'name', {
get () {
console.log('get');
return name;
},
set (newVal) {
console.log('set');
name = newVal;
}
})
这里有个巧妙地地方:data中每个属性都会双向绑定,但不是每个属性都会在模板中渲染,所以这里会有这样一个逻辑:当一个属性的get有用时才会走set,因为如果你没有get,说明你跟渲染无关,此时set他也不用渲染。这样可以避免不必要的渲染,提高性能。
vue中如何解析模板
模板的本质是字符串,有逻辑(v-if,v-for),与html很像但有很大区别,最终会转化成html来显示。
模板有逻辑,并且要渲染html,所以要转换为js代码(render函数)。
render函数-with
vue模板解析中使用了with语法,但是实际开发中不推荐使用with
// js中的with语法
const obj = {
name: 'tom',
age: 20,
getAddress () {
alert('beijing');
}
}
// 不用with
function fn() {
alert(obj.name);
alert(obj.age);
obj.getAddress();
}
// 使用wid
function fn() {
with(obj) {
alert(name);
alert(age);
getAddress();
}
}
render函数
先来个简单的模板转render函数的例子
<div id="app">
<p>{{price}}</p>
</div>
var vm = new Vue({
el: "#app",
data: {
price: 100
}meth
});
//模板对应的render函数片段
with(this) { // this就是vm
return _c(
'div',
{
attrs: {"id": "app"}
},
[
_c('p', [_v(_s(price))])
]
)
}
vue文件中的html模板部分最终都会被编译为render函数。同样的,React中的jsx模板也是通过编译之后变成js代码来使用的。
vue2.0开始支持预编译。预编译就是在打包的时候,就把我们写在.vue文件中的html模板编译成js的render函数。部署到线上的时候都是就已经都是js了。
render函数和vdom
- vm._c其实相当于snabbdom中的h函数,他们都是render函数
- render函数执行之后,返回的是vnode
- data中每次修改数据的时候,执行updateComponent
render函数是什么样子的?render函数其实就返回了一个vdom的h函数,返回一个vnode
vue的整体实现流程
- 第一步:解析模板成render函数(因为预编译,这一步在打包的时候就发生了)
- with的用法
- 模板中所有信息都被render函数包含
- 模板中用到的data中的属性都变成了js变量
- 模板中的
v-modal
,v-for
,v-on
都变成js逻辑 - render函数返回vnode
- 第二步:响应式开始监听(页面打开js开始执行的时候发生)
- Object.defineProperty
- 将data的属性代理到vm上
- 第三步:首次渲染,显示页面且绑定依赖
- 虚拟dom中的patch函数(第一种用法)
patch(el, vnode)
- 虚拟dom中的patch函数(第一种用法)
- 第四步:data属性变化,触发re-render
- 虚拟dom中的patch函数(第二种用法)
patch(preVnode, newVnode)
- 虚拟dom中的patch函数(第二种用法)