uni-app小程序客到店项目实战(三):跨页面通信数据预加载

2,224 阅读3分钟

背景

最近一直在试点用uni-app去做一些小需求,分享一下在项目中遇到的问题以及一些经验。ps:本项目整体为vue-cli创建,项目目录结构会与hbuilderx有差异。本项目开源于Github

项目目标

做一个用户线上预约,线下到店体验的简单预约商城小程序,常见于美业 婚庆/摄影 教育/培训 亲子等线下场景。小程序端使用uni-app,后端API使用nestjs+mongo,服务端部署使用docker

系列连载

(一):让Vant适用于uni项目

(二):uni拦截器(Interceptor)

(三):跨页面通信数据预加载

(四):是时候展示真正的艺术了

跨页面通信

跨页面通信,跨组件通信,这个在vue里应该是最基础的问答题目了。根据自己的项目大小,复杂程度能选择多种方案。

ps:我去年转岗面试的时候,还被小伙伴问及这个问题,然后我回答了我不会。尊重是相互的,我的简历你不看,你的问题我也就算了。

uni中,框架本身提供了全局级别的,跨任意组件,页面监听。用起来已经很方便了。但是依然满足不了我的需求。

通俗的场景:列表页面进入详情页面。想把列表中的一些内容传入页面内,能在页面内请求未加载之前提供一个初始有数据的页面给用户,而不是空白loading。

目标:很明确就是把当前页数据带入下一页数据。可以依赖vuex,也可以简单的造轮子。

轮子造起来

// 一个简单的数据存储 新建preload.ts
// 最终使用起来像这样吧
// uni.navigateTo({
// 	url: '/pages/index/detail',
//  preload: {} // 需要传递的数据
// })
function getCurrentPage () {
	return getCurrentPages()[getCurrentPages().length - 1]
}
export class Preload {
	private data: Map<string, any> = new Map<string, any>()
  // 放入数据
	set (url: string, data: any) {
		this.data.set(this.realPath(url), data)
	}
  // 取出并删除
	get (url?: string): any {
		url = this.realPath(url)
		const res = this.data.get(url)
		this.data.delete(url)
		return res
	}
  // 是否存在
	has (url?: string): boolean {
		return this.data.has(this.realPath(url))
	}
  // 修正地址
	private realPath (url?: string) {
		if (!url) {
			url = '/' + getCurrentPage().route
		}
		return url
	}
}
// 轮子怎么用? 在main.ts内new下,挂vue上就行啦....
import { Preload } from '@minh/preload'
// ...其他文件
Vue.prototype.$preload = new Preload()
// ...其他文件
// 上一章节提到的拦截器,继续增强它
uni.addInterceptor('navigateTo', {
  invoke (obj: any) {
    if (obj.preload) {
      let __timer: number
      // 走异步 不碍事
      __timer = setTimeout(() => {
        Vue.prototype.$preload.set(url, obj.preload)
        clearTimeout(__timer)
      })
    }
    return obj
  }
})
// 到这里就完成了通过 navigateTo 传递preload数据了
// 传递数据的获取 被传递页面
export default class Detail extends mixins(BasePageMixins) {
  onLoad () {
    const hasPreload = this.$preload.has()
    // 先判断 后获取
    if (hasPreload) {
      const preloadData = this.$preload.get()
    }
  }
}

以上,简单是实现了上面的目标。主要还是依靠拦截器,在拦截器内也可以使用vuex来存。

关于vuex

起初我也没打算使用vuex。后来一想,我是大型项目啊,怎么能没有vuex,那必须得加上。

在这推荐一下vuex的插件vuex-persistedstate,用于数据的持久化。场景也很常见,登录信息就需要持久化。

import persistedstate from 'vuex-persistedstate'
const debug = process.env.NODE_ENV !== 'production'
const plugins = [
	persistedstate({
		storage: {
			getItem: (key) => uni.getStorageSync(key),
			setItem: (key, value) => uni.setStorageSync(key, value),
			removeItem: (key) => uni.removeStorageSync(key)
		},
		paths: ['auth'] // 需要持久的路径 自己按模块来区分
	})
]
const modules = .... // 各种模块组件
const store: Vuex.Store<IRootState> = new Vuex.Store<IRootState>({
	plugins,
	strict: debug,
	modules
})

写在最后

前三章在项目调研过程中边写边调研,一直没发布。这次一次性发出来了。第四章开始就要展示真正的艺术了。

项目已经完成了一部分功能以及页面。下一章节,数据脱敏后会同步开源。