一、前言

最近一直在使用vue做项目,闲暇之余查阅了一些关于vue实现原理的资料,一方面对所了解到的知识做个总结,另外一方面希望能对看到此文章的同学有所帮助。本文如有不足之处,还请过往的大佬批评指正。

二、vue实现原理概述

vue作为一个前端渐进式的MVVM开发库,将广大的前端劳苦大众从DOM操作中解放出来;说到vue的实现原理,大体可分为三个要素

1、数据的响应式,即vue可以监听到数据的变化

2、模板引擎,模板引擎大家都应该不陌生,同之前使用的handlebars、artTemplate相似,都类似于Html语法,不过可以写一些逻辑在上面(数据绑定和事件绑定)

3、Html的渲染,即通过模板引擎将数据渲染到页面过程

这三点为理论上的实现原理,不过使用vue写项目的时候,从数据变化到页面展示的变化大体可分为一下一个步骤

第一步:解析模板成render函数

第二步:响应式开始监听数据的变化

第三步:首次渲染页面,显示页面,并绑定数据依赖和和事件

第四步:data的变化,触发rerender,更新视图的显示

一下将通过解释vue监听数据的变化、模板绑定数据、数据渲染至页面、实现只渲染数据改变部分DOM这几个部分进行讲解

三、vue实现整体解析

1、vue如何实现对数据的监听的?

说到vue对数据的监听,不得不提到Object.defineProperty,当前主流浏览器均支持此属性,vue的数据双向绑定及数据的监听都是基于此实现的;请看下面代码:

 1 var obj = {};
2 var name = "MrGao"
3 Object.defineProperty(obj, "name", {
4 get: function() { // 获取属性值
5 return name; // name的初始值为"MrGao"
6 },
7 set: function(newval) { // set新的值给属性
8 name = newval
9 }
10 })
11 console.log(obj.name) // MrGao
12 obj.name = "MrBone";
13 console.log(obj.name) // MrBone

可以看到Object.defineProperty传了三个参数进去

第一个参数为目标对象

第二个参数为要定义的属性或方法名称,(如果对象中不包含此属性将此属性添加到目标对象里,vue中将data数据指向vm就是用的这里,下面将详细讲解)

第三个参数为目标属性的所拥有的特性

这三个参数为必填参数,另外对于第三个参数除get和set之外还有一些其它的属性,在这里提一下

value: 属性的值

writable:属性的值是否能被重写,当设置为false的时候为只读,不能通过set进行重新赋值

configurable:是否可以设置他的其他属性(value,writable)

enumerable:是否可以在Object.keys或for...in中列举出来

get和set上面例子已经提到

Object.defineProperty在vue中的实现

我们知道在写vue的时候都是可以通过this.*来读取改变在data中定义的属性,那么这是怎么实现的呢?这就是通过Object.defineProperty将data中的属性指向到vm中,即this就是之vm实例,参考一下实现代码:

 1 var data = {
2 name: "MrGao",
3 age: 22,
4 address: "HangZhou"
5 };
6 var vm = {};
7
8 for(key in data) {
9 (function(key){ // 采用闭包,保证key的独立作用域
10 Object.defineProperty(vm, key, {
11 get: function() {
12 return data[key]
13 },
14 set: function(newval) {
15 data[key] = newval
16 }
17 })
18 })(key)
19 }
20
21 console.log(vm.name);
22 vm.name = "MrBone";
23 console.log(vm.name);

通过分析上面代码可以看出vue通过Object.defineProperty将data中的属性指向vm实例,即this可以获取data中的属性

以上为vue数据响应式监听的原理,接下来我们来看一下模板引擎的实现

2、vue模板引擎

说模板之前先来看下模板是什么:

本质:字符串

带逻辑: 如v-if、v-for、v-model

特点:最终要通过js转换成html代码来显示在页面上

所以如果要让有逻辑的模板显示在页面上,就需要通过js声明一个函数来处理这件事情,我们给它起个名字叫做render

通过都vue源码,可获取关于render函数中的一些核心函数,下面通过一个简单的例子来做下介绍:

 

通过以上代码可看出vue中render函数有两个特点,一是使用了with函数,二是模板中所有的信息都包含在render函数中;其中函数中的this指的就是vm,所以_c、_v、_s、tittle分别指的是vm._c、vm._v、vm._s、vm.tittle。这里重点说下_c,这里的_c和snabbdom.js中的h()函数相似,下面还会说到vdom中的patch()函数,要了解虚拟DOM相关细节我将在下一篇博客中介绍。

此处render函数将返回一个虚拟DOM,即vnode,并将vnode传到patch()函数中;参考下面代码:

vm._updata(vnode) {
const prevVnode = vm._vnode;
vm._vnode = vnode; // 将新的vnode赋值给旧的_vnode
if (!prevVnode) { // 如果旧的_vnode不存在则将dom挂载在vm.$el
vm.$el = vm.__patch__(vm.$el, vnode);
} else {
vm.$el = vm.__patch__(prevVnode, vnode);
}
}
function updateComponent() {
// vm._render为返回的虚拟DOM
vm._update(vm._render());
}

 3、数据渲染至页面

将数据渲染进页面,通过patch函数将虚拟DOM转换为真实DOM结构页面进行展示,渲染页面的函数调用如下:

初次渲染

1、执行updateComponent,执行vm._render()

2、执行render函数,会访问到数据源

3、相应式get方法监听到访问的数据源执行updateComponent,到patch()方法中的 vm.$el = vm.__patch__(vm.$el, vnode);

4、patch()将虚拟DOM渲染成DOM,初次渲染完成

修改属性渲染

1、修改属性,被响应式set监听到

