背景
最近一直在试点用
uni-app去做一些小需求,分享一下在项目中遇到的问题以及一些经验。ps:本项目整体为vue-cli创建,项目目录结构会与hbuilderx有差异。本项目开源于Github
项目目标
做一个用户线上预约,线下到店体验的简单预约商城小程序,常见于
美业婚庆/摄影教育/培训亲子等线下场景。小程序端使用uni-app,后端API使用nestjs+mongo,服务端部署使用docker。
系列连载
跨页面通信
跨页面通信,跨组件通信,这个在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
})
写在最后
前三章在项目调研过程中边写边调研,一直没发布。这次一次性发出来了。第四章开始就要展示真正的艺术了。
项目已经完成了一部分功能以及页面。下一章节,数据脱敏后会同步开源。