这几天在封装canvas,想弄成比较好开发的自用框架。
其实就是两个页面,点一下开始游戏,进入游戏,点一下结束,退出游戏,回到开始页面。(说白了,就是事件监听和页面切换)
我在第一次点击的时候,一切正常,正常跳转到了游戏主页面。我点退出的时候,也正常,回到了主页。
然后我多点了几次,忽然发现,日志打印了3次,也就是说触发了3次,接着8次,21次,离了个大谱,点了几次之后,100多次了。再点几次估计能上千。
然后就这么简单两个按钮跳转,直接让页面卡死。
底下的console里能看到,后面多点击一下,打印的日志乌拉拉几何级上升。
代码结构如下,就用红框的五个文件:
game.js里的直接调用new test(),会在test.js和test2.js来回跳转,模拟两个页面。
我上传一下完整代码吧:
test.js
import buttonSprite from './base/buttonSprite'
import Point2d from './base/point2d'
import test2Page from './test2'
let ctx = canvas.getContext('2d')
let gamesPage =0;
//精灵摆放
const arr = [
{x:100, y:390, width:100, height:50,name:'开始',color:'green',image:"images/start.png",funName:"start"},//退出
]
let i=0;
let limit = 1;
export default class test{
constructor() {
document.body.innerHTML="";//清空所有内容
// this.init();//数据初始化
console.log("进入开始页面!-----")
// console.log("数组:"+this.allShapes);
this.draw()
}
start(){
let test2 = new test2Page();
}
draw(){
ctx.fillStyle = "#f5f5f5";
// ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
let i = 0;
let startButton = new buttonSprite(arr[i].x,arr[i].y,arr[i].width,arr[i].height,arr[i].name,arr[i].funName);
startButton.drawToCanvas(ctx,arr[i].image);
this.allShapes=[];
this.allShapes.push(startButton);
canvas.addEventListener('touchend', this.handleTestEvent('touchend'),false)//目前一个canvas就监听所有按钮了
}
getNewEvent(event) {
let touchX = event.changedTouches[0].clientX;
let touchY = event.changedTouches[0].clientY;
let point = new Point2d(touchX, touchY)
return { point, isStopBubble: false, ...event, }
}
handleTestEvent = (name) => (event) => {
// event.stopPropagation();
event = this.getNewEvent(event)
this.allShapes.forEach((shape) => { // 获取当前事件的所有监听者 ,遍历每个形状
// const listerns = shape.listenerMap.get(name)
if (
shape.isPointInClosedRegion(event.point.x,event.point.y) //判断点击落在对应的图形内,则触发事件
&& (!event.isStopBubble)
)
{
console.log("命中shape:"+shape)
this.callMethodOnFunctionName(shape.functionName,[1]);//执行对应函数
}
})
}
//挨个判断是什么函数……暂时没法写成反射
callMethodOnFunctionName(functionName,arg) {
// 使用 Function 构造函数创建一个新的函数
let newFunction = new Function(functionName);
switch(functionName){
case "start":
this.start();
break;
case "showList":
this.showList(arg);
break;
case "clearStor":
this.clearStor(arg);
break;
}
}
}
test2.js
import buttonSprite from './base/buttonSprite'
import Point2d from './base/point2d'
import testPage from './test'
let ctx = canvas.getContext('2d')
//精灵摆放
const arr = [
{x:200, y:90, width:100, height:50,name:'退出',color:'green',image:"images/exit.png",funName:"exit"},//退出
//{x:100, y:200, width:100, height:50,name:'开始游戏',color:'green',image:"images/startBtn2.png",funName:"startGame"},//开始
// {x:100, y:260, width:100, height:50,name:'排行榜',color:'blue',image:"images/paihangbang.png",funName:"showList"},//排行榜
// {x:100, y:320, width:100, height:50,name:'清除缓存',color:'red',image:"images/clearStorage.png",funName:"clearStor"},//清除缓存
]
export default class test{
init(){
// this.i = 0;
//精灵摆放
this.arr = [
{x:200, y:90, width:100, height:50,name:'退出',color:'green',image:"images/exit.png",funName:"exit"},//退出
]
// this.gamesPage =0;
}
constructor() {
document.body.innerHTML="";//清空所有内容
this.draw()
}
exit(){
let test = new testPage(0);
}
draw(){
ctx.fillStyle = "#f5f5f5";
// ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
let i = 0;
let exitButton = new buttonSprite(arr[i].x,arr[i].y,arr[i].width,arr[i].height,arr[i].name,arr[i].funName);
exitButton.drawToCanvas(ctx,arr[i].image);
this.allShapes=[];
// if()
this.allShapes.push(exitButton);
canvas.addEventListener('touchend', this.handleEvent('touchend'),true)//目前一个canvas就监听所有按钮了
}
getNewEvent(event) {
let touchX = event.changedTouches[0].clientX;
let touchY = event.changedTouches[0].clientY;
let point = new Point2d(touchX, touchY)
return { point, isStopBubble: false, ...event, }
}
handleEvent = (name) => (event) => {
// event.stopPropagation();
event = this.getNewEvent(event)
this.allShapes.forEach((shape) => { // 获取当前事件的所有监听者 ,遍历每个形状
// const listerns = shape.listenerMap.get(name)
if (
shape.isPointInClosedRegion(event.point.x,event.point.y)
&& (!event.isStopBubble)
)
{
console.log("命中shape"+shape)
this.callMethodOnFunctionName(shape.functionName,[1]);//执行对应函数
}
})
}
//挨个判断是什么函数……暂时没写成反射
callMethodOnFunctionName(functionName,arg) {
// 使用 Function 构造函数创建一个新的函数
let newFunction = new Function(functionName);
switch(functionName){
case "exit":
this.exit();
break;
case "showList":
this.showList(arg);
break;
case "clearStor":
this.clearStor(arg);
break;
}
}
}
base文件夹下的buttonSprite.js
let x = 0;
let y = 0;
let width = 0;
let height = 0;
let name="按钮";
let leftTop={x:0,y:0};
/**
* 游戏基础的精灵类
*/
export default class buttonSprite {
constructor( x, y, width, height,name,functionName) {
this.name = name
this.functionName = functionName
this.x = x
this.y = y
this.leftTop = { x, y }
leftTop = { x, y }
this.width = width
this.height = height
this.visible = true
this.listenerMap = new Map()
this.props = {leftTop, width,height}
}
on(eventName, listener) {
console.log("hey,wobeidiaoyongle,jingguolew")
if (this.listenerMap.has(eventName)) {
this.listenerMap.get(eventName).push(listener)
} else {
this.listenerMap.set(eventName, [listener])
}
}
/**
* 将精灵图绘制在canvas上
*/
drawToCanvas(ctx,imgSrc) {
if ( !this.visible )
return
let img = new Image();
let x = this.x;
let y = this.y;
let width = this.width;
let height = this.height;
img.onload = function(){
ctx.drawImage(
img,
x,
y,
width,
height
)}
img.src = imgSrc;//先onload再给出src
}
callMethodOnFunctionName() {
// 使用 Function 构造函数创建一个新的函数
const newFunction = new Function(this.functionName);
// 使用 apply 方法调用传递的函数
newFunction.apply(this, [this]);
}
// 判断鼠标的点是否在图形内部
isPointInClosedRegion(touchX,touchY) {
// const { x, y } = mouse.point
const { leftTop, width, height } = this.props
const { x: minX, y: minY } = leftTop
const maxX = minX + width
const maxY = minY + height
if (touchX >= minX && touchX <= maxX && touchY >= minY && touchY <= maxY) {
return true
}
return false
}
}
base 文件夹下的point2d.js
export default class point2d {
constructor(x,y) {
this.x = x || 0;
this.y = y || 0;
}
clone() {
return this.constructor(this.x, this.y);
}
add(v) {
this.x += v.x;
this.y += v.y
return this;
}
random() {
this.x = Math.random() *1800;
this.y = Math.random() * 800;
return this
}
}
入口文件:game.js
import './js/libs/weapp-adapter'
import './js/libs/symbol'
import test from './js/test'
new test()
退出后按钮没销毁(回收),再进入后又重新生成了新的按钮