最近微信小程序开发文档说明,wx.getUserInfo()接口已经不会再弹授权框,甚至扬言要放弃这个接口。这次调整,还是蛮伤的。
看文档说需要用
这个功能按钮。乍一想,我需要判断登录了,就要有这样一个按钮?,多“捞”哦。我页面这么好看,容不下你这个按钮好嘛,根本没有你位置。
解决方案1
单独做个好看的登录页面,放个按钮。用户一进来,就是登录页面,要他授权。也可以在需要登录的地方,跳转到登录页面,授权了然后再回来。
解决方案2
既然你不就是想要个按钮嘛,给你弹一个好了。只要你需要登录,我就给你弹一个让你给我授权。当然,你弹个登录页面也是一样的。
方案1就不多说了,看看方案2效果图吧。
上面的弹框用的不是wx.showModal()弹框。这个需要自己封装的。
|--components
|--dialog
dialog.js // 弹框组件
dialog.json
dialog.wxml
dialog.wxss
components.js //页面绑定数据、方法的一个类
components.js 代码
class Component {
constructor (options = {}) {
Object.assign(this, {options});
this.__init();
}
/**
* 初始化
*/
__init () {
this.page = getCurrentPages()[getCurrentPages().length - 1];
const setData = this.page.setData.bind(this.page);
//重写setData方法
this.setData = (obj = {}, cb = ()=>({})) => {
const fn = () => {
if (typeof cb === 'function') {
cb();
}
};
setData(obj, fn);
}
this.__initState();
}
/**
* 初始化组件状态
*/
__initState () {
this.options.data && this.__initData();
this.options.methods && this.__initMthods();
}
/**
* 绑定组件数据
*/
__initData () {
const scope = this.options.scope;
const data = this.options.data;
this._data = {};
if (!this.isEmptyObject(data)) {
for (let key in data) {
if (data.hasOwnProperty(key)) {
if (typeof data[key] === 'function') {
data[key] = data[key].bind(this);
} else {
this._data[key] = data[key];
}
}
}
}
// 将数据同步到 page.data 方便组件渲染
this.page.setData({
[`${scope}`]: this._data
});
}
/**
* 绑定组件方法
*/
__initMthods () {
const scope = this.options.scope;
const methods = this.options.methods;
if (!this.isEmptyObject(methods)) {
for (let key in methods) {
if (methods.hasOwnProperty(key) && typeof methods[key] === 'function') {
this[key] = methods[key] = methods[key].bind(this);
//将组件内的方法重命名并挂载到 page 上, 否则 template 上找不到方法
this.page[`${scope}.${key}`] = methods[key];
//将方法同步到 page.data 上,方便 template 使用 {{methods}} 绑定事件
this.page.setData({
[`${scope}.${key}`]: `${scope}.${key}`
});
}
}
}
}
/**
* 获取组件数据
*/
getComponentData () {
let data = this.page.data;
let name = this.options.scope && this.options.scope.split(".");
name.forEach((n,i) => {
data = data[n];
});
return data;
}
/**
* 判断 Object 是否为空
*/
isEmptyObject (e) {
for (let t in e)
return !1
return !0;
}
/**
* 设置元素显示
*/
setVisible () {
this.setData({
[`${this.options.scope}.visible`]: !0
});
}
/**
* 设置元素隐藏
*/
setHidden (timer = 300) {
setTimeout(()=> {
this.setData({
[`${this.options.scope}.visible`]: !1
});
}, timer);
}
}
export default Component;
dialog.js 代码
// components/dialog/dialog.js
import Component from "../component";
export default {
//默认数据
data () {
return {
title: "提示",
content: "提示内容",
showCancel: !0,
cancelText: "取消",
cancelType: "button",
confirmText: "确定",
confirmType: "button",
confrimOpenType: "",
success: () => {
},
fail: () => {
},
complete: () => {
}
}
},
/**
* 创建组件
*/
open (opts = {}) {
const options = Object.assign({
visible: !1
}, this.data(),opts);
const component = new Component({
scope: `myDialog`,
data: options,
methods: {
//隐藏
hide (cb) {
this.setHidden();
setTimeout(() => typeof cb === 'function' && cb());
},
//显示
show () {
this.setVisible();
},
//按钮回调
buttonTapped (e) {
const index = e.currentTarget.dataset.index;
const button = options.buttons[index];
this.hide(() => {
if (options.buttons.length > 1) {
if (index < 1) {
typeof options.fail === `function` && options.fail(e);
}
} else {
typeof options.success === `function` && options.success(e);
}
});
},
//用户信息回调
getUserInfo (e) {
this.hide(() => {
if (e.detail.userInfo) {
// 成功获得用户信息
typeof options.success === `function` && options.success(e);
} else {
// 用户拒绝,走fail方法
typeof options.fail === `function` && options.fail(e);
}
typeof options.complete === `function` && options.complete(e);
});
}
});
component.show();
return component.hide;
},
/**
* 显示弹框
*/
showModal (opts) {
const options = Object.assign({
visible: !1
},this.data(),opts);
let buttons = [];
//声明取消按钮
let cancel_btn = {
text: options.cancelText,
type: options.cancelType,
onTap: (e) => {
options.fail === 'function' && options.fail(e)
}
},
//声明确定按钮
confirm_btn = {
text: options.confirmText,
type: options.confirmType,
openType: options.confirmOpenType,
className: "modal-btn-primary",
onTap: (e) => {
options.success === 'function' && options.success(e);
}
};
//是否显示取消按钮
if (options.showCancel) {
buttons[0] = cancel_btn;
buttons[1] = confirm_btn;
} else {
buttons[0] = confirm_btn;
}
return this.open(Object.assign({buttons}, options));
}
};
dialog.wxml 代码
{{title}}
{{content}}
dialog.wxss 代码
/* components/dialog/dialog.wxss */
.flex {
display: flex;
}
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, .5);
font-size: 0;
text-align: center;
white-space: nowrap;
overflow: auto;
z-index:9999;
}
.modal:after {
content: '';
display: inline-block;
vertical-align: middle;
height: 100%;
}
.dialog {
display: inline-block;
font-size: 14px;
vertical-align: middle;
text-align: left;
white-space: normal;
}
.modal-content {
width: 240px;
height: 145px;
background-color: #fff;
}
.modal-header,
.modal-body{
padding: 15px;
}
.modal-header {
border-bottom: 1px solid #ddd;
}
.modal-footer {
border-top: 1px solid #ddd;
border: 1px solid red;
}
.modal-btn {
display: block;
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
color: #3CC51F;
text-decoration: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
position: relative;
background: #fff;
border-radius: 0;
}
.modal-btn:after {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 2rpx;
bottom: 0;
border-left: 2rpx solid #D5D5D6;
color: #D5D5D6;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scaleX(0.5);
transform: scaleX(0.5);
}
.modal-btn:first-child:after {
display: none;
}
.modal-btn-default {
color: #353535;
}
.modal-btn-primary {
color: #0BB20C;
}
引用组件
在需要弹框的页面(.wxml)引入dialog.wxml模板
直接在app.wxss全局引用dialog.wxss
@import "./components/dialog/dialog.wxss";
对应js文件里面引用dialog.js
import myDialog from '../../../components/dialog/dialog';
//调起组件
myDialog.showModal({
title: "提示",
content: "需要您授权",
confirmOpenType: "getUserInfo", //如果不设置就是普通弹框
success: (e) => {
console.log("e", e);
let userInfo = e.detail.userInfo;
wx.setStorageSync("userInfo", userInfo);
},
fail: (err) => {
// 用户不小必点到拒绝,提示登录失败
wx.showToast({
title: "登录失败",
icon: "none"
});
}
});
这样原来我们用
wx.login({
success: (n) => {
wx.getUserInfo () {
success (e) => {
console.log(e);
}
}
}
});
就可以写成
wx.login({
success: (n) => {
myDialog.showModal({
title: "提示",
content: "需要您授权",
confirmOpenType: "getUserInfo",
success: (e) => {
console.log("e", e);
let userInfo = e.detail.userInfo;
wx.setStorageSync("userInfo", userInfo);
}
});
}
});
总结
写到这里呢,就已经结束了,有两个需要我们注意的细节。一个是,在调起弹框之前,我们先要wx.login(),不然会报错说你还没登录。二个是,如果用户在调起授权框之后,他选择了拒绝。当再次调起授权框,并同意,很可能会提示你code无效,就是已经用过的意思。所以还是要做好处理。
还有在写登录的时候我们可以把登录的逻辑代码封装成一个方法,然后在页面上引用就行。麻烦的是,在需要调起弹框的页面(wxml),我们都要引用dialog.wxml的模板。总的来说吧,这次api的调整还是蛮伤的。核心就是官方给的,看你怎么用了。如果你也喜欢弹弹弹这种方式,可以参考下。
最后附上一个我非常喜欢的大神写的一个小程序组件库: https://github.com/skyvow/wux,里面啥都有哦~