CocosCreator 不支持 js async await ,需要去 Github 上下载 runtime 环境,将其中 runtime.js 放置到最外层 require 一下就好了。
rutime 获取地址 https://github.com/facebook/regenerator
Klass 语法糖 来自《JavaScript 模式》P132。没有使用CocosCreator自带的cc.Class 便于迁移。
直接上代码。
Klass.js
var Klass = function (Parent_,props_){
var _ChildKlass,_F,_idx;
_ChildKlass=function () {
if(_ChildKlass.prototype.hasOwnProperty("__construct")){
_ChildKlass.prototype.__construct.apply(this,arguments);
}
};
Parent_=Parent_||Object;
_F=function(){};
_F.prototype=Parent_.prototype;
_ChildKlass.prototype = new _F();
_ChildKlass.uber = Parent_.prototype;
_ChildKlass.prototype.construct = _ChildKlass;
for(_idx in props_){
if(props_.hasOwnProperty(_idx)){
_ChildKlass.prototype[_idx]=props_[_idx];
}
}
return _ChildKlass
}
module.exports = Klass;
Base.js
var isString = function(maybeStr_){
if(typeof(maybeStr_) == "string"){
return true;
}else{
if(Object.prototype.toString.call(maybeStr_) == "[object String]"){
return true;
}
}
return false;
};
var Klass = require("Klass");
var Base =Klass(null,{__construct:function(className_){this.ctor(className_)},
ctor : function(className_){
if (!className_){
console.error("ERROR Base 没有类名");
}
if(!isString(className_)){
console.error("ERROR Base 类名不是字符串");
}
this.className = className_;
},
destory:function(){
},
})
module.exports = Base;
KeyValueStack.js
var Klass = require("Klass");
var KeyValueStack =Klass(require("Base"),{__construct:function(...args){this.ctor(...args);},
stack:[],
ctor : function(){
KeyValueStack.uber.ctor.call(this,"KeyValueStack");
},
pushStack:function(key_, value_) {
this.stack.push({key:key_,value:value_})
},
pullStack:function(){
if (this.stack.length > 0){
return this.stack.shift();
}
return null;
},
});
module.exports = KeyValueStack;
EventDispatcher.js
var Klass = require("Klass");
var EventDispatcher = Klass(require("Base"),{__construct:function(...args){this.ctor(...args);},
listeners : [],
ctor : function(){
EventDispatcher.uber.ctor.call(this,"EventDispatcher");
},
on : function (key_, callback_, target_) {
if(!(key_ in this.listeners)) {
this.listeners[key_] = [];
}
this.listeners[key_].push({callback:callback_,target:target_});
},
off : function(key_, callback_, target_) {
if(!(key_ in this.listeners)){
return;
}
let _stack = this.listeners[key_];
for(let _idx = 0, _len = _stack.length; _idx < _len; _idx++) {
let _element = _stack[_idx];
if( _element.callback === callback_ && ((_element.target === target_)||(null == target_ && _element.target == target_))){
_stack.splice(_idx, 1);
_idx--;
_len--;
}
}
},
dispatch : function (key_, value_) {
if(!(key_ in this.listeners)) {
return;
}
let _stack = this.listeners[key_];
for(let _idx = 0, _len = _stack.length; _idx < _len; _idx++) {
let _element = _stack[_idx];
_element.callback.call(_element.target, value_);
}
},
});
module.exports = EventDispatcher;
WxUtils.js
/*
非同步
{
funcName:"调用方法名",
isSuccess:true,//是否成功
successData:{},//成功时的数据
failData:{},//失败时的数据
retryTimes:0,//重试次数
}
同步
{
funcName:"调用方法名",
data:{},//API获取到的数据
...//其他参数
}
//微信Api的结果作为消息分发。把一个SDK当做一个服务器来处理。
WxUtils.on("login",this.onLogin,this);
function onLogin(data_){
console.log(data_.funcName == "login");//true
if(data_.isSuccess){
let _wxCode = data_.successData.code;
//其他操作。
}
}
//提供需要授权的连续操作的建议API
//如登陆,网路图片保存到相册
*/
require("runtime");
var Klass = require("Klass");
var KeyValueStack = require("KeyValueStack");
var EventDispatcher = require("EventDispatcher");
var WxUtils =Klass(require("Base"),{__construct:function(...args){this.ctor(...args);},
keyValueStack : new KeyValueStack(),//键值对堆
eventDispatcher : new EventDispatcher(),//事件分发器
lastHideTime : 0,//上一次onHide的时间
transparentButtonDict : {},//透明按钮缓存
ctor : function(){
WxUtils.uber.ctor.call(this,"WxUtils");
},
on : function(key_, callback_, target_) { //添加监听
this.eventDispatcher.on(key_, callback_, target_);
},
off : function(key_, callback_, target_) { //移除监听
this.eventDispatcher.off(key_, callback_, target_);
},
dispatchAll : function(){ //分发所有事件
let _keyValueDict = this.keyValueStack.pullStack();
while(_keyValueDict){
this.eventDispatcher.dispatch(_keyValueDict.key,_keyValueDict.value);
_keyValueDict = this.keyValueStack.pullStack();
}
},
update : function(){//帧更新
this.dispatchAll();
},
//创建透明按钮挡在给定的按钮节点上方,这个按钮节点是居中对齐的容器中的第一层级元素。
// btnType_
// createUserInfoButton 创建用户信息 ,这个时,会多两个参数 withCredentials_,lang_
// https://developers.weixin.qq.com/minigame/dev/api/open-api/user-info/wx.createUserInfoButton.html
// createFeedbackButton 创建反馈信息
// https://developers.weixin.qq.com/minigame/dev/api/open-api/feedback/wx.createFeedbackButton.html
createBtn:function (btnNode_, btnType_, key_, clickFunc_,withCredentials_,lang_) {
if (btnType_ != "createUserInfoButton" && btnType_ != "createFeedbackButton"){
console.log("按钮必须是 createUserInfoButton 或 createFeedbackButton 中的一个");
return;
}
var _authBtn = this.transparentButtonDict[key_];//根据 key_ 缓存,下次使用不需要再次创建。
if(_authBtn){
_authBtn.show();
}else{
var btnSize = cc.size(btnNode_.width + 10, btnNode_.height + 10);
var frameSize = cc.view.getFrameSize();
var winSize = cc.director.getWinSize();
var left = (winSize.width * 0.5 + btnNode_.x - btnSize.width * 0.5) / winSize.width * frameSize.width;
var top = (winSize.height * 0.5 - btnNode_.y - btnSize.height * 0.5) / winSize.height * frameSize.height;
var width = btnSize.width / winSize.width * frameSize.width;
var height = btnSize.height / winSize.height * frameSize.height;
var btnInfo = { type: 'text', text: '',
style: {//全部必填项
left: left,top: top,width: width,height: height,lineHeight: 0,
backgroundColor: '',color: '#ffffff',textAlign: 'center',
fontSize: 1,borderRadius: 1
}
};
if (btnType_ == "createUserInfoButton"){
if (withCredentials_){
btnInfo.withCredentials = true;
}
if (lang_){
btnInfo.lang = lang_;
}
}
_authBtn = wx[btnType_](btnInfo);
this.transparentButtonDict[key_] = _authBtn;
}
_authBtn.onTap((res_) => {
clickFunc_(res_); //res_ 在 createUserInfoButton 的情况下,是用户信息。
_authBtn.hide();
});
return _authBtn;//_authBtn.hide(); 隐藏的实际交给具体代码。有可能不点击按钮,也要隐藏。
},
//创建一个按钮,等待点击
createBtnPromise:function(btnNode_, btnType_, key_, withCredentials_, lang_){
return new Promise((resolve_)=> {
this.createBtn(btnNode_, btnType_, key_, (res_)=>{
resolve_(res_);//返回信息
},withCredentials_,lang_);
});
},
onNetworkStatusChange : function(){
wx.onNetworkStatusChange((data_)=>{
this.keyValueStack.pushStack("onNetworkStatusChange",{
funcName:"onNetworkStatusChange",
data:data_
});
});
},
showToast : function(title_,lastTime_){
wx.showToast({title: title_,duration: lastTime_});
},
onShow : function(){
wx.onShow((data_)=>{
let _showTime = Date.parse(new Date())/1000;
this.keyValueStack.pushStack("onShow",{
funcName:"onShow",
diffTimeInSecond:_showTime - this.lastHideTime,
data:data_
});
this.lastHideTime = 0;
});
},
onHide : function(){
wx.onHide((data_)=>{
this.lastHideTime = Date.parse(new Date())/1000;
this.keyValueStack.pushStack("onHide",{
funcName:"onHide",
data:data_
});
});
},
//https://developers.weixin.qq.com/minigame/dev/api/base/app/life-cycle/wx.getLaunchOptionsSync.html
getLaunchOptionsSync : function(){//登陆参数同步
let _data = wx.getLaunchOptionsSync();
this.keyValueStack.pushStack("getLaunchOptionsSync",{funcName:"getLaunchOptionsSync",isSuccess:true,successData:_data});
return _data;
},
//同步方法
//getNetworkType -> https://developers.weixin.qq.com/minigame/dev/api/device/network/wx.getNetworkType.html
//getSetting -> https://developers.weixin.qq.com/minigame/dev/api/open-api/setting/wx.getSetting.html
//getSystemInfo -> https://developers.weixin.qq.com/minigame/dev/api/base/system/system-info/wx.getSystemInfo.html
//getUserInfo -> https://developers.weixin.qq.com/minigame/dev/api/open-api/user-info/wx.getUserInfo.html
//getClipboardData -> https://developers.weixin.qq.com/minigame/dev/api/device/clipboard/wx.getClipboardData.html
//authorize -> https://developers.weixin.qq.com/minigame/dev/api/open-api/authorize/wx.authorize.html
//request -> https://developers.weixin.qq.com/minigame/dev/api/network/request/wx.request.html
//downloadFile -> https://developers.weixin.qq.com/minigame/dev/api/network/download/wx.downloadFile.html
//saveImageToPhotosAlbum -> https://developers.weixin.qq.com/minigame/dev/api/media/image/wx.saveImageToPhotosAlbum.html
//login -> https://developers.weixin.qq.com/minigame/dev/api/open-api/login/wx.login.html
getFuncAwait : function(funcName_,requestData_ = {} , needLoadingStr_ = null , retryTimes_ = 0){
return new Promise((resolve_)=> {
this.getFunc(funcName_,requestData_,needLoadingStr_,retryTimes_,resolve_);
});
},
//非同步get类封装,
getFunc : function(funcName_,requestData_ = {} , needLoadingStr_ = null , retryTimes_ = 0,resolve_ = null){
let _isSuccess = false;//是否成功执行
let _successData = null;
let _failData = null;
if (needLoadingStr_){
wx.showLoading({title: needLoadingStr_,mask: true});
}
let _success = (args_)=>{
console.log("WxMain : " + funcName_ + " success : ",args_);
_isSuccess = true;
_successData = args_;
};
let _fail = (args_)=>{
console.log("WxMain : " + funcName_ + " fail : ",args_);
_isSuccess = false;
_failData = args_;
};
let _complete = (args_)=>{
console.log("WxMain : " + funcName_ + " complete : ",args_);
if (retryTimes_ > 0 && !_isSuccess){
retryTimes_--;
wx[funcName_](requestData_);//第N次访问微信
}else{
let _value = {funcName:funcName_,retryTimes:retryTimes_,isSuccess:_isSuccess,successData:_successData,failData:_failData};
this.keyValueStack.pushStack(_value.funcName,_value);
if (needLoadingStr_){
wx.hideLoading();
}
if (resolve_){// 作为 await 内调用的方法,有这个参数。
resolve_(_value);
}
}
};
requestData_.success = _success;
requestData_.fail = _fail;
requestData_.complete = _complete;
wx[funcName_](requestData_);//第一次访问微信
},
/*
subscribeInfoList_ 元素格式
[
{
key:"Key",//字符串键,用来简易标示提示项
id:"SPCJOSAMGSMVKSNHWTUJTEOMSCOAPOFSAGJAOEWJMGK",//后台填写的id
title:"提示授权标题",//提示授权时的文字
triggered:false,//是否提示过授权
},
...
]
*/
initSubscribeMessage:function(subscribeInfoList_){
this.subscribeInfoList = subscribeInfoList_;
},
/*
WxUtils.subscribeMessage(["Key","Key1","Key2"]).then((acceptKeyList_)=>{
console.log(acceptKeyList_);
});
*/
subscribeMessage:async function(keyOrKeyList_) {
if(!this.subscribeInfoList){
console.error("订阅相关的授权,先要调用 initSubscribeMessage 设置项目");
}
//通过key的指定获取实际的id
let _idList = [];
if(keyOrKeyList_ == "ALL" || keyOrKeyList_[0] == "ALL"){ // 键为全部的时候,所有的都提示
this.subscribeInfoList.forEach((subscribeInfo_)=>{
if(subscribeInfo_.triggered == false){
_idList.push(subscribeInfo_.id);
subscribeInfo_.triggered = true;
}
});
}else{//给定几个或者一个的时候,只提示给定的
let _keyList = null;
if(Array.isArray(keyOrKeyList_)){
_keyList = keyOrKeyList_;
}else{
_keyList = [keyOrKeyList_];
}
_keyList.forEach((key_)=>{
this.subscribeInfoList.some((subscribeInfo_)=>{
if(subscribeInfo_.triggered == false && key_ == subscribeInfo_.key){
_idList.push(subscribeInfo_.id);
subscribeInfo_.triggered = true;
return true;//some 返回 true 打断 some 的循环
}
});
});
}
if (_idList.length > 0){//需要提示的id列表。大于零,证明有需要提示的
let _retryTimes = 3;
let _result = null;
_result = await this.getFuncAwait("requestSubscribeMessage",{tmplIds: _idList},"用户授权订阅",0);//用户操作,0次重试
if(!_result.isSuccess){
this.showToast("取消订阅授权",1000);
return null;
}
let _acceptKeyList = [];
_idList.forEach((id_)=>{
if (isSuccess.successData[id_] == 'accept') {
this.subscribeInfoList.some((subscribeInfo_)=>{
if(subscribeInfo_.id == id_){
_acceptKeyList.push(subscribeInfo_.key);
return true;//some 返回 true 打断 some 的循环
}
});
}
});
if(_acceptKeyList.length > 0){//有同意的,将同意的列表传递回去
return _acceptKeyList;
}else{//一个都没同意
return null;
}
}else{//给定的键,当前运行时都提示用户授权了
return null;
}
},
/*
WxUtils.loginAndGetUserInfo().then((loginAndUser_)=>{
console.log(loginAndUser_);
});
*/
loginAndGetUserInfo:async function(userInfoBtnNode_,withCredentials_,lang_){
if(userInfoBtnNode_.active){
console.warn("用户授权按钮的显示由后续判断决定,这里会强制设置成false");
userInfoBtnNode_.active = false;
}
let _retryTimes = 3;
let _result = null;
_result = await this.getFuncAwait("login",{},"用户登录",_retryTimes);
if(!_result.isSuccess){
this.showToast("用户登录失败",1000);
return null;
}
let _loginData = _result.successData;
_result = await this.getFuncAwait("getSetting",{},"获取授权信息",_retryTimes);
if(!_result.isSuccess){
this.showToast("获取授权信息失败",1000);
return null;
}
let _userData = null;
if(!_result.successData.authSetting['scope.userInfo']){//并未授权用户信息
userInfoBtnNode_.active = true;
_userData = await this.createBtnPromise(userInfoBtnNode_,"createUserInfoButton","GETUSERINFO",null,withCredentials_,lang_);//点击授权按钮
userInfoBtnNode_.active = false;
if (_userData.encryptedData && _userData.iv) {
this.showToast("授权成功",1000);
} else {
this.showToast("未授权",1000);
return null;
}
}else{
_result = await this.getFuncAwait("getUserInfo",{withCredentials: withCredentials_,lang:lang_},"获取用户信息",_retryTimes);
if(!_result.isSuccess){
this.showToast("获取用户信息失败",1000);
return null;
}
_userData = _result.successData;
}
if(_userData){//返回的是 登陆成功返回数据 和 用户信息。
return { login:_loginData, user:_userData};
}else{
this.showToast("登陆授权失败",1000);
return null;
}
},
//保存图片到相册
/*
WxUtils.downloadImageToPhotosAlbum("https://xxxxx.png").then((successBool_)=>{
console.log(successBool_);
});
*/
downloadImageToPhotosAlbum : async function(imageUrl_){
let _retryTimes = 3;
let _result = null;
_result = await this.getFuncAwait("getSetting",{},"获取授权信息",_retryTimes);
if(!_result.isSuccess){
this.showToast("获取授权信息失败",1000);
return false;
}
if(!_result.successData.authSetting['scope.writePhotosAlbum']){//未授权过
_result = await this.getFuncAwait("authorize",{scope: 'scope.writePhotosAlbum'},"授权相册",_retryTimes);
if(!_result.isSuccess){
this.showToast("授权相册失败",1000);
return false;
}
}
_result = await this.getFuncAwait("downloadFile",{
url:imageUrl_,
filePath: wx.env.USER_DATA_PATH + '/' + new Date().valueOf() + ".png",
},"下载图片中",_retryTimes);
if(!_result.isSuccess){
this.showToast("图片下载失败",1000);
return false;
}
let _tempFilePath = _result.successData.filePath;
_result = await this.getFuncAwait("saveImageToPhotosAlbum",{filePath:_tempFilePath},"保存图片中",_retryTimes);
if(!_result.isSuccess){
this.showToast("保存图片失败",1000);
return false;
}
return true;
},
});
module.exports = WxUtils;
没经过测试,相信你我都是复制粘贴胡编乱造的高手