Vue数据绑定(一)
Vue作为当下炙手可热的前端三大框架之一,一直都想深入研究一下其内部的实现原理,去学习MVVM模式的精髓。如果说MVVM是当下最流行的图形用户界面开发模式,那么数据绑定则是这一模式的根基。这也是我为什么要从数据绑定开始了解Vue的原因。
本篇文章首先从Vue构建开始,后面主要了解methods、data的执行过程以及原理,结合Vue文档来分析,做到知其然且知其所以然。对于计算属性、组件系统、指令等将在后续文章中分析。
源代码基于vue1.0,最新版本为2.x,其中的差异我会在文章尽量列出来。
Vue构造过程
1 |
function (options) {
|
Vue构造函数调用了一个_init函数,Vue所有的内置属性和方法都以_或者$开头:
1 |
exports.isReserved = function (str) {
|
_init函数调用了若干个初始化函数其中就包含了一个初始化状态属性相关的函数:
1 |
//instance/state.js |
看到调用函数的名称都知道是什么意思,这里主要研究一下_initMethods和_initData两个函数的实现原理。其余的会在后续文章分析。
_initMethods:
1 |
exports._initMethods = function () {
|
对于methods的初始化相对比较简单,这个函数的主要作用就是把用户定义在methods属性内的一些方法绑定到当前的Vue实例中。由于ES6的箭头函数会导致bind失败,这也是为什么Vue在文档中提示:
不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch(‘a’, newValue => this.myMethod())。因为箭头函数是和父级上下文绑定在一起的,this 不会是如你所预期的 Vue 实例,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
_initData:
1 |
exports._initData = function () {
|
对于子组件而言,propsData表示父组件传递过来的数据,因为initProp先执行_data填充的是父组件传递过来的数据。optionsDataFn表示组件自身的数据。 为什么这里看到的是一个函数呢?这是因为在Vue的初始化函数_init内调用了util/option.js下的mergeOptions这个方法,为了方便合并父组件和子组件的数据,它定义了一系列策略把组件传入的参数替换了。为了避免父组件的数据被子组件原生的数据覆盖需要做一次判定,发现有数据覆盖就警告用户。需要注意的是属性值为null且子组件原生就有的数据字段是不会被覆盖的。
在把数据合并之后,接下来要对组件数据做一个代理:
1 |
//... |
数据代理的作用就是为了实现:vm.prop === vm._data.prop的效果。代码位置在instance/state.js下的_proxy函数:
1 |
exports._proxy = function (key) {
|
为了避免覆盖Vue内置的属性所以做一次判定,接下来就是对数据的访问做一个代理。
仅仅代理数据是不够的,接下来要看到的是监控数据的变化:
1 |
exports._initData = function () {
|
Observer.create是Vue响应式数据绑定的核心:
1 |
Observer.create = function (value, vm) {
|
数据监听只针对对象类型,监听对象会内嵌到被监听的对象,这样可以避免重复监听数据对象:
1 |
function Observer (value) {
|
需要注意的是,Vue对象实例不会被监听,通过_isVue属性来辨别。对于被冻结的对象也是不能监听的,Vue通过接口Object.isFrozen来判定,官方文档也有说明:
这里唯一的例外是使用 Object.freeze(),这会阻止修改现有的属性,也意味着响应系统无法再追踪变化。
Observer对象会反向引用Vue实例对象,这是为了在用户调用$delete的时候能够反向通知到Vue实例对象, 把挂在实例上的被删除属性去除:
1 |
exports.delete = function (obj, key) {
|
数据的变化追踪分为两类:对象和数组类型。对象类型遍历属性监听每个属性的变化:
1 |
Observer.prototype.walk = function (obj) {
|
convert函数调用了数据追踪最关键的一个函数:
1 |
function defineReactive (obj, key, val) {
|
由于对象的属性可能还是一个对象或者数组。所以需要递归的追踪内嵌数据的变化。数据的监听者存放在Dep模块内。每次设置新的对象需要重新监听数据属性。
数组类型的数据监听追踪比较特殊,Vue通过拦截几个数组方法来追踪数组的变化
1 |
function Observer (value) {
|
arrayMethods是一个以Array.prototype为原型的对象://observer/array.js
1 |
var arrayProto = Array.prototype |
通过_.hasProto方法判定代理数组对象的若干个方法:
1 |
function protoAugment (target, src) {
|
至此Vue的数据追踪流程执行完毕。Vue提供了两个全局方法Vue.set和Vue.delete。下面来研究一下两个函数的实现,Vue.set最终会调用到util/lang.js下的set方法:
1 |
exports.set = function set (obj, key, val) {
|
如果设置的属性之前已经有了,这个时候直接设置就行,会促发相应的更新逻辑。如果是Vue对象则设置到_data属性内。如果数据对象不是响应式的则直接新增数据属性。这个时候不会触发视图更新等操作。反之通知相应的监听方,并且递归追踪新增的数据值。Vue官方文档有如下提示:
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性。
Vue.delete最终调用util/lang.js下的delete方法。
1 |
exports.delete = function (obj, key) {
|
被删除的属性如果不是响应式的,则直接删除然后退出函数。反之,通知各个监听对象,并且通过_unproxy方法把挂在Vue实例上的属性删除。
Vue数据绑定(一)的更多相关文章
- Vue数据绑定
gitHub地址:https://github.com/lily1010/vue_learn/tree/master/lesson04 一 双括号用来数据绑定 (1)写法一: {{message}}, ...
- 浅析vue数据绑定
前言:最近团队需要做一个分享,脚进脑子,不知如何分享.最后想着之前一直想研究一下 vue 源码,今天刚好 "借此机会" 研究一下. 网上研究vue数据绑定的文章已经非常多了,但是自 ...
- Vue数据绑定和响应式原理
Vue数据绑定和响应式原理 当实例化一个Vue构造函数,会执行 Vue 的 init 方法,在 init 方法中主要执行三部分内容,一是初始化环境变量,而是处理 Vue 组件数据,三是解析挂载组件.以 ...
- 17: VUE数据绑定 与 Object.defineProperty
VUE数据绑定原理:https://segmentfault.com/a/1190000006599500?utm_source=tag-newest Object.defineProperty(): ...
- (三)vue数据绑定及相应的命令
vue数据绑定及相应的命令 {{ Text }} 双括号进行数据渲染 动态绑定数据 例如:{{message}} data: { return{ message: 'Hello Vue!' } } 2 ...
- 「每日一题」有人上次在dy面试,面试官问我:vue数据绑定的实现原理。你说我该如何回答?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 来源:原创 一.前言 文章首发在「松宝写代码」 2020. ...
- vue数据绑定原理
一.定义 vue的数据双向绑定是基于Object.defineProperty方法,通过定义data属性的get和set函数来监听数据对象的变化,一旦变化,vue利用发布订阅模式,通知订阅者执行回调函 ...
- vue 数据绑定实现的核心 Object.defineProperty()
vue深入响应式原理 现在是时候深入一下了!Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.这使得状态管理非常简 ...
- vue数据绑定数组,改变元素时不更新view问题
关于这个问题,官网上说的很清楚官方文档 写个例子HTML<body> <div class="box"> <div v-for="aa i ...
随机推荐
- java常用工具类(一)
一.String工具类 package com.mkyong.common; import java.util.ArrayList; import java.util.List; /** * * St ...
- 吴裕雄--天生自然TensorFlow高层封装:解决ImportError: cannot import name 'tf_utils'
将原来版本的keras卸载了,再安装2.1.5版本的keras就可以了.
- ZZJ_淘淘商城项目:day01(RESTful Web Service、SVN)
淘淘商城项目是很适合初级Java程序员练习的实战项目,本次复习是另一位张老师教授的课,内容上与之前入老师版taotao商城比较有些新东西加了进来. 因此有必要记录下那些直到现在还可供参考的技术亮点分享 ...
- [HDU多校]Ridiculous Netizens
[HDU多校]Ridiculous Netizens 点分治 分成两个部分:对某一点P,连通块经过P或不经过P. 经过P采用树形依赖背包 不经过P的部分递归计算 树型依赖背包 v点必须由其父亲u点转移 ...
- 视觉SLAM算法框架解析(2) ORB-SLAM
版权声明:本文为博主原创文章,未经博主允许不得转载. ORB-SLAM[1]完全继承了PTAM(http://www.cnblogs.com/zonghaochen/p/8442699.html)的衣 ...
- 4412开发板QtE系统下MT6620-wifi的测试
基于iTOP4412系统烧写并启动之后,使用如下命令.wpa_passphrase XXX "YYY " >> /etc/wpa_supplicant.conf其中 X ...
- Maven 仓库搜索服务和私服搭建
Maven 仓库搜索服务 使用maven进行日常开发的时候,一个常见问题就是如何寻找需要的依赖,我们可能只知道需要使用类库的项目名称,但是添加maven依赖要求提供确切的maven坐标,这时就可以使用 ...
- [LC] 285. Inorder Successor in BST
Given a binary search tree and a node in it, find the in-order successor of that node in the BST. Th ...
- 关于Java中反射的总结
Java是面向对象的编程语言,万物皆对象,反射技术就是把类声明.类中的字段声明.方法声明.构造函数声明等都看成是对象,从而可以把类中的各个部分拆解出来单独处理,反射技术主要用来编写通用功能,平时编程使 ...
- IntelliJ IDEA项目断开版本管理解决方案
今天使用idea时打开项目突然发现项目不受svn管理(项目目录依然受svn管理,只是idea脱管了),如遇到可用以下方法: 图片示例: 1. 2. 希望能帮到你