当我从一页转到另一页时,我正在尝试显示活动指示器。目标页面中包含许多组件,并且加载时间很长。这就是为什么当所有子组件都加载时,我需要某种方法来监听,然后告诉我的变量isBussy为false
<template>
<StackLayout>
<ActivityIndicator :busy="isBussy" v-if="isBussy" />
<StackLayout v-else>
<Component1 />
<Component2 />
<Component3 />
<Component4 />
</StackLayout>
<StackLayout>
</template>
<script>
import Component1 from '~/components/Component1'
import Component2 from '~/components/Component2'
import Component3 from '~/components/Component3'
import Component4 from '~/components/Component4'
export default {
data() {
return {
isBussy: true
}
},
mounted() {
this.$nextTick(function() {
// Code that will run only after the
// entire view has been re-rendered
this.isBussy = false
})
}
}
</script>
此代码不起作用,因为一旦从上一页用以下内容指示了导航:
@tap="$goto('otherPage', { props: { foo: bar } })"
它仍然停留在初始页面上,并且所有组件都开始在目标页面的后台加载,但是没有显示父页面,只有在整个过程结束时才更改为该页面,并且从不显示/隐藏活动指标符合预期。
通过这种期望的行为,当我确实使用Promises请求和处理它们时,它可以完美地工作,然后我打开或关闭状态中的变量,它就起作用了。但我无法在页面之间的导航中复制该行为并收听加载所有组件
最后,我通过在互联网上发现的一个小技巧实现了预期的行为
mounted() {
setTimeout(() => {
this.isBussy = false
}, 500)
},
这导致所有子组件的渲染仅延迟了一点,从而显示了活动指示器,但并不过分,以至于没有检测到else块中包含的任何组件并开始渲染< / p>
答案 0 :(得分:2)
我认为这里有两个主要的想法需要理解。我会同时描述。
听起来您在父级组件一级理解了这个概念,但随后又问如何对此页面包含的子级组件执行非常相似的操作。
我处理此问题的方式是在我的组件中,我的数据默认为isLoading状态。然后,在beforeMount()
或mounted()
中,我执行异步操作并对页面数据进行必要的更改。
当我们查看子组件时,该问题变得完全递归。您要确保子组件正在渲染,并且在实现中需要进行的任何长时间运行的数据提取都只会导致它们在完成提取后重新呈现。
这是一个有效的示例:https://codesandbox.io/embed/r4o56o3olp 本示例使用Nuxt。除了添加的fetch()和asyncData()方法之外,其余的Vue生命周期挂钩在这里都是相同的。
我使用new Promise
和setTimeout
来演示将使用Promise并且是异步的操作。 (例如axios.get(..)
)
加载“关于”页面,并且beforeMount()
生命周期挂钩以不阻止页面呈现的方式执行异步获取。
我使用beforeMount()
钩子是因为,根据这里(https://alligator.io/vuejs/component-lifecycle/),它是页面数据处于响应状态后我们可以访问的第一个生命周期钩子。 (因此,如果在模板中使用this.myDataProp
,则修改{{ myDataProp }}
会触发重新渲染。)
我还包括一个子组件,在该组件中,我故意使它的数据加载花费两倍的时间。再次让我立即使组件呈现,然后然后在适当的生命周期挂钩中处理数据的获取/更新,因此我可以管理最终用户何时感知到要加载的页面。 / p>
在我的工作示例中,LongLoadingComponent
的技术与“关于”页面完全相同。
一旦您了解了如何使用beforeMount()
或mounted()
来获取数据然后更新状态,我认为关键是花点时间仔细考虑组件的默认状态。首次渲染时,用户在完成任何数据获取/长时间运行操作之前应该看到什么?
确定了默认(尚未加载)组件的外观后,请尝试将其呈现在屏幕上,然后添加获取和更新状态数据的逻辑。
这利用了上面的技术,但是包括了updated()
钩子的使用并发出了 custom事件(https://vuejs.org/v2/guide/components-custom-events.html
)
如果您确实想在子组件完成渲染时收听 ,则可以在$emit
钩子中updated()
自定义事件。也许是这样的(在您的一个子组件中)
if (this.dataLoaded) { this.$emit('loadedAndRendered') }
因此,当子级的异步操作完成后,它可以将其dataLoaded
属性翻转为true。如果在孩子的dataLoaded
中某个地方使用了<template>
,则该组件应重新渲染(因为它是“完成”状态)。当孩子重新渲染时,updated()
挂钩应触发。 (再次参见:https://alligator.io/vuejs/component-lifecycle/)我包括了if (this.dataLoaded)
部分,只是为了处理在中间数据更新期间可能调用updated()
钩子的情况。 (我们仅想在子进程完成加载数据/更新时发出loadedAndRendered
事件。)
直到我写下此答案后,我才意识到您没有使用Nuxt。但是,我添加这个是为了防止其他Nuxt用户碰到这个问题。
我添加此部分的原因仅在于我花了一些专心动手的时间来回头。 Nuxt通用应用程序同时执行服务器端和客户端渲染。刚开始时,了解什么东西在客户端上渲染以及什么时候在服务器上渲染有点困难。在我上面链接的工作示例中,当您访问“关于”页面时,您还可以查看该组件是从服务器获取的还是由客户端提供的。
我建议您使用Page的fetch()和asyncData()方法,看看在屏幕上呈现某些内容时它如何影响。 (https://nuxtjs.org/api/pages-fetch/)(https://nuxtjs.org/api/)。看看这些方法 有什么用,有助于我也确定它们 没什么用。
如果您使用的是Vuex商店,我建议您查看刷新页面或使用而不是导航页面时会发生的情况。 (在此处查看类似SSR模式图的内容可能会有所帮助:https://nuxtjs.org/guide#schema)
..我尚未完全理解Webpack为Universal Nuxt应用程序提供的捆绑和交付行为的细节(请参见图的右侧:https://medium.freecodecamp.org/universal-application-code-structure-in-nuxt-js-4cd014cc0baa)