子域index.js代码如下:
import * as Consts from './consts'
const PAGE_SIZE = 6;
const ITEM_HEIGHT = 125;
const dataSorter = (gameDatas, field = Consts.OpenDataKeys.Grade) => {
return gameDatas.sort((a, b) => {
const kvDataA = a.KVDataList.find(kvData => kvData.key === Consts.OpenDataKeys.Grade);
const kvDataB = b.KVDataList.find(kvData => kvData.key === Consts.OpenDataKeys.Grade);
const gradeA = kvDataA ? parseInt(kvDataA.value || 0) : 0;
const gradeB = kvDataB ? parseInt(kvDataB.value || 0) : 0;
return gradeA > gradeB ? -1 : gradeA < gradeB ? 1 : 0;
});
}
class RankListRenderer
{
constructor()
{
this.totalPage = 0;
this.currPage = 0;
this.gameDatas = []; //https://developers.weixin.qq.com/minigame/dev/document/open-api/data/UserGameData.html
this.init();
}
init()
{
this.canvas = wx.getSharedCanvas();
this.ctx = this.canvas.getContext('2d');
this.ctx.imageSmoothingEnabled = true;
this.ctx.imageSmoothingQuality = "high";
}
listen()
{
//msg -> {action, data}
wx.onMessage(msg => {
console.log("ranklist wx.onMessage", msg);
switch(msg.action)
{
case Consts.DomainAction.FetchFriend:
this.fetchFriendData();
break;
case Consts.DomainAction.FetchGroup:
if(!msg.data)
{
return;
}
this.fetchGroupData(msg.data);
break;
case Consts.DomainAction.Paging:
if(!this.gameDatas.length)
{
return;
}
const delta = msg.data;
const newPage = this.currPage + delta;
if(newPage < 0)
{
console.log("已经是第一页了");
return;
}
if(newPage + 1 > this.totalPage)
{
console.log("没有更多了");
return;
}
this.currPage = newPage;
this.showPagedRanks(newPage);
break;
default:
console.log(`未知消息类型:msg.action=${msg.action}`);
break;
}
});
}
fetchGroupData(shareTicket)
{
//取出群同玩成员数据
wx.getGroupCloudStorage({
shareTicket,
keyList:[
Consts.OpenDataKeys.Grade,
],
success:res => {
console.log("wx.getGroupCloudStorage success", res);
const dataLen = res.data.length;
this.gameDatas = dataSorter(res.data);
this.currPage = 0;
this.totalPage = Math.ceil(dataLen / PAGE_SIZE);
if(dataLen)
{
this.showPagedRanks(0);
}
},
fail:res => {
console.log("wx.getGroupCloudStorage fail", res);
},
});
}
fetchFriendData()
{
//取出所有好友数据
wx.getFriendCloudStorage({
keyList:[
Consts.OpenDataKeys.Grade,
],
success:res => {
console.log("wx.getFriendCloudStorage success", res);
const dataLen = res.data.length;
this.gameDatas = dataSorter(res.data);
this.currPage = 0;
this.totalPage = Math.ceil(dataLen / PAGE_SIZE);
if(dataLen)
{
this.showPagedRanks(0);
}
},
fail:res => {
console.log("wx.getFriendCloudStorage fail", res);
},
});
}
showPagedRanks(page)
{
const pageStart = page * PAGE_SIZE;
const pagedData = this.gameDatas.slice(pageStart, pageStart + PAGE_SIZE);
const pageLen = pagedData.length;
this.ctx.clearRect(0, 0, 1000, 1000);
for(let i = 0, len = pagedData.length; i < len; i++)
{
this.drawRankItem(this.ctx, i, pageStart + i + 1, pagedData[i], pageLen);
}
}
//canvas原点在左上角
drawRankItem(ctx, index, rank, data, pageLen)
{
const avatarUrl = data.avatarUrl.substr(0, data.avatarUrl.length - 1) + "132";
const nick = data.nickname.length <= 10 ? data.nickname : data.nickname.substr(0, 10) + "...";
const kvData = data.KVDataList.find(kvData => kvData.key === Consts.OpenDataKeys.Grade);
const grade = kvData ? kvData.value : 0;
const itemGapY = ITEM_HEIGHT * index;
//名次
ctx.fillStyle = "#D8AD51";
ctx.textAlign = "right";
ctx.baseLine = "middle";
ctx.font = "70px Helvetica";
ctx.fillText(`${rank}`, 90, 80 + itemGapY);
//头像
const avatarImg = wx.createImage();
avatarImg.src = avatarUrl;
avatarImg.onload = () => {
if(index + 1 > pageLen)
{
return;
}
ctx.drawImage(avatarImg, 120, 10 + itemGapY, 100, 100);
};
//名字
ctx.fillStyle = "#777063";
ctx.textAlign = "left";
ctx.baseLine = "middle";
ctx.font = "30px Helvetica";
ctx.fillText(nick, 235, 80 + itemGapY);
//分数
ctx.fillStyle = "#777063";
ctx.textAlign = "left";
ctx.baseLine = "middle";
ctx.font = "30px Helvetica";
ctx.fillText(`${grade}分`, 620, 80 + itemGapY);
//分隔线
const lineImg = wx.createImage();
lineImg.src = 'subdomain/images/llk_x.png';
lineImg.onload = () => {
if(index + 1 > pageLen)
{
return;
}
ctx.drawImage(lineImg, 14, 120 + itemGapY, 720, 1);
};
}
}
const rankList = new RankListRenderer();
rankList.listen();
主域:
import {appdata} from './appdata'
import {POP_UI_BASE} from './common/ui/pop_ui_base'
import {pop_mgr, UI_CONFIG} from "./common/ui/pop_mgr"
import {TimerMgr} from "./common/timer/timer_mgr"
import * as utils from "./common/util"
import * as wxapi from "./common/wxapi"
import * as Audio from "./common/audio/audioplayer"
const {ccclass, property} = cc._decorator;
@ccclass
export class RankView2 extends POP_UI_BASE {
@property(cc.Sprite)
img_head: cc.Sprite = null;
@property(cc.Label)
txt_name: cc.Label = null;
@property(cc.Sprite)
img_rank: cc.Sprite = null;
timerId:number;
isDirty:boolean;
rankTexture:cc.Texture2D;
rankSpriteFrame:cc.SpriteFrame;
on_show(...params)
{
const appUserInfo = appdata.appUserInfo;
const wxUserInfo = appdata.wxUserInfo;
const avatarUrl = wxUserInfo.avatarUrl132;
if(avatarUrl.length > 0)
{
this.txt_name.string = wxUserInfo.nickName;
utils.load_external_img(this.img_head, avatarUrl, "png");
}
//只能在主域设置大小, 且要先于赋值到sprite才起作用
const sharedCanvas = wxapi.wxOpenData.wxGetSharedCanvas();
sharedCanvas.width = this.img_rank.node.width;
sharedCanvas.height = this.img_rank.node.height;
this.rankTexture = new cc.Texture2D();
this.rankSpriteFrame = new cc.SpriteFrame();
//拿好友排行榜
this.isDirty = true;
wxapi.wxOpenData.wxPostMessageToSubDomain({
action:wxapi.WxDomainAction.FetchFriend,
});
this.timerId = TimerMgr.getInst().loop(0.1, utils.gen_handler(this.updateRankList, this));
}
on_hide()
{
this.rankTexture = null;
this.rankSpriteFrame = null;
this.isDirty = false;
TimerMgr.getInst().remove(this.timerId);
}
updateRankList()
{
if(!this.isDirty)
{
return;
}
const sharedCanvas = wxapi.wxOpenData.wxGetSharedCanvas();
this.rankTexture.initWithElement(sharedCanvas);
this.rankTexture.handleLoadedTexture();
this.rankSpriteFrame.setTexture(this.rankTexture);
this.img_rank.spriteFrame = this.rankSpriteFrame;
}
onTouchPageBtn(event, delta)
{
this.isDirty = true;
wxapi.wxOpenData.wxPostMessageToSubDomain({
action:wxapi.WxDomainAction.Paging,
data:parseInt(delta),
});
}
onTouchGroupRank()
{
wxapi.wxShare.share({
title:"分享文本",
imageUrl:"shareimg/bg02.png",
query:`openID=${appdata.appUserInfo.openid}`,
}, utils.gen_handler((shareTickets:string[]) => {
if(!shareTickets || !shareTickets.length)
{
console.log('本次分享无shareTicket');
return;
}
const shareTicket = shareTickets[0];
this.isDirty = true;
wxapi.wxOpenData.wxPostMessageToSubDomain({
action:wxapi.WxDomainAction.FetchGroup,
data:shareTicket,
});
}));
}
}
排行榜滑动和翻页
主域:
import * as Consts from "./consts"
import {appdata} from './appdata'
import {POP_UI_BASE} from './common/ui/pop_ui_base'
import {pop_mgr, UI_CONFIG} from "./common/ui/pop_mgr"
import {TimerMgr} from "./common/timer/timer_mgr"
import * as utils from "./common/util"
import * as wxapi from "./common/wxapi"
import * as Audio from "./common/audio/audioplayer"
const {ccclass, property} = cc._decorator;
@ccclass
export class RankView2 extends POP_UI_BASE {
@property(cc.Sprite)
img_rank: cc.Sprite = null;
timerId:number;
isDirty:boolean;
rankTexture:cc.Texture2D;
rankSpriteFrame:cc.SpriteFrame;
on_show(...params)
{
//只能在主域设置大小, 且要先于赋值到sprite才起作用
const sharedCanvas = wxapi.wxOpenData.wxGetSharedCanvas();
sharedCanvas.width = this.img_rank.node.width;
sharedCanvas.height = this.img_rank.node.height;
this.rankTexture = new cc.Texture2D();
this.rankSpriteFrame = new cc.SpriteFrame();
//拿好友排行榜
this.isDirty = true;
wxapi.wxOpenData.wxPostMessageToSubDomain({
action:wxapi.WxDomainAction.FetchFriend,
});
this.timerId = TimerMgr.getInst().loop(0.1, utils.gen_handler(this.updateRankList, this));
this.img_rank.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
}
on_hide()
{
this.rankTexture = null;
this.rankSpriteFrame = null;
this.isDirty = false;
TimerMgr.getInst().remove(this.timerId);
this.img_rank.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
}
onTouchMove(event:cc.Event.EventTouch)
{
const deltaY = event.getDeltaY();
// console.log("rank touchmove:", deltaY);
this.isDirty = true;
wxapi.wxOpenData.wxPostMessageToSubDomain({
action:wxapi.WxDomainAction.Paging,
data:deltaY,
});
}
updateRankList()
{
if(!this.isDirty)
{
return;
}
const sharedCanvas = wxapi.wxOpenData.wxGetSharedCanvas();
this.rankTexture.initWithElement(sharedCanvas);
this.rankTexture.handleLoadedTexture();
this.rankSpriteFrame.setTexture(this.rankTexture);
this.img_rank.spriteFrame = this.rankSpriteFrame;
}
onTouchGroupRank()
{
wxapi.wxShare.share({
title:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
imageUrl:"shareimg/bg02.png",
query:`openID=${appdata.appUserInfo.openid}`,
}, utils.gen_handler((shareTickets:string[]) => {
if(!shareTickets || !shareTickets.length)
{
console.log('本次分享无shareTicket');
return;
}
const shareTicket = shareTickets[0];
this.isDirty = true;
wxapi.wxOpenData.wxPostMessageToSubDomain({
action:wxapi.WxDomainAction.FetchGroup,
data:shareTicket,
});
}));
}
}
子域:
import * as Consts from './consts'
const PAGE_SIZE = 8;
const ITEM_WIDTH = 750;
const ITEM_HEIGHT = 125;
const dataSorter = (gameDatas, field = Consts.OpenDataKeys.Grade) => {
return gameDatas.sort((a, b) => {
const kvDataA = a.KVDataList.find(kvData => kvData.key === Consts.OpenDataKeys.Grade);
const kvDataB = b.KVDataList.find(kvData => kvData.key === Consts.OpenDataKeys.Grade);
const gradeA = kvDataA ? parseInt(kvDataA.value || 0) : 0;
const gradeB = kvDataB ? parseInt(kvDataB.value || 0) : 0;
return gradeA > gradeB ? -1 : gradeA < gradeB ? 1 : 0;
});
}
class RankListRenderer {
constructor() {
this.offsetY = 0;
this.maxOffsetY = 0;
this.gameDatas = []; //https://developers.weixin.qq.com/minigame/dev/document/open-api/data/UserGameData.html
this.init();
}
init() {
this.canvas = wx.getSharedCanvas();
this.ctx = this.canvas.getContext('2d');
this.ctx.imageSmoothingEnabled = true;
this.ctx.imageSmoothingQuality = "high";
}
listen() {
//msg -> {action, data}
wx.onMessage(msg => {
//console.log("ranklist wx.onMessage", msg);
switch (msg.action) {
case Consts.DomainAction.FetchFriend:
this.fetchFriendData();
break;
case Consts.DomainAction.FetchGroup:
if (!msg.data) {
return;
}
this.fetchGroupData(msg.data);
break;
case Consts.DomainAction.Paging:
if (!this.gameDatas.length) {
return;
}
const deltaY = msg.data;
const newOffsetY = this.offsetY + deltaY;
if (newOffsetY < 0) {
// console.log("前面没有更多了");
return;
}
if (newOffsetY + PAGE_SIZE * ITEM_HEIGHT > this.maxOffsetY) {
// console.log("后面没有更多了");
return;
}
this.offsetY = newOffsetY;
this.showRanks(newOffsetY);
break;
default:
console.log(`未知消息类型:msg.action=${msg.action}`);
break;
}
});
}
fetchGroupData(shareTicket) {
//取出群同玩成员数据
wx.getGroupCloudStorage({
shareTicket,
keyList: [
Consts.OpenDataKeys.Grade,
],
success: res => {
console.log("wx.getGroupCloudStorage success", res);
const dataLen = res.data.length;
this.gameDatas = dataSorter(res.data);
this.offsetY = 0;
this.maxOffsetY = dataLen * ITEM_HEIGHT;
if (dataLen) {
this.showRanks(0);
}
},
fail: res => {
console.log("wx.getGroupCloudStorage fail", res);
},
});
}
fetchFriendData() {
//取出所有好友数据
wx.getFriendCloudStorage({
keyList: [
Consts.OpenDataKeys.Grade,
],
success: res => {
console.log("wx.getFriendCloudStorage success", res);
const dataLen = res.data.length;
this.gameDatas = dataSorter(res.data);
this.offsetY = 0;
this.maxOffsetY = dataLen * ITEM_HEIGHT;
if (dataLen) {
this.showRanks(0);
}
},
fail: res => {
console.log("wx.getFriendCloudStorage fail", res);
},
});
}
showRanks(offsetY) {
const startY = offsetY % ITEM_HEIGHT;
const startIndex = Math.floor(offsetY / ITEM_HEIGHT);
const stopIndex = startIndex + PAGE_SIZE + (startY == 0 ? 0 : 1);
const datas = this.gameDatas.slice(startIndex, stopIndex);
this.ctx.clearRect(0, 0, 1000, 1000);
for (let i = 0, len = datas.length; i < len; i++) {
this.drawRankItem(this.ctx, i, startIndex + i + 1, datas[i], startY, this.offsetY);
}
}
drawAvatar(ctx, avatarUrl, x, y, w, h, cb) {
avatarUrl = avatarUrl.substr(0, avatarUrl.lastIndexOf('/')) + "/132";
ctx.fillStyle = "#ffffff";
ctx.fillRect(x - 5, y - 5, w + 10, h + 10);
const avatarImg = wx.createImage();
avatarImg.src = avatarUrl;
avatarImg.onload = () => {
cb(avatarImg);
};
}
//canvas原点在左上角
drawRankItem(ctx, index, rank, data, startY, prevOffsetY) {
const nick = data.nickname.length <= 10 ? data.nickname : data.nickname.substr(0, 10) + "...";
const kvData = data.KVDataList.find(kvData => kvData.key === Consts.OpenDataKeys.Grade);
const grade = kvData ? kvData.value : 0;
const itemGapY = ITEM_HEIGHT * index - startY;
//背景颜色
if (rank % 2 == 1) {
ctx.fillStyle = "#FBF7E4";
ctx.fillRect(0, itemGapY, ITEM_WIDTH, ITEM_HEIGHT);
}
//名次
if (rank < 4) {
const rankImg = wx.createImage();
rankImg.src = `subdomain/images/llk_phb_icon${rank}.png`;
rankImg.onload = () => {
if(prevOffsetY == this.offsetY) {
ctx.drawImage(rankImg, 55, 30 + itemGapY, 78, 82);
}
};
} else {
ctx.fillStyle = "#BDBDBD";
ctx.textAlign = "right";
ctx.baseLine = "middle";
ctx.font = "50px Helvetica";
ctx.fillText(`${rank}`, 100, 80 + itemGapY);
}
//头像
const avatarX = 125;
const avatarY = 25 + itemGapY;
const avatarW = 80;
const avatarH = 80;
this.drawAvatar(ctx, data.avatarUrl, avatarX, avatarY, avatarW, avatarH, (avatarImg) => {
if(prevOffsetY == this.offsetY) {
ctx.drawImage(avatarImg, avatarX, avatarY, avatarW, avatarH);
}
})
//名字
ctx.fillStyle = "#777063";
ctx.textAlign = "left";
ctx.baseLine = "middle";
ctx.font = "30px Helvetica";
ctx.fillText(nick, 220, 80 + itemGapY);
//分数
ctx.fillStyle = "#777063";
ctx.textAlign = "left";
ctx.baseLine = "middle";
ctx.font = "30px Helvetica";
ctx.fillText(`${grade}分`, 620, 80 + itemGapY);
}
}
const rankList = new RankListRenderer();
rankList.listen();
上面都是在论坛上看到的,最近自己也是再写排行榜,所以整理一下,防止自己忘记