vue学习笔记

1.vue data属性里面的getter和setter

data的每个属性都有两个相对应的get和set属性。

vue学习笔记_第1张图片

ES5的对象原型有两个新的属性__defineGetter__和__defineSetter__,专门用来给对象绑定get和set。可以这样书写:


vue学习笔记_第2张图片

vue双向绑定原理是由数据劫持结合发布者-订阅者模式实现的。

vue的数据劫持是通过Object.defineProperty()来对对象的setter和getter属性进行操作,在数据进行变动时,进行你想要的操作。

语法:Object.defineProperty(obj,prop,descriptor)

            参数:

                obj:要在其上定义属性的对象。

                prop:要定义或修改的属性名称。

                descriptor:将被定义或修改的属性描述。

            返回值:

                  被传递给函数的对象。

也就是说他可以控制一个对象属性的一些特有操作,比如读写或是否可枚举等,这里组要看set和get。

vue学习笔记_第3张图片

2.vue.js计算属性computed(getter,setter)

在Vue中,computed的属性可以被视为是data一样,可以读取和设置,因此在computed中可以分成getter和setter,一般情况下没有setter,computed预设只有getter,也就是只能读取,不能改变设值。

vue.js计算属性默认只有getter,因为是默认值所以我们也常常忽略不写,如下代码:

vue学习笔记_第4张图片

完整写法:

vue学习笔记_第5张图片

计算属性getter的出发时间:

vue学习笔记_第6张图片

如果我们改变上边代码里的2个输入框的值firstName或则lastName,都会触发computed以及updated(),也就是说会执行:console.log('computed')和console.log('updated');

需要注意的是,不是说我们更改了getter里使用的变量,就会触发computed的更新,前提是computed里的值必须要在模板里面使用才行。如果把上面代码中的p标签注释掉,就算改变input的值也不会触发computed。

2.vue生命周期。

1new Vue{

         router,

         store,

          //components: { App } vue1.0的写法

            render: h => h(App) vue2.0的写法

}).$mount('#app')

1.首先需要了解这是 es 6 的语法,表示 Vue 实例选项对象的 render 方法作为一个函数,接受传入的参数 h 函数,返回 h(App) 的函数调用结果。

2.其次,Vue 在创建 Vue 实例时,通过调用 render 方法来渲染实例的 DOM 树。

3.最后,Vue 在调用 render 方法时,会传入一个 createElement 函数作为参数,也就是这里的 h 的实参是 createElement 函数,然后 createElement 会以 APP 为参数进行调用,关于 createElement 函数的参数说明参见:Element-Arguments。

vue学习笔记_第7张图片


先了解一下vue的虚拟dom:

Vitual DOM是一种虚拟dom技术,本质上是基于javascript实现的,相对于dom对象,javascript对象更简单,处理速度更快,dom树的结构,属性信息都可以很容易的用javascript对象表示:

vue学习笔记_第8张图片

Virtual DOM并没有完全实现DOM,最主要还是保留了Element之间的层次关系和一些基本属性。你给我一个数据,我根据数据生成一个全新的Virtual DOM,然后跟我上一次生成的Virtual DOM去diff,然后通过patch方法挂载。

我们可以通过javascript对象表示的树结构来构建真正的DOM树,当数据发声变化时,可以直接修改这个javascript对象,接着对比修改后的对象,记录下需要对页面做的dom操作,然后将其应用到真正的DOM树,实现视图的更新。

VNode生成最关键点是通过render函数,由2种生成方式,第一种是直接在vue对象的option种添加render字段。第二种是写一个模板或指定el跟元素,它会首先转换成模板,经过html语法解析器生成一个ast抽象语法树,对语法树做优化,然后把语法树转换成代码片段,最后通过代码片段生成function添加到option的render字段中。

    ast语法优化过程,主要做了2件事:

        1.会检测出静态的class名和attributes,这样它们在初始化渲染后永远不会再被对比了。

        2.会检测出最大的静态子树,并且从渲染函数中萃取出来。这样在每次重渲染时,它们会直接重用相同的vnode,同时跳过比对。

creteelment方法的功能是给一个Vnode对象添加若干个Vnode,因为整个Vritual DOM是一种树状结构,每个节点都可能会有若干子节点。然后创建一个Vnode对象,如果是一个reserved tag(html,head等一些合法的html标签)则会创建普通的DOM Vnode,如果是一个component tag(通过vue注册的自定义component),则会创建Component Vnode对象,它的VnodeComponentOptions不为null。

