You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在VueJS应用中添加全局状态实现初始化加载屏的开发问题

实现步骤

1. 修正枚举定义

原枚举缺少INIT状态,补全后代码如下:

// enums.js
export default {
  INIT: -1,
  LOADING: 0,
  LOADED: 1
};

2. 完善Vuex相关逻辑

2.1 修正auth模块请求返回

auth.js中getUserData方法当前没有返回Promise,导致无法判断请求完成状态,修改为:

// auth.js 对应actions内的getUserData
getUserData ({ commit }) {
  return axios
    .get('user')
    .then(response => {
      commit('setUserData', response.data)
    })
    .catch(() => {
      localStorage.removeItem('authToken')
    })
},

2.2 新增全局初始化Action

修改store/index.js,新增全局初始化逻辑、补充对应getter:

// store/index.js 完整修改后代码
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './auth'
import appdata from './appData.js'
import ENUM from '../enums';

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    backEndErrors: [],
    apiState: ENUM.INIT
  },

  getters: {
    backEndErrors: state => state.backEndErrors,
    apiState: state => state.apiState,
    // 直接对外暴露加载完成状态,方便组件调用
    isAppLoaded: state => state.apiState === ENUM.LOADED
  },

  mutations: {
    setErrors (state, errors) {
      state.backEndErrors = errors
    },
    setApiState (state, apiState) {
      state.apiState = apiState;
    },
  },

  actions: {
    // 全局初始化Action,统一处理所有启动请求
    async initApp({ commit, dispatch }) {
      commit('setApiState', ENUM.LOADING)
      const initRequests = []
      // 有登录凭证的情况下才请求用户信息
      if (localStorage.getItem('authToken')) {
        initRequests.push(dispatch('auth/getUserData'))
      }
      // 全局基础数据请求
      initRequests.push(dispatch('appdata/getStatusesData'))
      // 等待所有请求完成(成功/失败都算完成,避免某个请求失败导致卡加载)
      await Promise.allSettled(initRequests)
      commit('setApiState', ENUM.LOADED)
    }
  },

  modules: {
    auth: auth,
    appdata: appdata
  }
})

3. 修改App.vue逻辑

3.1 模板新增加载屏

修改template部分,添加加载屏判断,只有初始化完成后才显示主应用内容:

<template>
  <div id="app">
    <!-- 加载屏 -->
    <div v-if="!isAppLoaded" class="loading-wrapper">
      <div class="spinning-loader"></div>
    </div>
    <!-- 主应用内容 -->
    <template v-else>
      <Sidebar
      v-if="isLogged"
      :class="{ 'show-sidebar': !isSmallSideBar, 'sidebar-hidden' : !isLogged }"
      @sideBarGrow="isSmallSideBar = false"
      @sideBarShrink="isSmallSideBar = true"
      @logout="logout"
      />
      <DynamicHeader
      :class="{ 'margin-header' : !isSmallSideBar }"
      @toogleSideBar="isSmallSideBar = !isSmallSideBar"
      />
      <div class="content" :class="{ 'margin-content' : !isSmallSideBar }">
          <router-view></router-view>
      </div>
    </template>
  </div>
</template>

3.2 调整生命周期逻辑

修改script部分,移除mounted中原有的分散请求,替换为调用全局初始化Action,补充状态映射:

<script>
import { mapGetters, mapActions } from 'vuex'
import Sidebar from './components/partials/Sidebar/Sidebar.vue'
import DynamicHeader from './components/partials/header/DynamicHeader.vue'

export default {
  data: function () {
    return {
      isSmallSideBar: true
    }
  },

  components: {
    Sidebar,
    DynamicHeader
  },

  async mounted () {
    // 执行全局初始化
    await this.initApp()
    // 初始化完成后如果未登录,跳转到登录页
    if (!this.isLogged) {
      this.$router.push('/login').catch()
    }
  },

  computed: {
    ...mapGetters(['isAppLoaded']),
    ...mapGetters('auth', ['user', 'isLogged']),
    ...mapGetters('appdata', ['statuses'])
  },

  methods: {
    ...mapActions(['initApp']),
    ...mapActions('auth', ['sendLogoutRequest', 'getUserData']),
    ...mapActions('appdata', ['getStatusesData']),
    logout () {
      this.sendLogoutRequest().then(() => {
        this.$router.push('/login').catch()
      })
    },
  }
}
</script>

3.3 补充加载屏样式

在style部分新增加载屏容器样式,实现全屏居中效果:

<style>
/* 原有样式保留,新增以下代码 */
.loading-wrapper {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #ffffff;
}
/* 原有样式保留 */
</style>

内容的提问来源于stack exchange,提问作者Kaloyan Nikolov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 08:57:03