【问题标题】:Vue 3: Wait until parent is done with data fetching to fetch child data and show loaderVue 3:等到父级完成数据获取以获取子级数据并显示加载器
【发布时间】:2022-01-19 09:26:55
【问题描述】:

我正在寻找一种可重用的方式来显示整个页面加载器(侧边栏始终可见,但加载器应该覆盖页面的内容部分),直到完成所有必要的 api 获取。

我有一个父组件 LaunchDetails 包裹在一个 PageLoader 组件中

LaunchDetails.vue

<template>
  <PageLoader>
    <router-link :to="{ name: 'launches' }"> Back to launches </router-link>
    <h1>{{ name }}</h1>

    <section>
      <TabMenu :links="menuLinks" />
    </section>

    <section>
      <router-view />
    </section>
  </PageLoader>
</template>

<script>
import TabMenu from "@/components/general/TabMenu";

export default {
  data() {
    return {
      menuLinks: [
        { to: { name: "launchOverview" }, display_name: "Overview" },
        { to: { name: "launchRocket" }, display_name: "Rocket" },
      ],
    };
  },
  components: {
    TabMenu,
  },
  created() {
    this.$store.dispatch("launches/fetchLaunch", this.$route.params.launch_id);
  },
  computed: {
    name() {
      return this.$store.getters["launches/name"];
    },
  },
};
</script>

PageLoader.vue

<template>
  <Spinner v-if="isLoading" full size="medium" />
  <slot v-else></slot>
</template>

<script>
import Spinner from "@/components/general/Spinner.vue";

export default {
  components: {
    Spinner,
  },
  computed: {
    isLoading() {
      return this.$store.getters["loader/isLoading"];
    },
  },
};
</script>

LaunchDetails 模板有另一个路由器视图。在这些子页面中,新的提取请求是根据来自 LaunchDetails 请求的数据发出的。

RocketDetails.vue

<template>
  <PageLoader>
    <h2>Launch rocket details</h2>

    <RocketCard v-if="rocket" :rocket="rocket" />
  </PageLoader>
</template>

<script>
import LaunchService from "@/services/LaunchService";
import RocketCard from "@/components/rocket/RocketCard.vue";

export default {
  components: {
    RocketCard,
  },
  mounted() {
    this.loadRocket();
  },
  data() {
    return {
      rocket: null,
    };
  },
  methods: {
    async loadRocket() {
      const rocket_id = this.$store.getters["launches/getRocketId"];

      if (rocket_id) {
        const response = await LaunchService.getRocket(rocket_id);
        this.rocket = response.data;
      }
    },
  },
};
</script>

我需要的是一种在父组件 (LaunchDetails) 中获取数据的方法。如果此数据存储在 vuex 存储中,则子组件 (LaunchRocket) 将获取必要的存储数据并执行获取请求。完成此操作后,我希望在加载父组件时拥有一个完整页面加载器或一个完整页面加载器,以及一个包含嵌套画布的加载器。

此时 vuex 存储正在跟踪 isLoading 属性,由 axios 拦截器处理。

所有代码在这个sandbox中可见

(注意:在此示例中,我可以从 url 获取 rocket_id,但在我的项目中不会出现这种情况,所以我真的在寻找一种从 vuex 商店获取这些数据的方法)

【问题讨论】:

    标签: vue.js axios vuex vuejs3


    【解决方案1】:

    我介绍你的救星Suspense,这个功能已经在 vue v3 中添加,但仍然是一个实验性功能。基本上它是如何工作的,您在父组件中创建了一个悬念,并且当您的应用程序的任何深度中的所有组件都得到解决时,您可以显示加载。请注意,您的组件应该是异步组件意味着它应该延迟加载或使您的设置函数(组合 API)成为异步函数,因此它将返回一个异步组件,这样您就可以在子组件和父组件中获取数据必要时显示后备。

    更多信息:https://v3.vuejs.org/guide/migration/suspense.html#introduction

    【讨论】:

      【解决方案2】:

      您可以使用事件:

      var Child = Vue.component('child', {
        data() {
          return {
            isLoading: true
          }
        },
        template: `<div>
          <span v-if="isLoading">Loading &hellip;</span>
          <span v-else>Child</span>
        </div>`,
        created() {
          this.$parent.$on('loaded', this.setLoaded);
        },
        methods: {
          setLoaded() {
            this.isLoading = false
          }
        }
      });
      
      var Parent = Vue.component('parent', {
        components: { Child },
        data() {
          return {
            isLoading: true
          }
        },
        template: `<div>
          Parent
          <Child />
        </div>`,
        mounted() {
          let request1 = new Promise((resolve, reject) => {
            setTimeout(resolve, 1000);
          });
          let request2 = new Promise((resolve, reject) => {
            setTimeout(resolve, 2000);
          });
          Promise.all([ request1, request2 ]).then(() => this.$emit('loaded'))
        }
      });
      
      new Vue({
        components: { Parent },
        el: '#app',
        template: `<Parent />`
      });
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
      <div id="app"></div>

      这可能被认为是一种反模式,因为它将父与子耦合在一起,并且事件被视为以相反的方式发送。如果您不想为此使用事件,则监视属性也可以正常工作。 Vue 3 中删除了非父子事件发射,但 can be implemented using external libraries

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-20
        • 2021-07-19
        • 2020-09-24
        • 1970-01-01
        • 1970-01-01
        • 2021-09-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多