MST

星途 面试题库

面试题:Vue路由动态参数传递与数据预取优化

在大型Vue应用中,有大量基于动态参数的路由页面,如商品详情页,每个商品详情页可能需要从多个API获取数据。为了提升用户体验,需要在路由跳转前就预取部分关键数据。请结合Vue路由动态参数传递,设计一个通用的数据预取方案,包括如何在路由配置、组件生命周期钩子函数以及数据请求逻辑方面进行设计和实现,同时说明如何处理预取数据失败的情况。
40.7万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

路由配置

  1. 定义动态路由参数:在 router/index.js 中,为商品详情页定义动态路由。例如:
const router = new VueRouter({
  routes: [
    {
      path: '/product/:productId',
      name: 'ProductDetail',
      component: ProductDetail
    }
  ]
});

这里 :productId 是动态参数,用于标识不同的商品。

组件生命周期钩子函数

  1. beforeRouteEnter 中预取数据:在 ProductDetail 组件中,使用 beforeRouteEnter 钩子函数。这个钩子函数在路由进入组件之前被调用,且此时组件实例还未被创建,所以不能使用 this。可以通过 next 回调函数将预取的数据传递给组件。
export default {
  name: 'ProductDetail',
  data() {
    return {
      productData: null,
      relatedData: null
    };
  },
  beforeRouteEnter(to, from, next) {
    const productId = to.params.productId;
    // 预取关键数据的逻辑,这里假设使用 axios 进行请求
    import axios from 'axios';
    axios.all([
      axios.get(`/api/product/${productId}`),
      axios.get(`/api/related/${productId}`)
    ]).then(axios.spread((productRes, relatedRes) => {
      next(vm => {
        vm.productData = productRes.data;
        vm.relatedData = relatedRes.data;
      });
    })).catch(error => {
      // 处理预取数据失败的情况,这里简单提示错误
      next(error.message);
    });
  },
  created() {
    // 如果在 beforeRouteEnter 中传递了错误信息,在这里处理
    if (typeof this.$route.params.error ==='string') {
      console.error('数据预取失败:', this.$route.params.error);
    }
  }
};

数据请求逻辑

  1. 封装API请求:将数据请求逻辑封装成独立的函数,以便复用。例如:
import axios from 'axios';

export const getProduct = (productId) => {
  return axios.get(`/api/product/${productId}`);
};

export const getRelated = (productId) => {
  return axios.get(`/api/related/${productId}`);
};

然后在 beforeRouteEnter 中调用这些函数:

import { getProduct, getRelated } from '@/api/product';

beforeRouteEnter(to, from, next) {
  const productId = to.params.productId;
  axios.all([
    getProduct(productId),
    getRelated(productId)
  ]).then(axios.spread((productRes, relatedRes) => {
    next(vm => {
      vm.productData = productRes.data;
      vm.relatedData = relatedRes.data;
    });
  })).catch(error => {
    next(error.message);
  });
}

处理预取数据失败的情况

  1. beforeRouteEnter 中捕获错误:如上述代码,在 axios.allcatch 块中捕获预取数据的错误,并通过 next 传递错误信息。
  2. 在组件 created 钩子中处理错误:在组件的 created 钩子函数中检查是否有错误传递过来,并进行相应处理,例如记录错误日志、显示错误提示等。
  3. 用户体验优化:可以在页面上显示一个加载动画,直到数据预取完成或失败。如果预取失败,可以提供一个重试按钮,让用户重新尝试预取数据。例如,在模板中添加:
<template>
  <div>
    <div v-if="loading">加载中...</div>
    <div v-if="error" class="error">{{ error }}</div>
    <button v-if="error" @click="retryFetch">重试</button>
    <div v-if="productData && relatedData">
      <!-- 商品详情内容展示 -->
    </div>
  </div>
</template>
export default {
  data() {
    return {
      loading: true,
      error: null,
      productData: null,
      relatedData: null
    };
  },
  beforeRouteEnter(to, from, next) {
    const productId = to.params.productId;
    axios.all([
      getProduct(productId),
      getRelated(productId)
    ]).then(axios.spread((productRes, relatedRes) => {
      next(vm => {
        vm.loading = false;
        vm.productData = productRes.data;
        vm.relatedData = relatedRes.data;
      });
    })).catch(error => {
      next(vm => {
        vm.loading = false;
        vm.error = error.message;
      });
    });
  },
  methods: {
    retryFetch() {
      this.loading = true;
      this.error = null;
      const productId = this.$route.params.productId;
      axios.all([
        getProduct(productId),
        getRelated(productId)
      ]).then(axios.spread((productRes, relatedRes) => {
        this.loading = false;
        this.productData = productRes.data;
        this.relatedData = relatedRes.data;
      })).catch(error => {
        this.loading = false;
        this.error = error.message;
      });
    }
  }
};