第一个vue程序
vue核心: Dom 监听 与 数据绑定
- view
- model
- viewModel(双向绑定)
- viewModel能观察到数据的变化,并实时更新视图
- viewModel能监听到视图的变化,并通知数据发生改变
MVVM
MVVM 由 Model,View,ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
如何理解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
主要目的是: 分离视图(view)和模型(model),有几大好处:
- 低耦合
- 可复用
- 独立开发
- 可测试
如何实现 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函数
- 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 中
第一个VUE程序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 导入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!--view层:模版-->
<div id="app">
{{msg}}
</div>
<script>
var vm = new Vue({
el: "#app",
//model: 数据
data:{
msg: "hello, vue!"
}
});
</script>
</body>
</html>