2、set中执行updateComponent

3、updateComponent重新执行vm._render()

4、生成vnode和旧的prevVnode,通过patch进行比较  vm.$el = vm.__patch__(prevVnode, vnode);

5、DOM更新

四、小节

以上为今天所讲的内容,对vue的实现原理进行了一个简单剖析,至于vue中实现的DOM的差量更新,vue2.0之后引入的虚拟DOM,是基于vdom的diff算法原理,通过patch函数比较vdom更新前后的数据差异进行DOM的更新,篇幅有限,这里就不在对虚拟DOM进行赘述,如有兴趣,欢迎阅读我下一篇关于虚拟DOM的文章。

什么是虚拟DOM

vue源码实现的整体流程解析的更多相关文章

  1. Duilib源码分析(六)整体流程

    在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...

  2. vue源码cached高阶函数解析

    1.源代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...

  3. 104 - kube-scheduler源码分析 - predicate整体流程

    (注:从微信公众:CloudGeek复制过来,格式略微错乱,更好阅读体验请移步公众号,二维码在文末) 今天我们来跟一下predicates的整个过程:predicate这个词应该是“断言.断定”的意思 ...

  4. Vue源码详细解析:transclude,compile,link,依赖,批处理...一网打尽,全解析!

    用了Vue很久了,最近决定系统性的看看Vue的源码,相信看源码的同学不在少数,但是看的时候却发现挺有难度,Vue虽然足够精简,但是怎么说现在也有10k行的代码量了,深入进去逐行查看的时候感觉内容庞杂并 ...

  5. Vue源码解析---数据的双向绑定

    本文主要抽离Vue源码中数据双向绑定的核心代码,解析Vue是如何实现数据的双向绑定 核心思想是ES5的Object.defineProperty()和发布-订阅模式 整体结构 改造Vue实例中的dat ...

  6. Vue源码解析之nextTick

    Vue源码解析之nextTick 前言 nextTick是Vue的一个核心功能,在Vue内部实现中也经常用到nextTick.但是,很多新手不理解nextTick的原理,甚至不清楚nextTick的作 ...

  7. ibatis源码学习1_整体设计和核心流程

    背景介绍ibatis实现之前,先来看一段jdbc代码: Class.forName("com.mysql.jdbc.Driver"); String url = "jdb ...

  8. Vue 源码解读(8)—— 编译器 之 解析(上)

    特殊说明 由于文章篇幅限制,所以将 Vue 源码解读(8)-- 编译器 之 解析 拆成了上下两篇,所以在阅读本篇文章时请同时打开 Vue 源码解读(8)-- 编译器 之 解析(下)一起阅读. 前言 V ...

  9. 【vuejs深入二】vue源码解析之一,基础源码结构和htmlParse解析器

    写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. vuejs是一个优秀的前端mvvm框架,它的易用性和渐进式的理念可以使每一个前端开发人员感到舒服,感到easy.它内 ...

随机推荐

  1. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_01-用户认证需求分析

    1.1 用户认证与授权 截至目前,项目已经完成了在线学习功能,用户通过在线学习页面点播视频进行学习.如何去记录学生的学习过程 呢?要想掌握学生的学习情况就需要知道用户的身份信息,记录哪个用户在什么时间 ...

  2. nginx在windows系统中如何启动、重启、停止

    nginx在windows系统中如何启动.重启.停止   查看nginx的版本号:nginx -v 启动nginx:start nginx 快速停止或关闭nginx:nginx -s stop 正常停 ...

  3. js下利用userData实现客户端保存表单数据

    对于多数网页制作的朋友,实现在客户端保存在网页表单上的信息,比较多的是采用Cookie技术来实现,这些功能例如:下拉列表框选择的选项,文本框输入的数据等. 事实上,我们可以利用微软DHTML默认行为中 ...

  4. (四)UML之顺序图(时序图)

    一.概念 顺序图是交互图的一种形式,它显示对象沿生命线发展,对象之间随时间的交互表示为从源生命线指向目标生命线的消息.顺序图能很好地显示那些对象与其它那些对象通信,什么消息触发了这些通信,顺序图不能很 ...

  5. topK问题

    概述 在N个乱序数字中查找第K大的数字,时间复杂度可以减小至O(N). 可能存在的限制条件: 要求时间和空间消耗最小.海量数据.待排序的数据可能是浮点型等. 方法 方法一 对所有元素进行排序,之后取出 ...

  6. 【ARM-Linux开发】ARM板卡上QT显示中文

    平台:Freescale imx6  编译系统:yocto  Qt版本:5.5.1 刚弄了个Qt程序到开发板,发现中文都没有显示,英文可以显示.  就加了个中文字库.DroidSansFallback ...

  7. csu 1958: 数字游戏

    1958: 数字游戏 Submit Page   Summary   Time Limit: 2 Sec     Memory Limit: 128 Mb     Submitted: 134     ...

  8. SSRAM、SDRAM和Flash简要介绍

    问题1:什么是DRAM.SRAM.SDRAM?答:名词解释如下DRAM--------动态随即存取器,需要不断的刷新,才能保存数据,而且是行列地址复用的,许多都有页模式SRAM--------静态的随 ...

  9. 27.Spark中transformation的介绍

    Spark支持两种RDD操作:transformation和action.transformation操作会针对已有的RDD创建一个新的RDD: 而action则主要是对RDD进行最后的操作,比如遍历 ...

  10. rsyslog服务日志报错分析1

    客户问题: 最近对服务器进行日志检查时,发现部分主机的rsyslog服务状态有报错,报错详情如下 排查过程: 1.从报错截图来看,报错主要发生在文件'/usr/lib64/rsyslog/omazur ...