显示加载微调器,直到页面内的所有子组件都已呈现 - Nativescript

Posted

技术标签:

【中文标题】显示加载微调器,直到页面内的所有子组件都已呈现 - Nativescript【英文标题】:show loading spinner until all child components inside of a Page have been rendered - Nativescript 【发布时间】:2019-08-29 02:15:24 【问题描述】:

当我从一个页面转到另一个页面时,我正在尝试显示一个活动指示器。目标页面中包含许多组件,加载需要时间。这就是为什么我需要一些方法来在所有子组件加载时进行监听,并且在那一刻告诉我的变量 isBussy 为假

<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 块中包含的组件并开始渲染

【问题讨论】:

很高兴你找到了适合你的东西!请注意,您似乎引入了 500 毫秒的加载时间(针对所有孩子)只是为了显示活动指示器 您可以删除 v-else 并让子组件开始加载,如果它们具有令人愉快的默认加载状态,并且您可以使用 setTimeout 解决方案保留您所拥有的内容。这不会增加子加载的延迟。此外,我不确定 *** 指南是什么,但您可能需要更新问题标题,因为您不是在寻找您要求的内容 【参考方案1】:

我认为这里有两个主要的想法需要理解。我会描述两者。

1。在不阻塞渲染的情况下获取数据的通用技术

听起来您在父组件级别了解此概念,但随后询问如何为该页面包含的子组件执行非常相似的操作。

我的处理方式是在我的组件中,我的数据默认为 isLoading 状态。然后,在beforeMount()mounted() 中,我执行异步操作并对我的页面数据进行必要的更改。

当我们查看子组件时,问题变得完全递归。您希望确保您的子组件正在渲染,并且需要在其实现中进行的任何长时间运行的数据提取只会导致它们在提取完成后重新渲染。

这是一个工作示例:https://codesandbox.io/embed/r4o56o3olp 此示例使用 Nuxt。除了 fetch() 和 asyncData() 方法之外,Vue 生命周期的其他钩子在这里都是一样的。

我使用new PromisesetTimeout 来演示一个使用promise 并且是异步的操作。 (例如axios.get(..)

“关于”页面加载,beforeMount() 生命周期挂钩以不会阻止页面呈现的方式执行异步获取。

我使用 beforeMount() 钩子是因为,根据这里 (https://alligator.io/vuejs/component-lifecycle/),一旦页面的数据是反应性的,它是我们可以访问的第一个生命周期钩子。 (所以如果模板中使用了 myDataProp ,那么修改this.myDataProp 会触发重新渲染)。

我还包括了一个子组件,我特意让它的数据加载时间增加了一倍。由于我再次让组件立即呈现,然后然后我在适当的生命周期挂钩中处理数据的获取/更新,我可以在最终用户感知到要加载的页面时进行管理。

在我的工作示例中,LongLoadingComponent 使用与“关于”页面完全相同的技术。

一旦您了解如何使用beforeMount()mounted() 获取数据然后更新状态,我认为诀窍是花点时间认真考虑一下组件的默认状态。当它首次渲染时,在它的任何数据获取/长时间运行的操作完成之前,用户应该看到什么?

确定默认(尚未加载)组件的外观后,尝试将其呈现在屏幕上,然后添加获取和更新状态数据的逻辑。

2。监听子组件何时从父组件完成渲染

这利用了上述技术,但包括使用 updated() 钩子并发出 自定义事件 (https://vuejs.org/v2/guide/components-custom-events.html )

如果您真的想收听您的子组件何时完成渲染,您可以在您的updated() 挂钩中$emit 自定义事件。也许是这样的(在您的子组件之一中)

if (this.dataLoaded)  this.$emit('loadedAndRendered') 

所以当孩子的异步操作完成后,它可以将其dataLoaded 属性翻转为true。如果dataLoaded 用于孩子的&lt;template&gt; 某处,那么组件应该重新渲染(因为它是“完成”状态)。当孩子重新渲染时,updated() 钩子应该触发。 (再次,请参阅:https://alligator.io/vuejs/component-lifecycle/)我包含if (this.dataLoaded) 部分只是为了处理在中间数据更新期间可能调用updated() 挂钩的情况。 (如果孩子完成加载数据/更新,我们只想发出loadedAndRendered事件。)

3。关于通用 nuxt 应用程序的其他注意事项

直到我写完这个答案后,我才意识到你没有使用 Nuxt。不过我会添加这个,以防其他 Nuxt 用户碰巧遇到这个。

我添加此部分只是因为我花了一些专注的动手时间来解决我的问题。 Nuxt 通用应用程序同时进行服务器端和客户端渲染。一开始我有点难以理解什么时候在客户端渲染什么时候在服务器上渲染。在我上面链接的工作示例中,当您访问 about 页面时,您还可以查看该组件是从服务器获取还是仅由客户端呈现。

我建议您使用 Page 的 fetch() 和 asyncData() 方法,看看当某些内容呈现在您的屏幕上时它会产生怎样的影响。 (https://nuxtjs.org/api/pages-fetch/) (https://nuxtjs.org/api/)。了解这些方法有什么用处可以帮助我确定它们没有有什么用处。

如果您使用的是 Vuex 商店,我建议您看看刷新页面或使用而不是 a 在页面之间导航时会发生什么。 (在这里查看类似 s-s-r 架构图的内容可能会有所帮助:https://nuxtjs.org/guide#schema)

..我还没有完全理解 Webpack 为 Universal Nuxt 应用程序提供的捆绑和交付行为的细节(请参见此处的图表右侧:https://medium.freecodecamp.org/universal-application-code-structure-in-nuxt-js-4cd014cc0baa)

【讨论】:

再补充一点,如果您正在寻找适用于 Vuex 商店的解决方案,这仍然有效。您可能会提交存储突变或调度存储操作,而不是修改本地组件状态。遵循相同的技术,只需从存储状态读取并通过 Vuex 突变进行任何数据更改。 感谢您的回复,但我认为它并不能完全解决我的问题。因为如果我有 20 个组件,我不想在每个组件中都定义“我准备好了”。我无法模拟加载带有承诺的组件,就好像它是一个请求一样。而且它是一个 Nativescript 应用程序其余的,我没有在我的问题中指定我不能使用 vue-router 来制作一个简单的 router.beforeEach () 因为它目前不受支持 我听到你的声音,只是好奇,为正在加载的子组件发出“imReady”事件或类似事件真的有那么糟糕吗?父级中只有一个侦听器计算事件(如果您正在跟踪,预计 20 个子组件的 20 个事件)。 其他选项是通过 $refs 访问数据,但我认为发出事件是做同样事情的推荐方式:访问子状态数据。至于您的页面渲染阻塞问题......您是否有机会尝试更多地解释您要完成的工作以及对您有用或没用的东西?我也许能够发现发生了什么

以上是关于显示加载微调器,直到页面内的所有子组件都已呈现 - Nativescript的主要内容,如果未能解决你的问题,请参考以下文章

使用微调器加载 jQuery 整个 HTML 页面

显示异步 Vue 2 组件的加载微调器

EmberJS View - 检测是不是所有子视图都已呈现

延迟 jquery 脚本,直到其他所有内容都已加载

在 jQuery Mobile 中的 Ajax 调用中显示页面加载微调器

如何检测到所有页面组件都已加载到 Oro 应用程序中?