zoukankan      html  css  js  c++  java
  • vue源码实现的整体流程解析

    一、前言

    最近一直在使用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

  • 相关阅读:
    自定义IP原来如此简单
    [转]如何在NIOS II中读写EPCS剩余空间
    坏了的芯片居然又好了一片,太神奇了
    今天报废两片EP3C5E144
    Quartus II 订购版 v10.1 正式推出下载
    发现用JTAG下载程序到EPCS比用AS方式下载速度快
    如何解决No EPCS layout data looking for section [EPCSXXXXXX]
    QII丰衣足食
    Why does my Cyclone III FPGA fail to access the EPCS device using the EPCS Controller module?
    <转载>在.NET中基于Windows消息的IPC实现
  • 原文地址:https://www.cnblogs.com/gaosong-shuhong/p/9253950.html
Copyright © 2011-2022 走看看