vue数据入口initSate开始分析数据驱动更新原理

2018-11-07 admin

前言

读这篇文章前,最好是先读vue数据绑定源码,因为本篇是接这章写的,放在一篇文章里,篇幅太大,我只好分成两章了。

初始化vue实例

Vue.prototype._init = function (options) {
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm) // 初始化数据的入口
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')

    if (vm.$options.el) {
      vm.$mount(vm.$options.el) // 挂载组件
    }
}

// mountComponent是在挂载组件时调用的方法
export function mountComponent (vm, el ,hydrating) {
  callHook(vm, 'beforeMount')

  let updateComponent = () => {
      vm._update(vm._render(), hydrating)
  }

  new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)

  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }

  return vm
}

initState

上一篇文章,我们已经了解了ObserverDepWatcher都是负责什么?如何互相协作? 接下来,我们从数据的入口开始,了解vue是如何使用这几个类完成的数据驱动视图更新的? 初始化state,就是初始化这几个属性。

clipboard.png

先讲下什么是可观察者对象呢? 具备两个条件: 1、取值的时候,能把要取值的watcher(观察者对象)加入它的dep(依赖,也可叫观察者管理器)管理的subs列表里(即观察者列表); 2、设置值的时候,有了变化,所有依赖于它的对象(即它的dep里收集到的观察者watcher)都得到通知。 watcher里面存储它都观察了谁(dep),dep里面存储了都谁观察了自己。

initProps

clipboard.png

循环每个props属性,对每个属性调用defineReactive,把每个属性加上getset装饰器,变为可观察者对象,如果属性值是对象也会递归转化。

initData

clipboard.png

observe就是循环把data中的所有项都转换成可观察者对象,如果子项是对象或数组就递归转化,确保data里的每一项及其后代都转化成了可观察者对象 初始化数据时,不管data里的数据渲染用没用到,都会转成可观察者对象。 对于propsdata,只有哪个watcher用到了去读取时,才会把该watcher加到他的观察者列表中。

dataprops里都调用了proxy这个方法,他是做什么的呢? proxy(vm,’_data’,key) proxy就是把dataprops下的属性都代理到了vm实例下,vm._data.a等价于vm.a 原理就是Object.definePropertyvmkey属性设置getset方法,当访问get的时候,返回的是vm._data[key];当访问set的时候,设置的是vm._data[key]的值。

initComputed

clipboard.png

初始化计算属性,就是为每一个计算属性定义一个Watcher观察者对象。这个对象是lazy的,不会立即就去执行计算(即get方法),等到用的时候才会去计算,这个时候就会去读取这个计算属性依赖的可观察属性的值来计算,读取的时候就会把这些依赖添加进这个计算watcher里,同时这些依赖的订阅者列表也会加入这个计算watcher。所以当依赖变化时,通知到他的所有订阅watcher。计算watcher接到依赖发生变化了,不会立即计算新值,而是标记dirtytrue,读取这个计算属性的时候,发现dirtytrue,就是说数据已经不是最新的了,需要重新计算,然后才去计算,否则直接取上一次计算的值value

如果某个data通过计算属性间接的被用到了渲染里,那么这个data也会被加入到渲染watcher的依赖列表,它的订阅者列表也会保存渲染watcher。 只有当模版里使用了该计算属性,这个计算属性依赖的可观察者才会被加入到渲染watcher的依赖列表。如果模版里没有直接或间接用到可观察者对象属性,那么当你set它的时候,也就不会触发更新操作。

initWatch

clipboard.png

初始化watch,就是为每个watch属性创建一个观察者对象,这个expOrFn解析取值表达式去取值,然后就会调用相关data/prop属性的get方法,get方法又会在他的观察者列表里加上该watcher,一旦这些依赖属性值变化就会通知该watcher执行update方法。即会执行他的回调方法cb,也就是watch属性的handler方法。

到这里,数据的初始化就完成了。

mountComponent

clipboard.png

