现状
一个微信小程序中,有首页,有个人页面,还有一些列表页面,详情页面等等,这些页面大部分是可以分享的。当分享出去的页面被一个另一个用户打开的时候,这个页面怎么确保这个用户已经登陆了呢?
网上有很多方案是在请求封装里面加一道拦截,如果没有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封装,你可以根据自己的需求进行添加。总之,我这里是提供一种思路,如有更佳,欢迎分享。
到此这篇关于微信小程序如何保证每个页面都已经登陆的文章就介绍到这了,更多相关微信小程序保证页面登陆内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论