用 Vue 已经有几年了,使用上大概是人们口中所说的老司机了吧,熟知 Vue 生态,用来开发了十来个项目,也可谓是驾轻熟路了吧。遇到问题也会通过 debug 找到问题出处,不明白的回去翻翻源码相应的位置。不过还是有很多地方是我不知道的,更确切的说是自己只是把他当做工具,能用就行,从来没有想过这个工具为什么这么设计,对于开发有什么借鉴意义,我想这也是大部分人的做法吧。

但是,作为一个想要更深入 Vue 的开发人员,可能多问问为什么也是有百利而无一害的,就是查资料搞明白需要费些时间。下面我将记录一些对 Vue 的思考以及自己的理解。

组件的 data 为什么用函数形式返回呢?

Vue api 文档是这么解释的

当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

data 会被代理到实例的根节点下,当有多个组件实例时,原型链上的数据会被共享,data 用函数形式返回可以解决这个问题。此外,data 使用函数形式还可以方便对数据进行一些操作,解决引用执行上下文的问题。

Vue 的通讯方式有哪几种

父子组件通讯方式

讲到通讯方式,我一般想到的是父子组件之间的通讯方式,父组件向子组件传值用 props,子组件向父组件传值用实例的 $emit 方法。

比较直接粗暴的方式,可以调用实例的属性 $parent 和 $children 做父子组件间的通讯。

在组件库中可能还会看到使用 provide/inject 进行通讯,由父组件向子组件注入数据,子组件进行消费。

不相邻组件间通讯方式

讲到不相邻组件的通讯方式,我首先想到的就是常用的 vuex,不过通常我管这个叫做全局状态管理,因为这里面的数据是在全局更新和设置的,一般用于存放一些组件的状态数据,供其他组件消费。

类似于 vuex 的另一个方法是 eventBus,创建一个事件中心,组件可以通过这个事件中心发布或者订阅其他组件的事件,以前 vue 文档记得有看到一些描述,最近打开没看到了。不过个人还是倾向于 vuex 的,比较好维护和管理。

使用 $attr/$listener 实现跨组件通讯,通常用于嵌套组件间的通讯,多个嵌套组件,底层组件需要跟上层组件通讯,可以用这个。这种通讯方式一般在高阶组件中使用,日常用的比较少。

生命周期钩子概述

beforeCreate

beforeCreate 发生在实例初始化之后,initState 之前,在这个阶段还没有 props、data、methods、watch、computed 等选项。

created

created 在实例创建完成后被立即调用,此时已经完成了 initState,但是还没有渲染 DOM,可以在这个阶段做一些数据的操作。

beforeMounte

在 Vnode 挂载之前执行

mounted

实例被挂载后调用,这个阶段可以做一些 DOM 的操作,父子组件的 mounted 调用过程是先子后父,所以这个阶段组件不能保证所有视图已经被渲染完了,有需要的话,可以在实例的 $nextTick 方法中做相应的操作。

beforeUpdate

这个钩子 api 文档是这么描述的

数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器

这个描述已经很清楚了,我就不做赘述了。

updated

虚拟 DOM 重新渲染和打补丁之后执行,父子组件的调用过程是先子后父,跟 mounted 一样,若想操作 DOM 可以在 $nextTick 中做相应的操作。

activated/deactivated

这两个钩子看 api 文档描述就好了,不做赘述

beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。

destroyed

发生在所有的实例被移除,包括子组件实例之后,移除过程是先子后父。

未完待续……

参考文档:

Vue api
Vue 技术揭秘