VUE 数据驱动渲染(一)

文章转自: https://www.jianshu.com/p/167c3aa20528

回忆

        前端的工作,把数据在视图上展示,完善用户交互逻辑。数据驱动渲染,大幅减少前端工作人员对于数据在Dom上展示的工作,只要专注于数据处理即可。这一小节我们了解一下数据驱动渲染的大概过程。

        Vue就是一个Function类,new Vue->_initcreatedbeforeCreated在这个阶段调用。主要做了合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等初始化工作。

        ->$mount,我们不借助vue-loader等编译工具,采用compile版本的vue进行线上编译的话,会先把template编译成render函数。再调用Vue.prototype.$mount,会调用mountComponent(由New Watcher触发update(render),render把render渲染成vnode,update根据vnode通过creat、diff、patch把vnode变成真实Dom插入)。

主线流程图

概述

        Vue.js 一个核心思想是数据驱动。所谓数据驱动,是指视图是由数据驱动生成的,我们对视图的修改,不会直接操作 DOM,而是通过修改数据。它相比我们传统的前端开发,如使用 jQuery 等前端库直接修改 DOM,大大简化了代码量。特别是当交互复杂的时候,只关心数据的修改会让代码的逻辑变的非常清晰,因为 DOM 变成了数据的映射,我们所有的逻辑都是对数据的修改,而不用碰触 DOM,这样的代码非常利于维护

        在 Vue.js 中我们可以采用简洁的模板语法来声明式的将数据渲染为 DOM:

模板语法来声明式的将数据渲染为 DOM

        最终它会在页面上渲染出 Hello Vue。接下来,我们会从源码角度来分析 Vue 是如何实现的,分析过程会以主线代码为主,重要的分支逻辑会放在之后单独分析。数据驱动还有一部分是数据更新驱动视图变化,这一块内容我们也会在之后的章节分析,这一章我们的目标是弄清楚模板和数据如何渲染成最终的 DOM

new Vue 发生了什么

        从入口代码开始分析,我们先来分析 new Vue 背后发生了哪些事情。我们都知道,new 关键字在 Javascript 语言中代表实例化是一个对象,而 Vue 实际上是一个类,类在 Javascript 中是用 Function 来实现的。

 Vue 只能通过 new 关键字初始化

初始化

来看一下源码,在src/core/instance/index.js 中调用了init()

instance/init.js

        Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。

合并options到$options

instance/init.js中一堆初始化

$mount做挂载

我们来看看initState(instance/state.js)

instance/state.js看看参数里有什么,有就进行初始化

其中我们主要看initData

1、判断data格式,不是function就报错,是的话就调用data.call(vm,vm)返回return对象取到真正data数据。2、取到data的key分别和props、methods做对比,不能想同,相同就报错,因为他们都要挂载到当前实例。3、把对data的访问代理到_data上。4、响应式处理observe。

        Vue 的初始化逻辑写的非常清楚,把不同的功能逻辑拆成一些单独的函数执行,让主线逻辑一目了然,这样的编程思想是非常值得借鉴和学习的。

        由于我们这一章的目标是弄清楚模板和数据如何渲染成最终的 DOM,所以各种初始化逻辑我们先不看在初始化的最后,检测到如果有 el 属性,则调用 vm.$mount 方法挂载 vm,挂载(这一行为)的目标就是把模板渲染成最终的 DOM,那么接下来我们来分析 Vue 的挂载过程。

$mount实例挂载

        Vue 中我们是通过 $mount 实例方法去挂载 vm 的,$mount 方法在多个文件中都有定义,如 src/platform/web/entry-runtime-with-compiler.jssrc/platform/web/runtime/index.jssrc/platform/weex/runtime/index.js。因为 $mount 这个方法的实现是和平台、构建方式都相关的。接下来我们重点分析带 compiler 版本的 $monut 实现,因为抛开 webpack 的 vue-loader,我们在纯前端浏览器环境分析 Vue 的工作原理,有助于我们对原理理解的深入。

        compiler 版本的 $monut 实现非常有意思,先来看一下 src/platform/web/entry-runtime-with-compiler.js 文件中定义。        

1、缓存了原型上的 $mount 方法,再重新定义该方法。2、它对 el 做了限制,Vue 不能挂载在 body、html 这样的根节点上,否则会报错(因为它会替换掉index.html内相应el对应节点)。

         compile版本的话,先对我们el做一些处理,在没有定义render函数时候,尝试去获取reder函数(把整个template通过一系列逻辑判断,因为template有很多实现方式,比如可以直接写template,也可以template是个dom,不写的话通过el获取dom,再把template通过编译手段转化成render函数),再去调用mountComponent(定义了updateComponent函数),updateComponent函数实际上定一个Watcher进行渲染(实际上执行了真正的渲染),视图首次渲染、更新渲染,都通过它来完成。

        $mount 方法支持传入 2 个参数,第一个是 el,它表示挂载的元素,可以是字符串,也可以是 DOM 对象,如果是字符串在浏览器环境下会调用 query 方法转换成 DOM 对象的第二个参数是和服务端渲染相关,在浏览器环境下我们不需要传第二个参数。

         $mount 方法实际上会去调用 mountComponent 方法(core/instance/lifecyle.js)原先原型上的 $mount 方法在这里重新定义,之所以这么设计完全是为了复用,因为它是可以被 runtime only 版本的 Vue 直接使用的,同时也要被compile版本使用。

3、如果$options没有render方法,则会把el或者template字符串编译成render方法。因为无论我们是用单文件 .vue 方式开发组件,还是写了 el 或者 template属性,最终都会转换成 render 方法。

4、在线编译都是调用compileToFunction方法拿到render和static函数赋值给$options,过程我们之后看。5、编译完了,正常调用原型上的$mount方法挂载。

接下来我们看看原型上的mount方法 它在core/instance/lifecyle.js

1、把el缓存到vm.$el上。2、对$options.render函数判断,不存在就赋予一个空虚拟节点。3、对开发环境的$options的render和template做检查,报错。

4、定义undateComponent函数(用于真实dom渲染),由Watcher执行。渲染过程除了首次,之后在更新过程还是会触发渲染Watcher进行执行updateComponent。渲染Watcher实际上就是一个监听到执行的过程。

        mountComponent核心就是先调用 vm._render 方法先生成虚拟 Node,再实例化一个渲染Watcher,在它的回调函数中会调用 updateComponent 方法,最终调用 vm._update 更新 DOM。

        Watcher 在这里起到两个作用,一个是初始化的时候会执行回调函数(updateComponent),另一个是当 vm 实例中的监测的数据发生变化的时候执行回调函数(updateComponent),这块儿我们会在之后的章节中介绍。

        函数最后判断为根节点的时候设置 vm._isMounted 为 true, 表示这个实例已经挂载了,同时执行 mounted 钩子函数。 这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例。

        mountComponent 方法的逻辑也是非常清晰的,它会完成整个渲染工作,接下来我们要重点分析其中的细节,也就是最核心的 2 个方法:vm._render 和 vm._update。    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值