微信小程序如何保证每个页面都已经登陆详解

一个微信小程序中,有首页,有个人页面,还有一些列表页面,详情页面等等,这些页面大部分是可以分享的。当分享出去的页面被一个另一个用户打开的时候,这个页面怎么确保这个用户已经登陆了呢?

网上有很多方案是在请求封装里面加一道拦截,如果没有token,就先调用登陆请求获取token后,再继续。

这种方案没毛病,只要注意一点,当一个页面有多个请求同时触发时,当所有请求拦截后,放到一个数组里面,在获取token成功后,遍历数组一个个请求就行。

但这个需求再复杂一点,比如连锁便利店小程序,大部分页面都需要有一个门店(因为需要根据门店获取当前门店商品的库存、价格等),这个门店是根据当前的定位来调用后台接口获得的,这个时候如果在请求里进行封装就太麻烦了。

解决方案

首先,我们注意到,登陆,获取定位与我们的页面请求是异步的,我们需要保证页面请求是在登陆和获取定位之后,但要是我们每个页面都写一个遍,可维护性就太差了。所以我们可以抽离出一个方法来做这件事。

所以代码就这样了:

const app = getApp() Page({ data: { logs: [] }, onLoad() { app.commonLogin(()=>{ // 处理页页面请求 }) } })

做到这里好像是解决我们的问题,但再想一想,如果还想做更多的事,比如说每个页面的onShareAppMessage统一处理,但我又不想在每个页面再写一遍,另外,我又想自己对每个页面实现一个watch,怎么做?

进一步解决方案

我们可以看到微信小程序,每个页面是一个Page(),那么我们可以给这个Page外面加一层壳子,我们可以有一个MyPage来替换这个Page,废话不多说,上代码:

tool.js 相关代码

/** * 处理合并参数 */ handlePageParamMerge(arg) { let numargs = arg.length; // 获取被传递参数的数值。 let data = {} let page = {} for (let ix in arg) { let item = arg[ix] if (item.data && typeof (item.data) === 'object') { data = Object.assign(data, item.data) } if (item.methods && typeof (item.methods) === 'object') { page = Object.assign(page, item.methods) } else { page = Object.assign(page, item) } } page.data = data return page } /*** * 合并页面方法以及数据, 兼容 {data:{}, methods: {}} 或 {data:{}, a:{}, b:{}} */ mergePage() { return this.handlePageParamMerge(arguments) } /** * 处理组件参数合并 */ handleCompParamMerge(arg) { let numargs = arg.length; // 获取被传递参数的数值。 let data = {} let options = {} let properties = {} let methods = {} let comp = {} for (let ix in arg) { let item = arg[ix] // 合并组件的初始数据 if (item.data && typeof (item.data) === 'object') { data = Object.assign(data, item.data) } // 合并组件的属性列表 if (item.properties && typeof (item.properties) === 'object') { properties = Object.assign(properties, item.properties) } // 合组件的方法列表 if (item.methods && typeof (item.methods) === 'object') { methods = Object.assign(methods, item.methods) } if (item.options && typeof (item.options) === 'object') { options = Object.assign(options, item.options) } comp = Object.assign(comp, item) } comp.data = data comp.options = options comp.properties = properties comp.methods = methods return comp } /** * 组件混合 {properties: {}, options: {}, data:{}, methods: {}} */ mergeComponent() { return this.handleCompParamMerge(arguments) } /*** * 合成带watch的页面 */ newPage() { let options = this.handlePageParamMerge(arguments) let that = this let app = getApp() //增加全局点击登录判断 if (!options.publicCheckLogin){ options.publicCheckLogin = function (e) { let pages = getCurrentPages() let page = pages[pages.length - 1] let dataset = e.currentTarget.dataset let callback = null //获取回调方法 if (dataset.callback && typeof (page[dataset.callback]) === "function"){ callback = page[dataset.callback] } // console.log('callback>>', callback, app.isRegister()) //判断是否登录 if (callback && app.isRegister()){ callback(e) } else{ wx.navigateTo({ url: '/pages/login/login' }) } } } const { onLoad } = options options.onLoad = function (arg) { options.watch && that.setWatcher(this) onLoad && onLoad.call(this, arg) } const { onShow } = options options.onShow = function (arg) { if (options.data.noAutoLogin || app.isRegister()) { onShow && onShow.call(this, arg) //页面埋点 app.ga({}) } else { wx.navigateTo({ url: '/pages/login/login' }) } } return Page(options) } /** * 合成带watch等的组件 */ newComponent() { let options = this.handleCompParamMerge(arguments) let that = this const { ready } = options options.ready = function (arg) { options.watch && that.setWatcher(this) ready && ready.call(this, arg) } return Component(options) } /** * 设置监听器 */ setWatcher(page) { let data = page.data; let watch = page.watch; Object.keys(watch).forEach(v => { let key = v.split('.'); // 将watch中的属性以'.'切分成数组 let nowData = data; // 将data赋值给nowData for (let i = 0; i < key.length - 1; i++) { // 遍历key数组的元素,除了最后一个! nowData = nowData[key[i]]; // 将nowData指向它的key属性对象 } let lastKey = key[key.length - 1]; // 假设key==='my.name',此时nowData===data['my']===data.my,lastKey==='name' let watchFun = watch[v].handler || watch[v]; // 兼容带handler和不带handler的两种写法 let deep = watch[v].deep; // 若未设置deep,则为undefine this.observe(nowData, lastKey, watchFun, deep, page); // 监听nowData对象的lastKey }) } /** * 监听属性 并执行监听函数 */ observe(obj, key, watchFun, deep, page) { var val = obj[key]; // 判断deep是true 且 val不能为空 且 typeof val==='object'(数组内数值变化也需要深度监听) if (deep && val != null && typeof val === 'object') { Object.keys(val).forEach(childKey => { // 遍历val对象下的每一个key this.observe(val, childKey, watchFun, deep, page); // 递归调用监听函数 }) } var that = this; Object.defineProperty(obj, key, { configurable: true, enumerable: true, set: function (value) { if (val === value) { return } // 用page对象调用,改变函数内this指向,以便this.data访问data内的属性值 watchFun.call(page, value, val); // value是新值,val是旧值 val = value; if (deep) { // 若是深度监听,重新监听该对象,以便监听其属性。 that.observe(obj, key, watchFun, deep, page); } }, get: function () { return val; } }) }

页面代码:

app.tool.newPage({ data: { // noAutoLogin: false }, onShow: function () { // 在这里写页面请求逻辑 } }

最后

代码是在线上跑了很久的,tool里的newPage封装,你可以根据自己的需求进行添加。总之,我这里是提供一种思路,如有更佳,欢迎分享。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwzysj.html