从入口开始

我们之前提到过 Vue.js 构建过程,在 web 应用下,我们来分析 Runtime + Compiler 构建出来的 Vue.js,它的入口是 src/platforms/web/entry-runtime-with-compiler.js:

摘选entry-runtime-with-compiler.js


import config from 'core/config'
import { warn, cached } from 'core/util/index'
import { mark, measure } from 'core/util/perf' //主角在这里
import Vue from './runtime/index'
import { query } from './util/index'
import { compileToFunctions } from './compiler/index'
import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat'

Vue 的入口

在这个入口 JS 的上方我们可以找到 Vue 的来源:import Vue from './runtime/index',我们先来看一下这块儿的实现,它定义在 src/platforms/web/runtime/index.js 中:


import Vue from 'core/index'
import config from 'core/config'
import { extend, noop } from 'shared/util'

这里关键的代码是 import Vue from 'core/index'是真正初始化 Vue 的地方[/src/core/index.js]


import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'

这里有 2 处关键的代码,import Vue from './instance/index'(./指的是当前目录) 和 initGlobalAPI(Vue),初始化全局 Vue API,我们先来看第一部分,在 src/core/instance/index.js 中:

Vue 的定义


import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index' function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
} initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue) export default Vue

1

在这里,我们终于看到了 Vue 的庐山真面目,它实际上就是一个用 Function 实现的类,我们只能通过 new Vue 去实例化它

为何 Vue 不用 ES6 的 Class 去实现呢?我们往后看这里有很多 xxxMixin 的函数调用,并把 Vue 当参数传入,它们的功能都是给 Vue 的 prototype 上扩展一些方法(这里具体的细节会在之后的文章介绍,这里不展开),Vue 按功能把这些扩展分散到多个模块中去实现,而不是在一个模块里实现所有,这种方式是用 Class 难以实现的。这么做的好处是非常方便代码的维护和管理,这种编程技巧也非常值得我们去学习。

initGlobalAPI

Vue.js 在整个初始化过程中,除了给它的原型 prototype 上扩展方法,还会给 Vue 这个对象本身扩展全局的静态方法,它的定义在 src/core/global-api/index.js 中:


export function initGlobalAPI (Vue: GlobalAPI) {
// config
const configDef = {}
configDef.get = () => config
if (process.env.NODE_ENV !== 'production') {
configDef.set = () => {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
)
}
}
Object.defineProperty(Vue, 'config', configDef) // exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
} Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
}) // this is used to identify the "base" constructor to extend all plain-object
// components with in Weex's multi-instance scenarios.
Vue.options._base = Vue extend(Vue.options.components, builtInComponents) initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
}

这里就是在 Vue 上扩展的一些全局方法的定义,Vue 官网中关于全局 API 都可以在这里找到,这里不会介绍细节,会在之后的章节我们具体介绍到某个 API 的时候会详细介绍。有一点要注意的是,Vue.util 暴露的方法最好不要依赖,因为它可能经常会发生变化,是不稳定的。

数据驱动

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


<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})

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

原文地址:https://segmentfault.com/a/1190000017132896

深入Vue.js从源码开始(二)的更多相关文章

  1. 从vue.js的源码分析,input和textarea上的v-model指令到底做了什么

    v-model是 vue.js 中用于在表单表单元素上创建双向数据绑定,它的本质只是一个语法糖,在单向数据绑定的基础上,增加了监听用户输入事件并更新数据的功能:对,它本质上只是一个语法糖,但到底是一个 ...

  2. Vue.js 从源码理解v-for和v-if的优先级的高低

    在vue.js里面,v-for和v-if是可以一起使用作用在某个元素上,网上看到一篇文章说永远不要把v-for和v-if同时用在同一个元素上,感觉有点瞎扯,官网也注明了可以一起使用的,还把两个指令的优 ...

  3. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  4. 手牵手,从零学习Vue源码 系列二(变化侦测篇)

    系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 陆续更新中... 预计八月中旬更新完毕. 1 概述 Vue最大的特点之一就是数据驱动视 ...

  5. 一张思维导图辅助你深入了解 Vue | Vue-Router | Vuex 源码架构

    1.前言 本文内容讲解的内容:一张思维导图辅助你深入了解 Vue | Vue-Router | Vuex 源码架构. 项目地址:https://github.com/biaochenxuying/vu ...

  6. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  7. Netty 源码(二)NioEventLoop 之 Channel 注册

    Netty 源码(二)NioEventLoop 之 Channel 注册 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一 ...

  8. [百度地图] 用于类似 DWZ UI 框架的 百度地图 功能封装类 [MultiZMap.js] 实例源码

    MultiZMap 功能说明 MultiZMap.js 本类方法功能大多使用 prototype 原型 实现,它是 ZMap 的多加载版本,主要用于类似 DWZ 这个 多标签的 UI 的框架: 包含的 ...

  9. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

随机推荐

  1. Java原来如此-反射机制

    在Java运行时环境中,对于任意一个类,能知道这个类有哪些属性和方法.对于任意一个对象,能调用它的任意一个方法.这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflect ...

  2. va_list 简介

    原文:http://blog.sina.com.cn/s/blog_590be5290100qhxr.html va_list是一个宏,由va_start和va_end界定. typedef char ...

  3. Linux下挂载指定分区下的某个文件夹到指定目录(mount)

    # 挂载 mount --bind olddir newdir # 卸载 umount newdir 参考: http://www.cnblogs.com/dabaopku/archive/2010/ ...

  4. iOS Framework: Introducing MKNetworkKit (MKNetworkKit介绍,入门,翻译)

    这片文章也有塞尔维亚-克罗地亚语(由Jovana Milutinovich翻译)和日语(由@noradaiko翻译) 如果有个一个网络库能够自动的为你处理cache该有多好啊. 如果有一个网络库能够在 ...

  5. iOS -- 开源项目和库

    TimLiu-iOS 目录 UI 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关与Tabbar 隐藏与显示 HUD与Toast 对话框 其他UI 动画 侧滑与右滑返回手势 gif动画 ...

  6. SQL_字符操作函数

    原创作品.出自 "深蓝的blog" 博客.欢迎转载,转载时请务必注明下面出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlo ...

  7. php.ini的载入位置

    php.ini文件找不到,载入WINDOS下的,但找不到,后来强制-c查找是OK的.思考,为什么载入window下的ini文件.1.可能是有一个默认路径.2.可能没有路径.默认载入. 问题解决:htt ...

  8. 如何防范SQL注入式攻击

    一.什么是SQL注入式攻击? 所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.在某些表单中,用户输入的内容直接用来构造(或者 ...

  9. C++11 并发指南五(std::condition_variable 详解)(转)

    前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread,std::mut ...

  10. 命令行查看w3wp进程信息

    用windbg.mdbg等调试器调试时,当出现多个w3wp进程并且用户名相同,需要区分每个w3wp进程对应的PID(进程ID)和应用程序池信息. 我们用以下方式得到每个w3wp进程的详细信息. Win ...