需求描述 源码地址
- 登录弹框样式实现。
- 在用户发起操作时(如:点击某个按钮)检测用户登录,如未登录,记录用户操作,弹出登录框。
- 用户登录成功后自动用户的上次操作。
- 操作流程 (开始)用户点击行为 --> 验证是否登录 --> 已登录,返回成功回调(结束),未登录,弹出登录框 --> 用户点击登录 --> 登录完成,根据记忆重复用户开始位置的点击行为
所需知识点
- behaviors混入
- 小程序获取自定义组件实例
实现
- 实现登录弹框组件 在根目录创建components文件夹,新建login-box组件,注意这里引用了vant的弹框,可以替换为自己的ui库弹框。
login-box/index.js文件中的$show方法记录当前调用位置的this实例、触发弹框的方法、方法的参数,以便于在登录成功后重新执行触发弹框的方法 来记忆用户的上次操作
import {
SwwComponent} from "../../mixins/component";
import {
wxLogin} from "../../utils/wxPromise";
SwwComponent({
data: {
userInfoVisible: false,
},
pageLifetimes: {
show() {
if ((this.data.userInfoVisible || this.data.phoneVisible) && this.$isLogin()) {
this.$close()
}
}
},
methods: {
//关闭弹框
$close() {
this.setData({
userInfoVisible: false,
phoneVisible: false
})
},
//打开弹框
$show(currentThis, funName, params) {
this.currentThis = currentThis
this.loginFunName = funName
this.loginFunParams = params
this.setData({
userInfoVisible: true
})
},
//获取用户信息
$getUserInfo(e) {
wx.nextTick(() => {
if (e.detail.errMsg === 'getUserInfo:ok') {
//用户同意授权
this.$close()
this.$loginByApi(e.detail.userInfo)
} else {
//用户拒绝授权
}
})
},
//通过接口获取用户信息
$loginByApi(info) {
console.log(info);
//TODO 这里模拟登录成功
wx.showLoading({
mask: true})
setTimeout(() => {
wxLogin().then(code => {
wx.hideLoading()
wx.showToast({
title: '登录成功'
})
wx.setStorageSync('token', code)
this.$loginSuccess()
})
}, 1000)
},
$loginSuccess() {
this.currentThis[this.loginFunName](this.loginFunParams)
wx.nextTick(() => {
delete this.currentThis
delete this.loginFunName
delete this.loginFunParams
})
}
}
});
- 重构页面Page,Compoent,这里使用的是vant封装的Compoent,并根据需求新增了一下自己的方法和属性。在项目根目录创建mixins文件夹,新建component.js basic.js。component.js根据习惯重新命名了小程序的一些页面属性名,如:properties --> props,behaviors --> mixins…。basic.js混入了一些常用方法,这里登录组件用到的有两个 $isLogin返回登录状态, $login验证是否有登录,如果登录则返回Promise.resolve,如果未登录,则拉起登录弹框。
//basic.js
export const basic = Behavior({
methods: {
$emit(name, detail, options) {
this.triggerEvent(name, detail, options);
},
set(data) {
this.setData(data);
return new Promise((resolve) => wx.nextTick(resolve));
},
/**
* 验证是否登录
*/
$isLogin() {
let token = wx.getStorageSync('token')
return !!token
},
/**
* 验证是否登录,若未登录,则打开登录弹框
* funName 登录成功的回调方法
* params 登陆成功的回调参数
*/
$login(funName = '', params = {
}) {
return new Promise((resolve, reject) => {
if (this.$isLogin()) {
resolve()
} else {
try {
let pages = getCurrentPages()
pages[pages.length - 1].selectComponent('#login-box').$show(this, funName, params)
} catch (e) {
wx.showToast({
title: '请在页面引入登录组件'
})
reject(e)
}
reject()
}
})
},
},
});
//component.js
import {
basic } from './basic';
function mapKeys(source, target, map) {
Object.keys(map).forEach((key) => {
if (source[key]) {
target[map[key]] = source[key];
}
});
}
function SwwComponent(vantOptions) {
const options = {
};
mapKeys(vantOptions, options, {
data: 'data',
props: 'properties',
mixins: 'behaviors',
methods: 'methods',
beforeCreate: 'created',
created: 'attached',
mounted: 'ready',
destroyed: 'detached',
classes: 'externalClasses',
watch: 'observers',
options: 'options',
lifetimes: 'lifetimes',
pageLifetimes: 'pageLifetimes',
});
// add default externalClasses
options.externalClasses = options.externalClasses || [];
options.externalClasses.push('custom-class');
// add default behaviors
options.behaviors = options.behaviors || [];
options.behaviors.push(basic);
// add relations
const {
relation } = vantOptions;
if (relation) {
options.relations = relation.relations;
options.behaviors.push(relation.mixin);
}
// map field to form-field behavior
if (vantOptions.field) {
options.behaviors.push('wx://form-field');
}
// add default options
options.options = {
multipleSlots: true,
addGlobalClass: true,
};
Component(options);
}
export {
SwwComponent };
- 全局引入登录弹框,在页面中(注意这里,假如页面A引入了组件B,组件B又引入了组件C···,切组件A B C···都使用了登录验证,无需在每个组件都引入登录弹框组件,仅需在页面A使用弹框组件即可)使用登录弹框login-box。调用登录弹框的操作如下:
import {
SwwComponent} from "../../../../mixins/component";
SwwComponent({
methods: {
onClick(e) {
this.$login('onClick', e).then(() => {
console.log(e);
console.log('登录成功');
})
}
}
})