Vue渲染父子组件时需要注意的点

前言

我在边学 Vue 边做 轱辘UI 的项目中,写 row 组件测试用例时碰到了一个问题。
测试用例需要渲染两个组件,它们是父子关系,但测试下来子组件并没有拿到父组件的 gutter 属性,发现原来是因为 Vue 异步的渲染。
之后通过 setTimeoutdone() 解决了这一问题,之后便有了这篇博客。

分析

Vue到底是怎样渲染组件到页面的?看例子来分析吧

我们自己会怎么写:

1
2
3
// 这是个同步的过程
var div = document.createElement('div')
document.body.appendChild(div)

而 Vue 不是这么简单的:

1
2
3
4
5
6
7
8
var div = document.createElement('div')
var child = document.createElement('div')
// 步骤一,会触发child的mounted事件,这是异步的
div.appendChild(child)
// 步骤二,会触发div的mounted事件,这也是异步的
document.body.appendChild(div)
// 步骤三,这行代码会先于上面两行执行,因为这是同步的,而此时div里还没有child
console.log(div.outerHTML)

执行顺序:步骤三 → 步骤一 → 步骤二

Vue 钩子的调用并不是同步的。

假如是同步的,mounted你写了几百行代码,则需要大量的运算,那Vue岂不是要等你执行完再继续?
所以 Vue 不应该等,Vue 应该优先完成元素的渲染,这是一个异步的触发

解决

我预想子组件会通过 mounted 钩子拿到父组件传来的 gutter 属性,但我的测试用例执行时,实际上还没有执行 mounted 钩子,所以子组件才没有拿到这个 gutter 属性的值。

知道了原因,那么就好解决了,用 setTimeout(){}

另外由于测试框架默认都是同步的代码(这是测试框架的一个约定),所以要在参数中加上 done ,在我的测试用例执行完时调用 done()

这样,就解决了。具体代码可在此点击