@[toc]

需求

页面中接口, 需要带上用户信息或者是某个鉴权字段, 这个用户信息或者鉴权字段由某个接口返回

原生 Vue 中的处理方法

1.vuex 配置

import api from '@/api'

const state = {
    userInfo: null, // 需要的用户数据
    globalLoading: true // 一个全局loading, 根据这个字段觉得是否显示一个全局的loading小狗
}

const actions = {
    // 读取用户信息
    async ['getUserInfo'](store) {
        const { commit } = store
        const { data, code } = await api('/api/user/user_info')
        if (code === 200) {
            commit('receiveUserInfo', data)
        }
    }
}

const mutations = {
    ['receiveUserInfo'](state, payload) {
        state.userInfo = payload
    },
    ['globalLoading'](state, payload) {
        state.globalLoading = payload
    }
}

const getters = {
    ['getGlobal'](state) {
        return state
    }
}

export default {
    namespaced: true,
    actions,
    state,
    mutations,
    getters
}

2. 根组件配置

<template>
    <div id="app" class="wrap">
        <!-- 前置接口请求完后, 才开始渲染路由组件 -->
        <router-view v-if="!$global.globalLoading" class="body"></router-view>
		<div v-else>这里可以放个loading效果</div>
    </div>
</template>
<script>
export default {
    name: 'app-root',
    async created() {
        // 请求前置接口
        await this.$store.dispatch('global/getUserInfo')
		// 前置接口请求完成后, 将全局loading关闭
        this.$store.commit('global/globalLoading', false)
    }
}
</script>

3. 路由组件

结果步骤1和2后, 路由组件已经可以正常读取到 vuex 中的 userInfo 数据

uni-app 中的处理方法

uni-app 中由于没有router-view组件, 原生 vue 的方法是不能用了, 只能想一些曲线救国的方法了

1. vuex 配置

和上面一样, 不再重复

2. 根组件配置

uni-app 中应用生命周期函数有不少个, 但是能用的似乎也只有onLaunch了, 但是onLaunch却不能阻止路由组件的渲染, 也就是说, 在onLaunch里执行一个ajax请求, 很可能在渲染到路由组件时, ajax请求还没有结束, 重点要解决的就是这个

<script>
export default {
    async onLaunch() {
        // 请求前置接口
        await this.$store.dispatch('global/getUserInfo')
        // 前置接口请求完成后, 将全局loading关闭
        this.$store.commit('global/globalLoading', false)
    }
}
</script>

3. 路由组件

<template>
    <!-- 路由组件的数据是否加载完成-->
    <view v-if="isLoaded" class="wrap">
        <!-- 组件内容 -->
    </view>
	<!-- 没有加载完成, 给个loading效果 -->
    <view v-else class="page-loading">
        <u-loading mode="flower" size="80"></u-loading>
    </view>
</template>
<script>
export default {
    data() {
        return {
            isLoaded: false
        }
    },
	computed: {
		['$globalLoading']() {
			return this.$store.state.global.globalLoading
		}
	},
    onLoad(e) {
	    // 将路由传过来的参数, 全部 set 到 data 中
        Object.keys(e).forEach(item => {
            this.$set(this, item, e[item])
        })
		// 当 globalLoading=true 时, 即前置接口还没有请求完, 一般出现在刚打开的第一个页面, 或者是 H5 站时的刷新页面
        if (this.$globalLoading) {
		    // 这时候, 我们不直接请求路由组件里的接口, 而是通过 watch 来监听前置接口是否请求完成
            const unwatch = this.$watch('$globalLoading', val => {
				// 监听到 globalLoading = false 时, 开始请求路由组件内的接口
                if (!val) {
                    this.init()
					// 逻辑已经完里, 不需要再监听了, 将 watch 注销
                    unwatch()
                }
            })
		// 当 globalLoading=false 时, 可以直接开始请求路由组件内的接口, 一般出现在打开第一个页面后的路由切换
        } else {
            this.init()
        }
    }
    methods: {
	    // 将所有需要初始化的逻辑放在 init 方法里
        async init() {
            await this.getList()
			// 接口请求完后, 将 isloaded 设置成 ture, 开始渲染模板, 同时关闭 loading 效果
            this.isloaded = true
        }
        async getList() {
		    // 这里已经能读到 vuex 里的 userInfo 了
            // ajax
        }
    }
}
</script>

4. 优化下

每个页面都向步骤3这么写, 似乎有点不优雅, 我们稍微优化下

a. 创建一个 mixins 文件

mixins/index.js
我们将, 每个路由组建的onLoad提取出来, 作为一个混合, 这里也就明白了为什么前面, 要特别用一个 init 方法, 主要是方便路由组件进行混合

export default {
	computed: {
		['$globalLoading']() {
			return this.$store.state.global.globalLoading
		}
	},
    onLoad(e) {
        Object.keys(e).forEach(item => {
            this.$set(this, item, e[item])
        })
        console.log('mixin onload')
        if (this.$globalLoading) {
            const unwatch = this.$watch('$globalLoading', val => {
                if (!val) {
                    this.init()
                    unwatch()
                }
            })
        } else {
            this.init()
        }
    }
}
b. 修改下路由组件
<template>
    <!-- 路由组件的数据是否加载完成-->
    <view v-if="isLoaded" class="wrap">
        <!-- 组件内容 -->
    </view>
	<!-- 没有加载完成, 给个loading效果 -->
    <view v-else class="page-loading">
        <u-loading mode="flower" size="80"></u-loading>
    </view>
</template>
<script>
import asyncData from '@/mixins/index'

export default {
    // 使用混合
    mixins: [asyncData],
    data() {
        return {
            isLoaded: false
        }
    },
    onLoad() {
	    // 路由组件里, 其他需要在 onload 钩子执行的逻辑
    }
    methods: {
	    // 将所有需要初始化的逻辑放在 init 方法里
        async init() {
            await this.getList()
			// 接口请求完后, 将 isloaded 设置成 ture, 开始渲染模板, 同时关闭 loading 效果
            this.isloaded = true
        }
        async getList() {
            // ajax
        }
    }
}
</script>

使用方法也很简单, 在需要的页面里, 引入混合, 将所有初始化逻辑, 丢到 init 方法里即可

到此, 就完成了…

发表评论
6天a
1111