这个方法是在,所有的数据初始化完成后,执行挂载组件时调用,创建一个渲染watcher,每个组件有且仅有一个渲染watcherupdateComponentwatchergetter属性,创建后,立即调用get方法,即是调用updateComponent,也就是调用render方法,render里使用了的数据就会读取相关的dataget方法,就会把data的依赖加进这个渲染watcher的依赖列表里,datasubs也会加入渲染watcher,如此,当设置data时拦截的set方法就会通知渲染watcher调用update方法。

我总结下: 一个数据变更后,通知他的Watcher去执行update。 不同类型的Watcher职责不同,vue里的Watcher可以分为3类: 渲染Watcher、计算Watcher、侦听器Watcher,注意这3中Watcher的getter属性分别是什么。

  • 渲染Watcher的update,负责重新渲染,执行render;getter是updateComponent。
  • 计算Watcher的update,负责标记dirty,告诉它数据不是最新的需要重新计算了;getter是计算属性的get方法。
  • 侦听器Watcher的update,负责执行回调方法,也就是watch的handler;getter是watch的取值表达式。

原文链接:https://segmentfault.com/a/1190000016933541

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-44764.html

文章标题:vue数据入口initSate开始分析数据驱动更新原理

相关文章
在 Microsoft Azure 中使用 MEAN 堆栈基于开放数据协议
网络开发人员通常构建伟大的应用程序在客户端使用JavaScript和ASP(c#或Visual Basic . NET)在服务器端。 但是如果你能使用一个共同的语言来构建应用程序的所有层堆栈,从浏览器和服务器端业务处理服务层,甚至在数据库查...
2015-11-12
vuejs通过filterBy、orderBy实现搜索筛选、降序排序数据
直接贴代码了: 先上输入前的样子: <style> #example{margin:100px auto;width:600px;} .show{margin:10px;} #searchText{display: block...
2017-03-17
三步搞定vue在vscode的环境配置问题
1. vscode基础开发插件 vscode-icons 图标美化 Debugger for Chrome 调试 Beautify 代码格式化 Prettier 代码格式化 ESLint 代码规范 JavaScript (ES6) cod...
2017-12-25
v-charts | 饿了么团队开源的基于 Vue 和 ECharts 的图表工具
在使用echarts生成图表时,经常需要做繁琐的数据类型转化、修改复杂的配置项,v-charts的出现正是为了解决这个 痛点。基于Vue2.0和echarts封装的v-charts图表组件,只需要统一提供一种对前后端都友好的数据格式 设置简...
2018-05-24
vue使用watch 观察路由变化,重新获取内容
问题背景: 点击用户头像 => 进入用户个人中心,在用户个人中心里点击其他用户的头像,我希望显示被点击用户的个人中心,但只看到了路由参数在发生变化,页面内容并没有更新。如图: 页面代码如下: <script> exp...
2017-03-13
vue-awesome-swiper的使用以及API整理
一、先说一个看关于vue-awesome-swiper的一个坑 vue项目的package.json中显示的<span style=“color: orange;”>“vue-awesome-swiper”: “^2.5.4”&...
2018-04-26
数据类型和结构
ECMAScript标准定义了七种数据类型 1)布尔值(true 和 false) 2)null,一个特殊的关键字表示空,要注意,javascrip是区分大小写的,所以Null和null是不一样的 3)undefined 表示未定义 4)N...
2015-11-12
详解使用vue-router进行页面切换时滚动条位置与滚动监听事件
按照正常的产品逻辑,我们在进行页面切换时滚动条应该是在页面顶部的,可是。。。在使用vue-router进行页面切换时,发现滚动条所处的位置被自动记录了下来,且在另一个组件内定义的滚动监听事件仍会运行,着实吃了一大惊。。。 说说我的破解方法:...
2017-03-13
Vue 短信验证码组件开发详解
Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此...
2017-03-17
数据格式之战:JSON vs XML
在比较JSON和XML之前,我们先来上一堂关于数据格式的简要历史(更准确的说,是关于XML的始祖): 早在1970年,IBM开发了一种叫Generalized Markup Language的标记语言,简称GML,它主要是为脚本语言定义的一...
2016-01-13
回到顶部