показывать загрузчик до тех пор, пока не будут отображены все дочерние компоненты внутри страницы - Nativescript - PullRequest
1 голос
/ 08 апреля 2019

Я пытаюсь показать индикатор активности при переходе с одной страницы на другую. Целевая страница содержит много компонентов, и для ее загрузки требуется время. вот почему мне нужен какой-то способ прослушивания, когда все дочерние компоненты загружены, и в этот момент говорят, что моя переменная 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, затем я включаю или выключаю переменную в состоянии, и она работает. но я не могу воспроизвести это поведение при навигации между страницами и прослушать, чтобы загрузить все компоненты

EDIT

Наконец-то я добился желаемого поведения с помощью небольшого трюка, найденного в интернете

  mounted() {
    setTimeout(() => {
      this.isBussy = false
    }, 500)
  },

это приводит к тому, что рендеринг всех дочерних компонентов задерживается лишь немного, так что индикатор активности отображается, но не слишком сильно, чтобы не было обнаружено, что ни один из компонентов, содержащихся в блоке else, обнаружен и начинает рендеринг

1 Ответ

2 голосов
/ 08 апреля 2019

Я думаю, здесь есть две основные идеи, которые нужно понять.Я опишу оба.

1.Общий метод извлечения данных без блокирования рендеринга

Похоже, вы понимаете эту концепцию на уровне родительских компонентов, но затем спрашиваете, как сделать нечто очень похожее для дочерних компонентов, содержащихся на этой странице.

То, как я справляюсь с этим, находится в моем компоненте, мои данные по умолчанию находятся в состоянии isLoading.Затем в beforeMount() или mounted() я выполняю свои асинхронные действия и вносю необходимые изменения в данные своей страницы.

Проблема становится полностью рекурсивной, когда мы смотрим на дочерние компоненты.Вы хотите убедиться, что ваши дочерние компоненты выполняют рендеринг, и что любая длительная выборка данных, которая должна происходить в их реализации, просто заставит их повторно выполнить рендеринг после завершения выборки.

Вотрабочий пример: https://codesandbox.io/embed/r4o56o3olp В этом примере используется Nuxt.Помимо методов fetch () и asyncData (), остальные хуки жизненного цикла Vue здесь одинаковые.

Я использую new Promise и setTimeout, чтобы продемонстрировать операцию, которая будет использовать обещания и бытьасинхронный.(например, axios.get(..))

Страница About загружается, а хук жизненного цикла beforeMount() выполняет асинхронную выборку так, чтобы не блокировать отображение страницы.

Я используюbeforeMount() ловушка, потому что, согласно (1028 *https://alligator.io/vuejs/component-lifecycle/), это первая ловушка жизненного цикла, к которой мы имеем доступ, как только данные страницы реагируют.(Таким образом, изменение this.myDataProp вызовет повторную визуализацию, если в шаблоне будет использоваться {{ myDataProp }}).

Я также включил дочерний компонент, где я намеренно заставил его данные загружаться в два раза дольше.Поскольку я снова позволяю компоненту визуализироваться немедленно, а , а затем Я занимаюсь извлечением / обновлением данных в соответствующем хуке жизненного цикла, я могу управлять, когда конечный пользователь воспринимает страницу для загрузки.

В моем рабочем примере LongLoadingComponent выполнял ту же самую технику, что и страница About.

Как только вы увидите, как использовать beforeMount() или mounted() для извлечения данных, а затем для обновления состояния,Я думаю, хитрость заключается в том, чтобы занять мгновение и по-настоящему задуматься о состоянии по умолчанию вашего компонента.Когда он впервые рендерится, что должен увидеть пользователь перед завершением каких-либо операций извлечения данных / выполнения длительных операций?

Как только вы определите, как должен выглядеть компонент по умолчанию (еще не загруженный), попробуйте получить его ввизуализируйте на экране и добавьте в логику, которая выбирает и обновляет данные о состоянии.

2.Прослушивание, когда дочерний компонент заканчивает рендеринг из родительского компонента

. В нем используется описанная выше методика, но при этом используется ловушка updated() и отправляется пользовательское событие (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, если дочерний элемент завершил загрузка данных / обновление.)

3.Другие предупреждения об универсальных приложениях nuxt

Только после того, как я написал этот ответ, я понял, что вы не используете Nuxt.Однако я добавляю это в случае, если другие пользователи Nuxt сталкиваются с этим.

Я добавляю этот раздел только потому, что мне понадобилось некоторое время для того, чтобы обернуть голову.Универсальное приложение Nuxt выполняет рендеринг как на стороне сервера, так и на стороне клиента.Поначалу мне было немного трудно понять, когда что-то отображается на клиенте, а не на сервере.В рабочем примере, на который я ссылался выше, когда вы посещаете страницу о программе, вы также можете увидеть, был ли этот компонент извлечен с сервера или он только что был обработан клиентом.

Я бы порекомендовал поиграть со страницами.методы fetch () и asyncData () и посмотрите, как они влияют на отображение определенных вещей на вашем экране.(https://nuxtjs.org/api/pages-fetch/) (https://nuxtjs.org/api/).Просмотр того, для чего эти методы полезны, помогает мне также определить, для чего они not .

Если вы используете магазин Vuex, я бы порекомендовал посмотретьчто происходит, когда вы обновляете страницу или используете вместо нее навигацию между страницами.(Видеть что-то похожее на диаграмму схемы SSR может быть полезно здесь: https://nuxtjs.org/guide#schema)

.. Мне еще предстоит полностью оценить детали поведения комплектации и доставки, которое Webpack предоставляет для приложения Universal Nuxt(Смотрите правую часть схемы здесь: https://medium.freecodecamp.org/universal-application-code-structure-in-nuxt-js-4cd014cc0baa)

...