MST

星途 面试题库

面试题:复杂业务下Vue路由守卫与组件生命周期的协作优化场景探讨

在一个具有多层嵌套路由,且各组件间存在复杂数据交互的Vue项目中,如何协调路由守卫与组件生命周期钩子函数,以实现高效的页面渲染、数据加载及权限控制等场景。请举例说明并阐述整体设计思路与可能遇到的问题及解决方案。
14.5万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

整体设计思路

  1. 路由守卫
    • 全局前置守卫:用于全局的权限控制,例如在进入任何页面之前检查用户是否登录。可以在router.js中定义:
    const router = new VueRouter({... })
    router.beforeEach((to, from, next) => {
        const isLoggedIn = localStorage.getItem('token')
        if (to.meta.requiresAuth &&!isLoggedIn) {
            next('/login')
        } else {
            next()
        }
    })
    
    • 路由独享守卫:在特定路由上定义守卫,用于该路由特有的权限或数据加载逻辑。例如:
    const router = new VueRouter({
        routes: [
            {
                path: '/admin',
                component: AdminComponent,
                beforeEnter: (to, from, next) => {
                    const userRole = localStorage.getItem('role')
                    if (userRole === 'admin') {
                        next()
                    } else {
                        next('/forbidden')
                    }
                }
            }
        ]
    })
    
    • 全局后置守卫:主要用于页面切换后的一些操作,如页面标题的更新等。
    router.afterEach((to, from) => {
        document.title = to.meta.title || '默认标题'
    })
    
  2. 组件生命周期钩子函数
    • created:在此钩子函数中可以进行数据的初始化获取,例如调用API获取页面所需数据。对于多层嵌套路由,父组件获取的数据可以通过props传递给子组件。
    export default {
        data() {
            return {
                userData: null
            }
        },
        created() {
            this.fetchUserData()
        },
        methods: {
            async fetchUserData() {
                const response = await axios.get('/api/user')
                this.userData = response.data
            }
        }
    }
    
    • mounted:适合进行一些DOM操作相关的初始化,比如初始化第三方插件(如echarts)。如果需要在组件挂载后根据路由参数更新数据,也可以在这里进行。
    export default {
        data() {
            return {
                chart: null
            }
        },
        mounted() {
            this.chart = echarts.init(this.$el.querySelector('.chart - container'))
            this.updateChartData()
        },
        methods: {
            async updateChartData() {
                const response = await axios.get('/api/chart - data')
                this.chart.setOption({...response.data })
            }
        }
    }
    

举例说明

假设我们有一个多层嵌套路由的博客管理系统,有/posts(展示文章列表),/posts/:id(展示文章详情),/admin/posts(管理员管理文章页面,需要管理员权限)。

  1. 权限控制
    • /admin/posts路由上设置路由独享守卫,检查用户是否为管理员。
    • 在全局前置守卫中检查用户是否登录,若未登录,阻止进入需要登录的页面。
  2. 数据加载
    • PostsList组件(对应/posts)的created钩子函数中获取文章列表数据。
    • PostDetail组件(对应/posts/:id)的created钩子函数中,根据路由参数:id获取文章详细数据。

可能遇到的问题及解决方案

  1. 数据重复加载
    • 问题:在路由切换时,如果组件没有被销毁,可能会重复加载数据。例如从/posts切换到/posts/:idcreated钩子函数可能会再次执行导致数据重复获取。
    • 解决方案:可以通过watch监听路由参数的变化,只有当参数变化时才重新获取数据。
    export default {
        data() {
            return {
                post: null
            }
        },
        watch: {
            '$route.params.id': {
                immediate: true,
                async handler(newId) {
                    const response = await axios.get(`/api/post/${newId}`)
                    this.post = response.data
                }
            }
        }
    }
    
  2. 权限控制不及时
    • 问题:如果用户在登录状态下权限发生变化,可能不会及时在路由守卫中反映出来。
    • 解决方案:可以在路由守卫中增加一个获取最新权限的逻辑,或者在用户权限变化时手动刷新页面(简单粗暴但有效),也可以通过事件总线或Vuex来通知路由守卫更新权限状态。
  3. 组件生命周期与路由守卫冲突
    • 问题:例如在组件created钩子函数中获取数据,同时路由守卫中也进行一些数据处理,可能会导致数据处理顺序混乱。
    • 解决方案:明确职责,尽量在路由守卫中只进行权限控制和一些与路由相关的基础数据准备,而复杂的数据获取和处理放在组件生命周期钩子函数中。同时,在涉及异步操作时,合理使用async/await确保操作顺序。