MST

星途 面试题库

面试题:Vue中如何在网络请求时实现基础的全局加载动画

在Vue项目里,假设使用axios进行网络请求,阐述如何实现一个简单的全局加载动画,即当有网络请求发起时显示加载动画,请求结束后隐藏。请说明实现思路并给出关键代码示例。
16.8万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 创建加载动画组件:在Vue组件中创建一个加载动画的组件,比如使用CSS动画或SVG来展示加载效果。
  2. Axios拦截器:利用Axios的请求拦截器和响应拦截器。请求拦截器在请求发起时触发,设置加载动画显示的状态;响应拦截器在请求结束(无论成功或失败)时触发,设置加载动画隐藏的状态。
  3. Vuex状态管理(可选但推荐):如果项目较为复杂,可以使用Vuex来管理加载动画的显示和隐藏状态,便于在不同组件中共享和使用该状态。

关键代码示例

  1. 创建加载动画组件 Loading.vue
<template>
  <div v-if="isLoading" class="loading-container">
    <div class="loading-spinner"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isLoading: false
    };
  }
};
</script>

<style scoped>
.loading-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 9999;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid rgba(0, 123, 255, 0.6);
  border-top-color: #007bff;
  border-radius: 50%;
  animation: spin 1s ease-in-out infinite;
  -webkit-animation: spin 1s ease-in-out infinite;
}

@keyframes spin {
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
</style>
  1. main.js 中配置Axios拦截器
import Vue from 'vue';
import axios from 'axios';
import Loading from './components/Loading.vue';

// 创建Vue实例用于访问Vuex等
const app = new Vue();

axios.interceptors.request.use(config => {
  app.$root.$emit('showLoading');
  return config;
}, error => {
  app.$root.$emit('hideLoading');
  return Promise.reject(error);
});

axios.interceptors.response.use(response => {
  app.$root.$emit('hideLoading');
  return response;
}, error => {
  app.$root.$emit('hideLoading');
  return Promise.reject(error);
});

// 在Vue根实例中监听事件来控制加载动画
Vue.prototype.$on('showLoading', () => {
  Loading.isLoading = true;
});

Vue.prototype.$on('hideLoading', () => {
  Loading.isLoading = false;
});
  1. App.vue 中引入加载动画组件
<template>
  <div id="app">
    <Loading />
    <!-- 其他组件内容 -->
  </div>
</template>

<script>
import Loading from './components/Loading.vue';

export default {
  components: {
    Loading
  }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

如果使用Vuex,实现会略有不同:

  1. store.js 中定义加载动画状态
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    isLoading: false
  },
  mutations: {
    setLoading(state, status) {
      state.isLoading = status;
    }
  },
  actions: {
    showLoading({ commit }) {
      commit('setLoading', true);
    },
    hideLoading({ commit }) {
      commit('setLoading', false);
    }
  }
});
  1. main.js 中配置Axios拦截器
import Vue from 'vue';
import axios from 'axios';
import store from './store';

axios.interceptors.request.use(config => {
  store.dispatch('showLoading');
  return config;
}, error => {
  store.dispatch('hideLoading');
  return Promise.reject(error);
});

axios.interceptors.response.use(response => {
  store.dispatch('hideLoading');
  return response;
}, error => {
  store.dispatch('hideLoading');
  return Promise.reject(error);
});
  1. Loading.vue 中使用Vuex状态
<template>
  <div v-if="isLoading" class="loading-container">
    <div class="loading-spinner"></div>
  </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
  computed: {
  ...mapState(['isLoading'])
  }
};
</script>

<style scoped>
// 样式同之前
</style>