function patch(oldVnode, vnode, hydrating, removeOnly, parentElm, refElm){

创建好Vnode,下一步就是要把虚拟dom渲染成真正的dom,是通过patch来实现。patch支持3个参数,其中oldNode是一个真实DOM或则一个Vnode对象,它表示当前的VNode,vnode是VNode对象类型,它表示待替换的VNode,hydration是bool类型,它表示是否直接使用服务器端渲染的DOM元素,下面流程图表示patch的运行逻辑:

vue学习笔记_第9张图片

patch运行逻辑看上去比较复杂,有2个方法createElm和patchVnode是生成dom的关键.

createElm方法会根据vnode的数据结构创建真实的DOM节点,如果vnode有children,则会遍历这些子节点,递归调用createElm方法,InsertedVnodeQueue是记录子节点创建顺序的队列,每创建一个DOM元素就会往这个队列中插入当前的VNode,当整个VNode对象全部转换成为真实的DOM树时,会依次调用这个队列中的VNode hook的insert方法

1.了解vue的$mount所作的工作大体分为3部:

    1.如果你的option里面没有render函数,那么,通过complieToFunctions将HTML模板编译成可以生成VNode的Render函数。

    2.new一个Watcher实例,触发updateComponent方法。

    3.生成vnode,经过path,把vnode更新到dom上。

vue学习笔记_第10张图片

从上面的代码中可以看到,首先判断option里面有没有render函数,没有的话,进一步判断有没有template,没有的话就用dom元素的outerHTML。得到template以后干了什么呢?如下图:

vue学习笔记_第11张图片

我们可以看到,调用了complieToFunction将template转成render函数。这里面有两个过程:

将template解析成ast语法树。

通过ast语法树生成render函数。

下一步就开始mountConmponet了。

vue学习笔记_第12张图片
vue学习笔记_第13张图片

从上图可以看出,程序声明了一个updateComponent 方法,这个是将要被Watcher实例调用的更新组件的方法。


vue学习笔记_第14张图片

vm:当前的vm实例。

updateComponent 这个非常重要,用来在后面将vnode更新到dom上。

noop无意义的函数。

null option选项没有则为null。

true主要是用来判断是哪个watcher。因为computed计算属性和如果你要在options里面配置watch了同样也是使用了 new Watcher ,加上这个用以区别这三者。

if(isRenderWatcher) {

     vm._watcher = this;

}

可以看到,如果声明这个watcher的上下文是用来渲染视图的,也就是说在mountComponent这里调用new Watcher的时候,才会把this赋值给_watcher。然后把 watcher push到 _watchers 里面,目的是等到组件销毁时顺便把watcher也销毁掉。

接下来,就是赋值给 getter , this.getter = expOrFn 。还记得刚才传过来的 updateComponent 函数么,没错,就是这个赋值给我 getter 。然后我们就到了:

vue学习笔记_第15张图片

我们可以看到,首先它执行的是 pushTarget(this) ,pushTarget(this) 代码如下:

vue学习笔记_第16张图片

也就是说如果当前有 Dep.target 的话,就把target放到 targetStack 里面,如果没有的话,就设为当前的target,也就是这个watcher。 接着,就是执行了它的 getter 属性,也就是刚刚传入 updateComponent 函数。


官方vue生命周期图:

vue学习笔记_第17张图片

从图可以看出在vue整个的生命周期中会有很多的钩子函数,提供给我们在vue生命周期不同的时刻进行操作。没一个组件或则实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。

    1.实例、组件通过new Vue()创建出来之后会初始化事件和生命周期,然后会执行beforeCreted钩子函数,这个时候数据还没有挂载,只是一个空壳,无法访问到数据和真实的dom,一般不做操作。

    2.挂载数据,绑定事件等等,然后执行creted函数,这个时候已经可以只用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其它钩子函数,一般可以在这里做初始数据的获取。

    3.接下来开始找实例或则组建对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会。

    4.接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom。

    5.当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制就会重新构建虚拟dom树利用diff算法进行对比后重新渲染。

    6.当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的虚拟dom。

    7.当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等

    8.组件的数据绑定、监听...去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以

先列出所有的钩子函数,再一一详解:

    *beforeCreate

    *created

    *beforeMount

    *mounted

    *beforeUpdate

    *updated

    *beforeDsetroy

    *destroyed

你可能感兴趣的:(vue学习笔记)