@[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 方法里即可
到此, 就完成了…