在开发uniapp项目时,页面切换的过程中,经常需要添加loading效果以提高用户体验。uniapp自带的loading效果无法自定义,所以想着自己实现一个。
实现思路
- 封装一个全局loading组件,放置插槽和loading效果,使用
v-if
或者v-show
去进行切换。 - 将切换的状态isLoading放置在
app.vue
中的globalData
里面来进行状态控制 - 使用
uni.$on
和uni.$emit
来完成切换即可
实现代码
globalData
app.vue
我们需要统一管理页面切换时的loading状态,以便在其他页面中使用。
<script>
export default {
globalData: {
loading: false
}
}
</script>
pageLoading组件实现
src/components/pageLoading/index.vue
在created中监听 pageSwitch 事件, res就是你传递的参数,true就是开启loading效果
<template>
<view class="container">
<slot v-if="!loading"></slot>
<view v-else class="center">
<!-- loading组件可以自己实现, 不想自己写就找个网站cv一下 -->
<!-- <loading></loading> -->
加载中...
</view>
</view>
</template>
<script>
export default {
name: 'pageLoading',
data() {
return {
loading: false
}
},
created() {
this.loading = getApp().globalData.loading
uni.$on('pageSwitch', res => {
this.loading = res
getApp().globalData.loading = res
})
}
}
</script>
<style lang="scss" scoped>
.center {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.6);
}
</style>
使用
在跳转的时候开启loading效果,跳转到对应页面之后再去手动关闭即可,或者是在某个请求完成之后去关闭
<template>
<page-loading>
<button @click="jump">跳转</button>
</page-loading>
</template>
<script>
// 嫌麻烦注册个全局组件
import pageLoading from '../../components/pageLoading/index.vue'
export default {
components: { pageLoading },
methods: {
jump() {
uni.$emit('pageSwitch', true)
uni.switchTab({
url: '/pages/my/my'
})
}
}
}
</script>
使用扩展
如果嫌每次跳转都需要手动开启loading,那就封装一下uni的跳转函数或者拦截一下跳转,这种方式并不是很推荐,一般是请求完成了加载页面,建议封装在请求里面 —— 大概思路就是,每个页面最主要的数据回来了就可以关闭loading了,又或者是直接写到页面里面去等请求执行完了关闭,这个得看实际场景。
拦截跳转实现
const switchTabBarInterceptor = () => {
uni.addInterceptor('switchTab', {
success: function (res) {
uni.$emit('pageSwitch', true)
},
complete() {
uni.$emit('pageSwitch', false)
}
})
}
switchTabBarInterceptor()
// 丢main.js 里面就好了..
跳转封装大概实现
export class Jump {
tabBarPage = []
/**
* Jump类构造函数
* @param {Array} tabBar - 底部tab栏的页面列表
*/
constructor(tabBar) {
this.tabBarPage = tabBar
}
/**
* 将传入的参数转化成URL参数字符串
* @param {Object} params - 需要转化的参数对象
* @returns {string} - 转化后的URL参数字符串
*/
parseParams(params) {
return Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&')
}
/**
* 跳转到某一个页面
* @param {string} url - 需要跳转的页面路径
* @param {Object} params - 需要传递的参数对象
*/
push(url, params = {}) {
const urlWithParams = Object.keys(params).length ? `${url}?${this.parseParams(params)}` : url
const isTabBarPage = this.tabBarPage.some(page => page === url)
if (isTabBarPage) {
// 还是老样子,在跳转之前开启loading
uni.$emit('pageSwitch', true)
uni.switchTab({ url: urlWithParams })
}
else {
uni.navigateTo({ url: urlWithParams })
}
}
}
挂载一手方便使用
/**
* @typedef {Object} Vue
* @property {Jump} $jump - 跳转类实例
*/
Vue.prototype.$jump = new Jump(['/pages/index/index', '/pages/my/my'])
请求关闭loading
在统一管理请求的时候就确定好哪些api是可以关闭loading的
// request.js
class Http {
...
request(..., closeLoading = false) {
// ...
uni.request({
complete() {
if(closeLoading) uni.$emit('pageSwitch', false)
}
})
// ...
}
}
// api.js
const http = new Http()
const fetchOrderList = () => http.request(..., true)