如何在初始 vue.js / vue-router 加载时加载所有服务器端数据?

IT技术 javascript jquery ajax wordpress vue.js
2021-02-22 19:49:16

我目前正在使用 WordPress REST API 和 vue-router 在一个小的单页面站点上的页面之间进行转换。但是,当我使用 REST API 对服务器进行 AJAX 调用时,数据会加载,但仅在页面已呈现之后。

VUE路由器文档提供了深入了解在关于如何前和导航到各航线后加载数据,但我想知道如何加载在初始页面加载的所有路线和页面数据,绕过需要每个负载数据激活路由的时间。

请注意,我将数据加载到acf属性中,然后.vue使用this.$parent.acfs.

main.js 路由器代码:

const router = new VueRouter({
    routes: [
        { path: '/', component: Home },
        { path: '/about', component: About },
        { path: '/tickets', component: Tickets },
        { path: '/sponsors', component: Sponsors },
    ],
    hashbang: false
});

exports.router = router;

const app = new Vue({
    router,
    data: {
        acfs: ''
    },
    created() {
        $.ajax({
            url: 'http://localhost/placeholder/wp-json/acf/v2/page/2',
            type: 'GET',
            success: function(response) {
                console.log(response);
                this.acfs = response.acf;
                // this.backgroundImage = response.acf.background_image.url
            }.bind(this)
        })
    }
}).$mount('#app')

Home.vue 组件代码:

export default {
    name: 'about',
    data () {
        return {
            acf: this.$parent.acfs,
        } 
    },
}

有任何想法吗?

5个回答

我的方法是延迟 store 和 main Vue 的构建,直到我的 AJAX 调用返回。

商店.js

import Vue from 'vue';
import Vuex from 'vuex';
import actions from './actions';
import getters from './getters';
import mutations from './mutations';

Vue.use(Vuex);

function builder(data) {
  return new Vuex.Store({
    state: {
      exams: data,
    },
    actions,
    getters,
    mutations,
  });
}

export default builder;

主文件

import Vue from 'vue';
import VueResource from 'vue-resource';
import App from './App';
import router from './router';
import store from './store';

Vue.config.productionTip = false;

Vue.use(VueResource);

Vue.http.options.root = 'https://miguelmartinez.com/api/';

Vue.http.get('data')
  .then(response => response.json())
  .then((data) => {
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      store: store(data),
      template: '<App/>',
      components: { App },
    });
  });

我已经将这种方法用于其他框架,例如 Angular 和 ExtJS。

太棒了 - 谢谢你。我在 12 小时内学会了 Webpack/Vue/vue-cli,但三天无法理解 Vuex 并正常工作。直到这个。很好的答案@Miguel
2021-04-24 19:49:16
好的!我也这样做了...我在这里只是因为我不确定这是否是好的做法,但很高兴看到其他人认为这是一个好主意。
2021-05-01 19:49:16
如果您不想创建store构建器,则可以store.commit('set_exams', data)在 ajax Promise解决后调用这假设你有一个相关的突变来做到这一点。
2021-05-07 19:49:16
@NtwariClaranceLiberiste 您可以fetch()在浏览器中使用或导入类似 Axios 的东西来进行 API 调用,而不是Vue.http()
2021-05-11 19:49:16
这很聪明。
2021-05-20 19:49:16

您可以使用导航守卫

在特定组件上,它看起来像这样:

export default {
    beforeRouteEnter (to, from, next) {
        // my ajax call
    }
};

您还可以为所有组件添加导航守卫:

router.beforeEach((to, from, next) => {
    // my ajax call
});

要记住的一件事是导航守卫是异步的,因此您需要next()在数据加载完成后调用回调。我的应用程序中的一个真实示例(其中保护功能驻留在单独的文件中):

export default function(to, from, next) {
    Promise.all([
        IngredientTypes.init(),
        Units.init(),
        MashTypes.init()
    ]).then(() => {
        next();
    });
};

在你的情况,你需要调用next()success回调,当然。

友好警告;这变得非常混乱,非常快
2021-04-23 19:49:16
@ZacJacob ...希望我在两年前看到你的警告,因为你是对的。搞得一团糟
2021-04-26 19:49:16
因此,如果我正在使用router.beforeEach(),我应该在哪里存储我的 AJAX 响应数据?是否有我应该将其存储的路径对象$route.params
2021-05-03 19:49:16
我为此使用服务类(IngredientTypes等)。它们存储数据,任何组件都可以使用它们。当他们已经存储了数据时,他们不会发送另一个请求,而是立即返回一个已解决的Promise。我也知道有一个叫做 vuex 的状态管理工具,理论上它也可以帮助你实现你想要的,但我没有使用它,所以我不能提供任何关于它的可靠信息。
2021-05-11 19:49:16
另外,有没有办法确保数据只加载一次,而不是在页面之间来回切换时多次加载?
2021-05-16 19:49:16

