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

Ако си зад уеб филтър, моля, увери се, че домейните *. kastatic.org и *. kasandbox.org са разрешени.

Основно съдържание

Функция за бутон

Ако мина през курса въведение в JS, значи вече направи няколко бутона в Logic предизвикателствата Твоят първи бутон и По-умен бутон. В случай, че не си спомняш, нека да си припомним как се правят прости бутони.
Първо какви са минималните характеристики на един бутон?
  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, която ще се извика, когато потребителят кликне, а в нея трябва да проверим дали mouseX и mouseY са в границите на бутона. За бутона, даден по-горе, границите му са от x=100 до x=250 и от y=100 до y=150, както е показано по-долу:
Можем да проверим тези координати, като свържем четирите условия с оператора &&:
mouseClicked = function() {
    if (mouseX >= 100 && mouseX <= 250 &&
        mouseY >= 100 && mouseY <= 150) {
        println("Все още доста безполезен");    
    }
};
Опитай да кликнеш върху него, за да се увериш, че работи:
Определено работи, но нещо ме притеснява. Притеснявам се за това, че кодът ми не е преизползваем. Колко работа трябва да свърша, ако искам да променя позицията на бутона? (Опитай!) Виждам доста "хард-коднати" (представени чрез себе си) числа в кода си – като координатите във функцията mouseClicked, и веднага започвам да се чудя дали няма по-чист начин.
За начало, нека изнесем в променливи позицията и размера, за да можем да ги променяме на едно място и да сме сигурни, че щракането върху бутона ще продължи да работи. Добавих btnX, btnY, btnWidth и btnHeight към програмата по-долу. Опитай да промениш стойностите им и да кликнеш върху бутона:
Така вече е по-добре. Но все още трябва да свърша доста работа, ако искам да добавя още един бутон. Трябва ли да копирам всичко това и да направя 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 is not defined" ("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(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);
};
Функцията 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 бутона на платното, но само първият отговаря на кликване. Можем да накараме и втория да реагира, като използваме логиката и подадем btn2 вместо btn1, ето така:
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("Втори все още безполезен!");    
    }
};
И това е! Използвахме функции, за да нарисуваме няколко бутона и направихме така, че сравнително лесно да добавяме още бутони. Опитай и ти:
Можем да продължим – да направим масив от всички бутони в програмата, което ще ни позволи да ги променяме лесно с надписи и цветове – но се надявам, че това ти даде добра основа за това как да създаваш прости бутони с помощта на функции. Следва да научим как да създаваме бутони, като използваме принципите на обектно-ориентираното програмиране.

Искаш ли да се присъединиш към разговора?

Все още няма публикации.
Разбираш ли английски? Натисни тук, за да видиш още дискусии в английския сайт на Кан Академия.