手记

阅读源码后对VUE的理解~

在学习vue的时候看了不少相关的文章 但是始终不明白其中的原委,不明白为什么创建了一个vue实例就会实现数据会驱动视图更改,哪些个指令是什么鬼 也不明白传入vue实例后参数到底发生了什么?没办法只能自己看源码了 仅以此文记录一下自己对vue的认识~···
先看一下最简单的实例:
html代码如下:

<!DOCTYPE html>
<html>
<head>
<script src="http://vuejs.org/js/vue.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<div id="app">{{message}}
  <button v-on:click="sayHello">click</button>
</div>
</html>

html引入了vue.js,下面是创建vue实例的js代码:

var app = new Vue({
    el:'#app',
    data:{
      message:'hello world!',
      sayHello:function(){
          console.log(1)
      }
  }
})

在这个案例中,传入了el和data 两个参数,
1.对于data这个参数,vue函数在内部,遍历了这个参数下的所有属性,并为每个属性做了一个处理。就是用js的原生函数Object.defineProperty为这些属性分别定义了属性。有点绕,也就是说属性本身也是有属性的,比如这个属性是否可读,是否可写,还有getter和setter属性。getter属性里面定义的是一个函数,表示我们在获取这个属性的值的时候,会触发这个函数,setter属性里面定义的也是一个函数,表示的是我们在改变这个属性的值的时候,就触发这个函数。那么这两个函数是怎么定义的呢?我们先看看el这个参数。
2.对于el这个参数,vue函数根据这个参数的参数值“#app”,获取到html文件中id为“#app”下的所有的标签内容,我们称之为template。拿到这个template之后呢,会通过一个编译函数将这个template转化成一个名叫render的函数。
接着创建了一个watch对象,watcher对象有个upadate方法,在这里被调用。(这个update函数内部调用的是vue实例的updated函数。这个函数会调用到前面的render 函数),最终把template转化成虚拟的node 节点。所谓虚拟的node节点就是用对象来表示这些标签,一个标签对应一个虚拟节点,即一个标签对应一个对象,这个对象里面包含了标签的相关信息,比如一个标签的tag,attr等等,这些都是为了创建真实的dom节点用的。button也会对应一个虚拟节点。button这个虚拟节点是div这个虚拟节点的子节点,所以button 这个虚拟节点(虚拟节点就是对象)被保存在div 虚拟节点的children 字段下。如果button下也有子节点,这个子节点同理会被保存到button虚拟节点下的children字段中。可以想象,template 就是被转换成树状结构的虚拟节点。这个虚拟节点树,最终会被渲染成真实的dom。
3.这里的{{message}}呢?这个文本是属于div这个虚拟节点的,创建虚拟div时,先通过正则匹配到这是一个vue语句,取出里面的message字段,对应data中定义的属性message,然后把this.data.message的值赋值给这个虚拟节点下的某个属性,作为创建真实dom时的文本。this.data.message在前面被设置了getter 和setter函数,所以在这里一赋值,就会调用前面定义的getter 函数。这个getter函数实际上就是把watcher 对象(watcher对象作为一个字段被保存在vue实例中) 加入一个数组中。
4.在我们更改this.data.message的值的时候,会调用setter 函数,setter 函数里面定义的就是遍历这个数组,调用watcher 对象的updata函数,也就是调用vue实例的update 函数,会导致虚拟节点的数据更改,那么渲染成真实的dom的数据也更改了 。
5..v-on这个指令被怎么处理了呢?这个指令被包装成了一个diretive 对象,这个对象里面包含了各种信息,其中有个字段叫express ,里面存的就是函数表达式。
再看一个案例:

   <div id="app">
       <my-component>
    <heading></heading>
     </my-component>
    </div>
 ---

 var Child = {
   template: '<h3>Hello World</h3>'
 }

 var app = new Vue({
   el:'#app',
   components:{
     'my-component':Child
   }
 })

这里的template中有个自定义的标签<my-conmponet>,这个template在转换成虚拟节点的时候,这个my-conmponet它也是一个虚拟节点,但是能这个虚拟节点和一般的不一样,需要特殊处理,否则在渲染成真实的dom时会不认识这个节点。那么第一个要做的就是注册这个节点。以这个案例为例:
1.vue实例化的时候被传入了一个components对象,首先就是遍历这个对象,在这里这个对象只有一个字段 'my-component',根据这个字段及其值生成一个创建组件的vuecomponent函数。这个函数被保存到vue.componets.my-component中,也就是说这个组件被注册了。
2.说明一下:这个函数继承vue函数,和vue的功能很相似。是用来实例化组件的,实例化一个组件的过程就和实例化一个vue的过程差不多。其中“my-compont”是组件名,另外,我们知道template中的my-compont标签最终是要被渲染成真实的dom的,而真实的dom就是这里的”: '<h3>Hello World</h3>'。
3.注册完了之后呢?这个vuecomponets什么时候会被调用?
在前面我们说了 my-component 会被渲染成一个虚拟节点 但是它比较特殊,这个虚拟节点中保存的数据和一般的不一样。这些数据也就是表明这是一个自定义的标签,是一个组件。等到整个虚拟节点树创建真实dom时,对于个标签,会实例化一个组件,也就是new vuecomponent函数,前面说过这个函数创建组件的过程和vue差不多,也就是说它做的事情同样也是把template: '<h3>Hello World</h3>'渲染成虚拟节点树,绑定数据,等等工作。这个函数生成的真实dom 和vue生成的真实的dom 共同组成了最后的html

还想说说vue中的过渡,有时间再写了。好累哦

8人推荐
随时随地看视频
慕课网APP

热门评论

言简意赅,谢谢作者的分享

很优秀很贴近我的需求

查看全部评论