好吧,我终于想通了这件事。我所做的只是在我的main.js文件中调用同步 ajax 请求,在其中实例化我的根 vue 实例,并为请求的数据分配一个数据属性,如下所示:

主文件

let acfData;

$.ajax({
    async: false,
    url: 'http://localhost/placeholder/wp-json/acf/v2/page/2',
    type: 'GET',
    success: function(response) {
        console.log(response.acf);
        acfData = response.acf;
    }.bind(this)
})  

const router = new VueRouter({
    routes: [
        { path: '/', component: Home },
        { path: '/about', component: About },
        { path: '/tickets', component: Tickets },
        { path: '/sponsors', component: Sponsors },
    ],
    hashbang: false
});

exports.router = router;

const app = new Vue({
    router,
    data: {
        acfs: acfData 
    },
    created() {

    }
}).$mount('#app')

从这里,我可以在每个单独的.vue文件/组件中使用提取的数据,如下所示:

export default {
    name: 'app',
    data () {
    return {
        acf: this.$parent.acfs,
    }
},

最后,我.vue使用以下内容在同一模板中呈现数据

<template>
  <transition
      name="home"
      v-on:enter="enter"
      v-on:leave="leave"
      v-bind:css="false"
      mode="out-in"
    >
    <div class="full-height-container background-image home" v-bind:style="{backgroundImage: 'url(' + this.acf.home_background_image.url + ')'}">
      <div class="content-container">
        <h1 class="white bold home-title">{{ acf.home_title }}</h1>
        <h2 class="white home-subtitle">{{ acf.home_subtitle }}</h2>
        <div class="button-block">
          <a href="#/about"><button class="white home-button-1">{{ acf.link_title_1 }}</button></a>
          <a href="#/tickets"><button class="white home-button-2">{{ acf.link_title_2 }}</button></a>
        </div>
      </div>
    </div>
  </transition>
</template>

要带走的最重要的信息是所有 ACF 数据在一开始只被调用一次,而每次使用类似的东西访问路线时都只调用一次beforeRouteEnter (to, from, next)结果,我能够根据需要获得如丝般平滑的页面过渡。

希望这可以帮助遇到同样问题的人。

在 Vue Router 的文档中查看此部分

https://router.vuejs.org/guide/advanced/data-fetching.html

所以首先你必须编写从端点获取数据的方法,然后使用观察者来观察路由。

export default {
    watch: {
        '$route': 'fetchItems'
    },
    methods: {
        fetchItems() {
          // fetch logic
        }
    }
}

由于您正在使用 WP Rest API,请随时查看我在 Github 上的 repo https://github.com/bedakb/vuewp/blob/master/public/app/themes/vuewp/app/views/PostView.vue#L39

我根据对这篇文章的所有精彩回应组成了我自己的版本......几年过去了,也给了我更多的工具。

main.js 中,我使用 async/await 调用预取服务来加载启动时必须存在的任何数据。我发现这增加了可读性。获得数据comms 后,我将其分派到 beforeCreate() 钩子中的适当 vuex 存储module。

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

import { prefetchAppData } from '@/services/prefetch.service';

(async () => {
    let comms = await prefetchAppData();

    new Vue({
        router,
        store,
        beforeCreate() {
            store.dispatch('communityModule/initialize', comms);
        },
        mounted() {},
        render: h => h(App)
    }).$mount('#app');
})();

我觉得有必要警告那些人要小心你预取的东西。尽量谨慎地执行此操作,因为它确实会延迟初始应用程序加载,这对于良好的用户体验而言并不理想。

这是我执行数据加载的示例prefetch.service.js这当然可以更复杂。

import api from '@api/community.api';
export async function prefetchAppData() {
    return await api.getCommunities();
}

一个简单的vue商店。此商店维护应用程序启动前需要加载的“社区”列表。

community.store.js(注意我使用 vuex module)

export const communityModule = {
    namespaced: true,
    state: {
        communities: []
    },
    getters: {
        communities(state) {
            return state.communities;
        },
    },
    mutations: {
        SET_COMMUNITIES(state, communities) {
            state.communities = communities;
        }
    },
    actions: {
        // instead of loading data here, it is passed in 
        initialize({ commit }, comms) {
            commit('SET_COMMUNITIES', comms);
        }
    }
};