导航
登录流程是调wx.login获取code传给后台服务器获取微信用户唯一标识openid及本次登录的会话密钥(session_key)等)。拿到开发者服务器传回来的会话密钥(session_key)之后,前端要保存wx.setStorageSync('sessionKey', 'value')
持久登录状态:session信息存放在cookie中以请求头的方式带回给服务端,放到 request.js 里的 wx.request 的header 里
核心:通过 vuex 的 hasLogin 来判断是进行后续操作,还是跳转到登录页
onLaunchuserInfo 和 userInfo.tel
openIdtelunionid 传给后端,换取最新 userInfo,设置 hasLogin = true
openId 在不同应用下唯一unionid 在同一公司下,不同应用中唯一hasLogin = false,清空 userInfo,清空 tokenwx.login 获取 wxCodewxCode、手机号iv、手机号encryptedData 发给后端换取 token、tel、userInfohasLoginauth 页面的方法getCurrentPages()[getCurrentPages().length - 1] 拿到当前页面onLaunch: function () {
this.wxLogin()
}
async wxLogin(context) {
let userInfo = storage.getUserInfo();
if (userInfo && userInfo.tel) {
// 有电话,以前登录过,更新 userInfo
const res = await user.doLoginMobile({
openid: userInfo.openidApp,
phone: userInfo.tel,
unionid: userInfo.unionid,
});
if (res.code === 0 && res.data) {
// 设置vuex登录状态
context.commit("setHasLogin", true);
context.commit("setUserInfo", res.data ? res.data : {});
context.commit("setToken", res.data ? res.data.token : "");
return context.state.userInfo;
} else {
// 登录失败
// 登出
context.commit("logout");
return false;
}
} else {
context.commit("logout");
return false;
}
},
// 登出
logout(state) {
state.userInfo = {};
state.hasLogin = false;
storage.removeUserInfo();
storage.removeToken();
},
// 手机号登录
async weChatLogin() {
// 获取code
this.wxCode = await this.getWxCode();
const data = {
code: this.wxCode, // 必传
IV: this.userData.iv, // 必传(手机号的iv)
encryptedData: this.userData.encryptedData, // 必传(手机号的encryptedData)
};
const res = await user.weChatLogin(data);
if (res.code === 0 && res.data) {
// 登录成功
this.setHasLogin(true);
this.$storage.setToken(res.data.token);
this.setUserInfo(res.data);
uni.showToast({ title: "授权登陆成功" });
setTimeout(() => {
this.jumpUrl(this.redirectUrl);
}, 500);
} else {
// 登录失败
uni.showModal({
title: "登录失败,请重试",
content: res.msg,
showCancel: false,
});
}
},
navigateTo 等跳转方法,使其除了接收 options 对象参数,还接受一个 needAuthneedAuth 为真,就看下 hasLogin 是否为真
// 对于需要登录才可以进入的页面,先做一下登录校验,如果未登录,则跳转前先跳转至登录页面。
import store from "@/store";
import { gotoAuth } from "@/utils/index";
// 对路由相关的几个方法进行遍历并缓存原方法,
// 在uni对象上重写方法,每个方法增加needAuth参数,表示跳转前是否需要登录
// 如果需要登录,则首先获取用户信息,
// 如果获取不到用户信息,将会自动跳转到登录页(store里面的user模块做的),
// 否则获取到信息就调用缓存起来的原方法,实现跳转 如果不需要登录,则直接调用原方法
export default function () {
["navigateTo", "redirectTo", "switchTab", "navigateBack"].map(item => {
const nativeFunc = uni[item];
uni[item] = function (opts, needAuth) {
if (needAuth) {
// store.dispatch("user/getToken").then(() => {
// nativeFunc.call(this, opts);
// });
if (store.state.hasLogin) {
nativeFunc.call(this, opts);
} else {
gotoAuth();
}
} else {
return nativeFunc.call(this, opts);
}
};
});
}
wx.getStorage/setStorage 支持任何原生类型,支持对象Date.now() - data.createTime > date.timeouthx-header
index.json 中设置 component: trueposition: fixed导航栏高度 = 胶囊上下pending + 胶囊高度 + 状态栏高度wx.navigateBack
getCurrentPages().length === 1wx.switchTab({ url: 'pages/index/index' })usingComponents: { "hx-header": 'path'}navigationStyle: "custom"Component({
properties: {},
data: {
navigationTop: 0, // 导航栏顶部高度
navigationHei: 20, // 导航栏高度
paddingLeft: 0, // 导航栏左内边距
padddingTop: 0, // 导航栏上内边距
imgArrow: "<https://cdn2.iconfinder.com/data/icons/font-awesome/1792/angle-left-512.png>" // 返回箭头
},
ready: function () {
// 状态栏高度
const { screenWidth, statusBarHeight } = wx.getSystemInfoSync();
// 胶囊按钮
//bottom: 胶囊底部距离屏幕顶部的距离
//height: 胶囊高度
//left: 胶囊左侧距离屏幕左侧的距离
//right: 胶囊右侧距离屏幕左侧的距离
//top: 胶囊顶部距离屏幕顶部的距离
//width: 胶囊宽度
const { height: capsuleHeight, top: capsuleTop, right: capsuleRight } = wx.getMenuButtonBoundingClientRect();
// 左、上边内边距
const paddingLeft = screenWidth - capsuleRight;
const paddingTop = statusBarHeight;
// 导航栏高度 = 胶囊上下pending + 胶囊高度 + 状态栏高度
const navigationHei = (capsuleTop - statusBarHeight) * 2 + capsuleHeight + statusBarHeight;
this.setData({
navigationTop: 0,
navigationHei,
paddingLeft,
paddingTop
})
},
methods: {
back: function () {
wx.navigateBack({
delta: 1,
})
}
}
})
{
"usingComponents": {
"hx-header": "../../components/hx-header/index"
},
"navigationStyle": "custom"
}
{
...
"window": {
...
"navigationStyle": "custom"
},
"usingComponents": {
"hx-header": "components/hx-header/index"
},
...
}
tabBar ,设置 custom: true 和 list
usingComponents: { "custom-tab-bar": "custom-tab-bar/index" }e.currentTarget.dataset
wx.switchTab({ url: path }) 跳转custom-tab-bar 组件,index.json 下设置 component: true<cover-view class="tab-bar">
<cover-view class="tab-bar-border"></cover-view>
<cover-view wx:for="{{list}}" wx:key="index" class="tab-bar-item" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab">
<cover-image src="{{selected === index ? item.selectedIconPath : item.iconPath}}"></cover-image>
<cover-view style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</cover-view>
</cover-view>
</cover-view>
Component({
data: {
selected: 0,
color: "#7A7E83",
selectedColor: "#3cc51f",
list: [{
pagePath: "/pages/index/index",
text: "首页",
iconPath: "/images/Home.png",
selectedIconPath: "/images/Home.png"
}, {
pagePath: "/pages/mall/index",
text: "商城",
iconPath: "/images/Mall.png",
selectedIconPath: "/images/Mall.png"
},
{
pagePath: "/pages/cart/index",
iconPath: "/images/Cart.png",
text: "购物车",
selectedIconPath: "/images/Cart.png"
},{
pagePath: "/pages/me/index",
text: "个人中心",
iconPath: "/images/My.png",
selectedIconPath: "/images/My.png"
}]
},
attached() {
},
methods: {
switchTab(e) {
const data = e.currentTarget.dataset
console.log(data);
const url = data.path
wx.switchTab({url})
this.setData({
selected: data.index
})
}
}
})
{
...
"usingComponents": {
"hx-header": "components/hx-header/index",
"custom-tab-bar": "custom-tab-bar/index"
},
"tabBar": {
"custom": true,
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "./images/Home.png",
"selectedIconPath": "./images/Home.png"
},
{
"pagePath": "pages/mall/index",
"text": "商城",
"iconPath": "./images/Mall.png",
"selectedIconPath": "./images/Mall.png"
},
{
"pagePath": "pages/cart/index",
"text": "购物车",
"iconPath": "./images/Cart.png",
"selectedIconPath": "./images/Cart.png"
},
{
"pagePath": "pages/me/index",
"text": "个人中心",
"iconPath": "./images/My.png",
"selectedIconPath": "./images/My.png"
}
]
},
...
}
来源:
使用全局变量实现数据传递 globalData
在 app.js 文件中定义全局变量 globalData, 将需要存储的信息存放在里面
// app.js
App({
// 全局变量
globalData: {
userInfo: null
}
})
使用的时候,直接使用 getApp() 拿到存储的信息