框架到底为我们做了什么?
- 数据和视图分离,解耦(开放封闭原则)
- 所有数据和视图不分离的,都会命中开放封闭原则
-
Vue数据独立在data里面,视图在template中
- 以数据驱动视图,只关心数据变化,
dom操作被封装- 使用原生js是直接通过操作
dom来修改视图,例如ducument.getElementById('xx').innerHTML="xxx" - 以数据驱动视图就是,我们只管修改数据,视图的部分由框架去帮我们修改,符合开放封闭模式
- 使用原生js是直接通过操作
如何理解 MVVM ?
- MVC
-
Model数据 →View视图 →Controller控制器
-
- MVVM
-
MVVM不算是一种创新 - 但是其中的
ViewModel是一种创新 -
ViewModel是真正结合前端应用场景的实现
-
- 如何理解MVVM
-
MVVM - Model View ViewModel,数据,视图,视图模型 - 三者与
Vue的对应:view对应template,vm对应new Vue({…}),model对应data - 三者的关系:
view可以通过事件绑定的方式影响model,model可以通过数据绑定的形式影响到view,viewModel是把model和view连起来的连接器
-
如何实现 MVVM - 以 Vue.js 为例
MVVM 框架的三大要素
- 响应式:
Vue如何监听到data的每个属性变化 - 模板引擎:
Vue的模板如何被解析,指令如何处理 - 渲染:
Vue的模板如何被渲染成html,渲染过程是怎样的
Vue 如何实现响应式
- 什么是响应式
- 修改
data属性之后,Vue立刻监听到,立刻渲染页面 -
data属性被代理到vm上
- 修改
- Object.defineProperty
- 将对象属性的值的设置和访问 (get,set) 都变成函数,可以在当中加入我们自己的逻辑(进行监听)
- 普通的
JavaScript对象,做属性修改,我们监听不到,所以需要用到Object.defineProperty - 既能get,又能set,才是双向数据绑定
Vue 如何解析模板
- 模板是什么
- 本质:模板就是字符串
- 与html格式很像,但是模板中是有逻辑的,可以嵌入JS变量,如v-if, v-for等
- 视图最终还是需要由模板生成
html来显示 - 模板必须先要转换成JS代码
- 有逻辑(v-if, v-for),必须用JS才能实现(图灵完备)
- 转换为html渲染页面,必须用JS才能实现
- 因此,模板要转换成render函数
- render函数
- render函数包含了模板中所有的信息,返回
vnode,解决了模板中的逻辑(v-if, v-for)问题 - 如何找到最终生成的render函数
- 找到vue源码,搜索
code.render,将code打印出来,就是生成的render函数
- 找到vue源码,搜索
- render函数包含了模板中所有的信息,返回
- render函数与vdom
- 模板生成
html:vm._c -
vm._c和snabbdom中的h函数的实现很像,都是传入标签,属性,子元素作为参数 -
Vue.js的vdom实现借鉴了snabbdom -
updateComponent中实现了vdom的patch - 页面首次渲染执行
updateComponent -
data中每次修改属性,都会执行updateComponent
- 模板生成
Vue.js 运行机制
- 第一步:解析模板成
render函数- 因为在打包的时候就已经生成了render函数,所以编译是第一步;响应式监听是在代码执行的时候才开始监听。
- 模板中的所有信息都被render函数包含
- 模板中用到的data中的属性,都变成了js变量
- 模板中的 v-model v-for v-on都变成了js逻辑
- render函数返回vnode
- 第二步:响应式开始监听
- 通过Object.definedProperty监听到对象属性的get和set
- 将data的属性代理到vm上
- 第三步:首次渲染,显示页面,且绑定依赖
- 初次渲染,执行
updateComponent,执行vm._render() - 执行
render函数,会访问到data中的值,访问时会被响应式的get方法监听到 - 执行
updateComponent,会走到vdom的patch方法 -
patch将vnode渲染成dom,初次渲染完成 - 疑问:为何要监听
get,而不是直接监听set?- 因为
data中有很多属性,有些被用到,有些可能不被用到 - 只有被用到的才会走
get - 没有走到
get中的属性,set的时候我们也无需关心 - 避免不必要的重新渲染
- 因为
- 初次渲染,执行
- 第四步:
data属性变化,触发re-render- 修改属性,被响应式的
set监听到 -
set中执行updateComponent -
updateComponent重新执行vm._render() - 生成的
vnode和prevVnode,通过patch进行对比 - 渲染到
html中
- 修改属性,被响应式的