在 vue.js 中渲染子组件之前等到父组件安装/准备好
Posted
技术标签:
【中文标题】在 vue.js 中渲染子组件之前等到父组件安装/准备好【英文标题】:Wait until parent component is mounted / ready before rendering child in vue.js 【发布时间】:2018-07-23 19:53:38 【问题描述】:在我的 SPA 应用程序中,我有一个 <app-view>
包装器,它处理基本应用程序代码(加载用户数据、渲染导航栏和页脚等),并有一个 slot
用于渲染实际页面。此仅当用户数据可用时才会呈现此槽。
创建此包装器是因为某些页面需要不同的基本代码,因此我无法再将此基本代码保留在包含 <router-view>
的主应用程序中。
我尝试查看 vue-router 是否提供高级选项或建议用于切换基本代码的设计模式,但没有找到任何东西。
问题是子组件会在父组件挂载之前渲染,即在父组件决定不渲染子组件之前(因为它正在加载用户数据)。这会导致像undefined as no attribute foo
这样的错误。
正因为如此,我正在寻找一种方法来推迟子渲染,直到它的父被挂载。
【问题讨论】:
你试过v-cloak
吗?
不,但不只是为了在 vue 准备好之前隐藏 html 模板吗?我使用的是 vue 模板,而不是 html。
我没有尝试将v-if
放入<slot>
标记中。我想知道...?
【参考方案1】:
我遇到了类似的问题,但不是 SPA。我有需要来自父级的数据的子组件。问题是只有在父级完成安装后才会生成数据,所以我最终在子级中得到了空值。
我就是这样解决的。我仅在父级完成安装后才使用v-if
指令安装子级。 (在mounted()
方法中)见下面的例子
<template>
<child-component v-if="isMounted"></child-component>
</template>
<script>
data()
isMounted: false
, mounted()
this.isMounted = true
</script>
之后,孩子可以从父母那里获取数据。 这有点无关,但我希望它能给你一个想法。
【讨论】:
【参考方案2】:对于想要在父组件从 API 调用中获取数据后立即显示子组件的任何人,您应该使用以下内容:
<template>
<child-component v-if="itemsLoaded"></child-component>
</template>
<script>
data()
itemsLoaded: false
,
methods:
getData()
this.$axios
.get('/path/to/endpoint')
.then((data) =>
// do whatever you need to do with received data
// change the bool value here
this.itemsLoaded = true
)
.catch((err) =>
console.log(err)
)
,
,
mounted()
this.getData()
// DONT change the bool value here; papa no kiss
this.itemsLoaded = true
</script>
如果你尝试改变mounted()
方法中的布尔值this.itemsLoaded = true
,在调用getData()
方法之后,你会得到不一致的结果,因为你可能会也可能不会收到this.itemsLoaded = true
之前的数据执行。
【讨论】:
另外,mounted()
方法可以设为异步 (async mounted()
),以便您可以 await this.getData()
并以您警告的方式设置 this.itemsLoaded = true
。【参考方案3】:
您实际上可以将v-if
放在组件中的<slot>
标记上。
new Vue(
el: '#app',
render: function(createElement)
return createElement(
// Your application spec here
template: `<slotty :show="showSlot"><span> here</span></slotty>`,
data()
return
showSlot: false
,
components:
slotty:
template: `<div>Hiding slot<slot v-if="show"></slot>.</div>`,
props: ['show']
,
mounted()
setTimeout(() => this.showSlot = true, 1500);
);
)
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
</div>
【讨论】:
这在我的情况下不起作用,因为即使我不渲染插槽(例如,我在“加载”v-if 分支中,并且插槽位于不同的分支)【参考方案4】:在尝试了几个选项之后,看来我需要硬着头皮明确定义我的组件所依赖的数据,如下所示:
<app-view>
<div v-if='currentProfile'>
...
</div>
</div>
(currentProfile
是从 vuex store getter 接收的,并在 app-view
内获取)
【讨论】:
以上是关于在 vue.js 中渲染子组件之前等到父组件安装/准备好的主要内容,如果未能解决你的问题,请参考以下文章