为啥子组件的挂载钩子刚刚触发时,我们可以获取父组件的整个DOM?

Posted

技术标签:

【中文标题】为啥子组件的挂载钩子刚刚触发时,我们可以获取父组件的整个DOM?【英文标题】:Why we can get the whole DOM of parent component when child component's mounted hook is just triggered?为什么子组件的挂载钩子刚刚触发时,我们可以获取父组件的整个DOM? 【发布时间】:2021-02-19 12:52:27 【问题描述】:

前几天刚开始学习vue,前几天一个问题把我搞糊涂了。如下代码:

// inside the parent.vue
<div>
    <child-component-a />
    <child-component-a />
    <div>hello</div>
</div>
...
// inside the child-component-a.vue
<div>child a</div>
...
// inside the child-component-b.vue
<div>child b</div>
...

在我看来,当子组件的mounted钩子被触发时,dom应该不可用,以下是我的想法:

// inside the child-component-a.vue
export default 
    ...,
    mounted() 
        // here the DOM is "<div><div>child a</div></div>"
        // and not inserted into document yet 
    

// inside the child-component-b.vue
export default 
    ...,
    mounted() 
        // here the DOM is "<div><div>child a</div><div>child-b</div></div>"
        // and also not inserted
    

// inside the parent.vue
export default 
    ...,
    mounted() 
        // here the DOM is "<div><div>child a</div><div>child b</div><div>hello</div></div>"
        // and the whole dom has been inserted into document
        // so we can manipulate the html element with document APIs
    

但是,实际上我们可以在 child-a 的挂载钩子被触发时,通过文档 API 获取整个 DOM,为什么?

【问题讨论】:

【参考方案1】:

Vue.js 在将其插入 HTML 之前同步构建其虚拟 DOM。为了构建一个元素,它还需要构建子元素。它以预先订购、深度优先的方式执行此操作,这与浏览器构建普通 HTML 的方式非常相似(请参阅https://dom.spec.whatwg.org#trees)。即,为了显示***div,首先需要知道child-component-achild-component-b 是什么。这是渲染顺序:

    div 我们看到一个有子元素的 div 组件。我们需要先渲染它们,这样我们才能知道如何在屏幕上绘制这个元素。 a 没有要渲染的子组件,所以我们渲染 a 元素。 b 没有孩子,所以我们渲染 b。 (注意a 已经被渲染) div ("hello") 没有子节点,所以我们渲染它的内容(ab 都被渲染了) div(***)现在所有子组件都已渲染,我们知道如何绘制它们,我们可以渲染父节点。 [ Vues.js:将此树与现有 DOM 进行比较,只更新需要它的元素。 ]

注意:这稍微简化了。文本内容为text 节点,并相应地呈现。

就个人而言,我认为如果您要使用像 Vue 这样的工具包,您应该尽可能利用它的 API,而不是在不需要时尝试使用低级 API。老实说,我不明白为什么你需要在任何实际场景中使用它,而不仅仅是探索 Vue 的工作原理。如果你正在探索,向你致敬! Vue's API documentation 和 Guide 非常冗长,我建议您坐下来完整阅读它们。对于您遇到的问题,W3C standards documentation(especially on the DOM 和WhatWG)也非常棒,尽管它更具技术性。您不必记住其中的所有信息,只需阅读它,我相信它会在您需要时回来。

【讨论】:

我想可能我表达的不是很清楚,我想知道mounted钩子到底是什么时候触发的?我认为整个虚拟DOM应该在浏览器渲染之前生成,并且当渲染开始时,父容器div将首先在浏览器中渲染,然后将每个child组件的html插入到容器div一个接一个,所以当child-amounted钩子被触发时,浏览器中的html应该是&lt;div&gt;&lt;div&gt;child a&lt;/div&gt;&lt;/div&gt;...然后child-b...,当所有@987654352 @ 渲染,parentmounted 钩子被触发。 我不认为 vue 是这样渲染的。文档中有一个生命周期图:v3.vuejs.org/guide/instance.html#lifecycle-diagram 如果您正在寻找它。如果你问为什么本地上下文与渲染上下文不同,你应该阅读虚拟 DOM。这里有一个很好的深潜:medium.com/@koheimikami/…

以上是关于为啥子组件的挂载钩子刚刚触发时,我们可以获取父组件的整个DOM?的主要内容,如果未能解决你的问题,请参考以下文章

为啥子组件在 React 中没有通过 Axios 获得父组件的 props

vue父组件与子组件生命周期钩子顺序是啥?

Vue 的父组件和子组件生命周期钩子执行顺序

Vue 的父组件和子组件生命周期钩子执行顺序

父组件监听子组件的生命周期

有条件地渲染同一个组件不会触发挂载()钩子。