If you're seeing this message, it means we're having trouble loading external resources on our website.

如果你被网页过滤器挡住,请确保域名*.kastatic.org*.kasandbox.org 没有被阻止.

主要内容

按钮函数

如果你上过 JS 的入门课程,那你应该已经在逻辑挑战 你的第一个按钮智能按钮 中制作了一些简单的按钮。如果你忘记了,我们就一起复习一下如何制作一个简单的按钮。
首先,按钮的基本特征是什么?
  1. 画布上的一个形状(通常是一个矩形)
  2. 包括一个标签或图标,用来描述它的作用
  3. 响应用户的点击(但不在其他地方)
我们可以很容易地实现特征 #1 和 #2:
fill(0, 234, 255);
rect(100, 100, 150, 50, 5);
fill(0, 0, 0);
textSize(19);
text("无用的按钮", 110, 133);
想要实现特征 #3, 我们需要定义一个 mouseClicked 函数,当用户单击时就调用这个函数,并且在函数中,我们需要检查 mouseXmouseY 是否在按钮的边框内。对于上面的按钮, 它的范围是从 x=100 到 x=250,从 y=100 到 y=150,如下图所示:
我们可以用 && 连接四个条件来检查这些坐标:
mouseClicked = function() {
    if (mouseX >= 100 && mouseX <= 250 &&
        mouseY >= 100 && mouseY <= 150) {
        println("仍然没什么用");    
    }
};
尝试点击它,并松开鼠标,来验证它是否有效:
它确实有效,但也让我担心。我担心它不具有很好的可重用性。如果我想改变按钮的位置,我需要做什么?(在上面试试看!)我在代码中看到了很多“硬编码”的数字——比如 mouseClicked 函数中的坐标,我就立即开始怀疑是否有更简单的方法。
首先,让我们创建位置和大小的变量,这样我们就可以在一个地方更改它们,并且实现单击按钮后的效果。我在下面的程序中添加了 btnXbtnYbtnWidthbtnHeight 。尝试改变它们的值,然后单击按钮:
这样就更好了。但是,如果我想添加一个额外的按钮,我还需要做什么呢?我需要把上面所有的代码复制粘贴,然后再创建 btn2X, btn2Y?呃,听起来一点都不好玩。这给了我们动力去写一个函数来处理对于所有按钮都相同的事情,并使用参数来处理不同的事情。我们可以把变量改为参数:
var drawButton = function(btnX, btnY, btnWidth, btnHeight) {
    fill(0, 234, 255);
    rect(btnX, btnY, btnWidth, btnHeight, 5);
    fill(0, 0, 0);
    textSize(19);
    textAlign(LEFT, TOP);
    text("无用的按钮", btnX+10, btnY+btnHeight/4);
};
然后可以这样调用它:
drawButton(100, 100, 150, 50);
但是,我们 mouseClicked 的代码呢?你看出来问题出在哪里了吗?
mouseClicked = function() {
    if (mouseX >= btnX && mouseX <= (btnX+btnWidth) &&
        mouseY >= btnY && mouseY <= (btnY+btnHeight)) {
        println("仍然没什么用");    
    }
};
如果我们把所有这些代码放在一起,检错小帮手会提示一个错误,“btnX没有定义”——他是对的!我们将 btnX 转换为一个函数的参数,这表示它不再是一个全局变量。这提升了 drawButton 函数的可重用性,但是现在 mouseClicked 函数无法得到要检查的坐标。
因此,我们需要找到一种合适的方式来将信息传递到 drawButton并且将这些信息提供给 mouseClicked。我想到了一些方法:
  1. 重新引入位置和大小的全局变量(btnX, btnY, btnWidth, btnHeight
  2. 引入一个全局数组来存储所有参数(var btn1 = [...];
  3. 引入一个全局对象来存储参数(var btn1 = {..}
  4. 使用面向对象原则定义按钮并存储属性(var btn1 = new Button(...))
选择哪一个?我不喜欢第一种,因为我们需要添加太多的全局变量,我对全局变量过敏。我不喜欢第二种方法,因为读取基于数组索引抓取数据的代码可读性很差。我喜欢第三种方法,因为它只引入了一个全局变量,代码也具有更好的可读性。我也喜欢第四种方法,使用面向对象的原则来创建通用的 Button 对象类型,但是让我们等一会儿再实现这种方法。
我们可以像这样创建全局 btn1 对象:
var btn1 = {
    x: 100,
    y: 100,
    width: 150,
    height: 50
};
然后改变 drawButton 函数以接受一个对象,并从该对象中抓取属性:
var drawButton = function(btn) {
    fill(0, 234, 255);
    rect(btn.x, btn.y, btn.width, btn.height, 5);
    fill(0, 0, 0);
    textSize(19);
    textAlign(LEFT, TOP);
    text("无用的按钮", btn.x+10, btn.y+btn.height/4);
};
mouseClicked 函数将检查全局变量的属性:
mouseClicked = function() {
    if (mouseX >= btn1.x && mouseX <= (btn1.x+btn1.width) &&
        mouseY >= btn1.y && mouseY <= (btn1.y+btn1.height))     {
        println("仍然没什么用");    
    }
};
在下面试一试!像之前一样,尝试改变按钮的不同参数,看看一切是否仍然有效:
这样做可以让我们能够轻松地添加更多的按钮,这是最终的可重用性测试。我们能做到吗?哒哒哒。
我们先引入新的全局变量 btn2 ,从第一个按钮向 y 方向偏移:
var btn2 = {
    x: 100,
    y: 200,
    width: 150,
    height: 50
};
然后, 我们将画出该按钮:
drawButton(btn2);
这将成功地在画布上绘制2个按钮,但只有第一个按钮将响应点击。我们可以通过相同的逻辑将 btn1 改为 btn2,来使第二个按钮也响应, 如下所示:
mouseClicked = function() {
    if (mouseX >= btn1.x && mouseX <= (btn1.x+btn1.width) &&
        mouseY >= btn1.y && mouseY <= (btn1.y+btn1.height))     {
        println("仍然没什么用");    
    }

    if (mouseX >= btn2.x && mouseX <= (btn2.x+btn2.width) &&
        mouseY >= btn2.y && mouseY <= (btn2.y+btn2.height))     {
        println("第二个也没什么用!");    
    }
};
但是,这些重复的代码难道不会让你皱眉头吗?让我们创建一个函数 isMouseInside ,如果鼠标在按钮上,它知道如何检查任何按钮对象,并返回true:
var isMouseInside = function(btn) {
    return (mouseX >= btn.x &&
            mouseX <= (btn.x+btn.width) &&
            mouseY >= btn.y && 
            mouseY <= (btn.y+btn.height));
};
现在, 我们可以在 mouseClicked 中使用该函数,来大大减少重复的代码数量:
mouseClicked = function() {
    if (isMouseInside(btn1))     {
        println("仍然没什么用");    
    } else if (isMouseInside(btn2))     {
        println("第二个也没什么用!");    
    }
};
就是这样!我们已经使用函数来绘制多个按钮,并使添加新按钮变得相对容易。在下面尝试一下:
我们可以继续——创建程序中所有按钮的数组,实现定制按钮的标签和颜色——但希望这节课给了你一个很好的基础,你学会了如何使用函数创建简单的按钮。接下来,我们将介绍如何使用面向对象的原则创建按钮。

想加入讨论吗?

尚无帖子。
你会英语吗?单击此处查看更多可汗学院英文版的讨论.