Xpoint
   [напомнить пароль]

Создание графического checkbox-а

Оглавление

Иногда веб-дизайнеры, увлёкшись сочинением ни на что не похожего суперстиля для сайта, сталкиваются с необходимостью вписать в этот свой уникальный стиль стандартные элементы управления HTML-форм. Стандартные элементы, хотя и всем привычны, выглядят довольно коряво, к тому же могут иметь совершенно разный вид на разных платформах. Естественно, в этом случае у дизайнера возникает желание совсем отказаться от стандартных элементов управления и нарисовать свои собственные.

Эту идею, вообще говоря, нельзя назвать удачной, и на практике таким мыслям следует всячески сопротивляться. Во-первых, потому что самостоятельно созданные элементы управления непривычны для пользователя, и он может просто не понять, как ими пользоваться. Во-вторых, потому что функциональность формы в этом случае будет жёстко привязана к факту наличия/отсутствия JavaScript-а в браузере клиента. И если у клиента JavaScript отключён, он может вообще не суметь воспользоваться вашей формой. Также у него могут возникнуть трудности при отключённых картинках. В общем, стоит трижды подумать, прежде чем принимать такое решение, а для посещаемых сайтов с широкой аудиторией лучше вовсе от этой идеи отказаться.

Однако сама по себе эта задача довольно интересна, хотя и не сложна. Поэтому, исключительно в ознакомительных целях:) рассмотрим создание собственного элемента управления типа checkbox (далее — «чекбокс»).

Постановка задачи и требования

Требования к нашему чекбоксу просты. Имеются две картинки (скажем, on.png и off.png) изображающие наш чекбокс во включённом и выключенном состояниях. По нажатию на картинку состояние чекбокса меняется. Кроме того, с чекбоксом может быть связан элемент label, нажатия на который тоже следует обрабатывать. И, наконец, состояние чекбокса должно передаваться на сервер при сабмите формы так же, как если бы это был нормальный чекбокс.

Основная идея

Вместо того, чтобы возиться с hidden-полями (как это обычно делается в таких случаях), мы воспользуемся… обычным чекбоксом, только скрытым. Именно он будет реально передаваться на сервер и хранить в себе данные. Но он будет невидимым, а видимыми будут наши картинки, эмулирующие чекбокс. Однако невидимым он будет только если у пользователя работает JavaScript, в противном случае пользователь сможет воспользоваться обычным чекбоксом вместо картинки.

Вот как это работает:

<input type="checkbox" id="chbox" name="chbox" value="1" checked>
<img src="off.png" onclick="myCheckBox.flip()" 
    style="display: none" id="imgchbox" width="12" height="12" alt="">

<label for="chbox" onclick="myCheckBox.flip()">some text</label>

<script>myCheckBox = new ImgCheckbox("imgchbox", "chbox", "on.png", "off.png")</script>

Первые две строки — это, собственно, и есть сам элемент управления. Он состоит из нормального чекбокса и картинки. Треться строчка — метка, привязаная к нашему чекбоксу. Наконец, script-блок — создание объекта, который будет обрабатывать нажатия на наш элемент управления.

Обратите внимания на явно заданный стиль display: none у картинки. Если к нам придёт пользователь с отключённым JavaScript-ом, то картинка останется невидимой и блок script не сработает. В этом случае пользователь увидит обычный чекбокс с меткой.

Если же у пользователя включён JavaScript, то при создании объекта myCheckBox обычный чекбокс будет скрыт, а картинка, наоборот, станет видимой. Нажатия на картинку и на метку будут обрабатываться методом myCheckBox.flip(), который и обеспечит обновление невидимого чекбокса.

Реализация

Вот код класса ImgCheckbox с комментариями. Он предельно прост:

/* 
Класс ImgCheckbox
В конструктор передаются параметры:
    imgId        id картинки, которая будет служить чекбоксом
    inputId      id «настоящего» чекбокс-элемента формы
    imgOn        url картинки «включённого» чекбокса
    imgOff       url картинки «выключённого» чекбокса
*/
function ImgCheckbox(imgId, inputId, imgOn, imgOff) {
    this.imgOn   = imgOn
    this.imgOff  = imgOff
    this.image   = document.getElementById(imgId)
    this.input   = document.getElementById(inputId)

    // предзагрузка картинок
    this.preload_imgOn      = new Image()
    this.preload_imgOn.src  = imgOn
    this.preload_imgOff     = new Image()
    this.preload_imgOff.src = imgOff

    // скрываем обычный чекбокс…
    this.input.style.display = "none"
    // и показываем чекбокс-картинку
    this.image.style.display = "inline"
    
    // установка начального состояния чекбокса
    this.setState(this.input.checked)
}

// установка состояния чекбокса
ImgCheckbox.prototype.setState = function(state) {
    // меняем состояние скрытого чекбокса
    this.input.checked     = state
    // меняем картинку
    this.image.src   = state ? this.imgOn : this.imgOff
}

// изменение состояния чекбокса на обратное (вкл -> выкл и наоборот)
ImgCheckbox.prototype.flip = function() {
    this.setState(!this.input.checked)
}

В случае, если чекбокс расположен внутри элемента label, обработчик onclick следует указывать только у элемента label:

<label for="chbox" onclick="myCheckBox.flip()">

<input type="checkbox" id="chbox" name="chbox" value="1" checked>
<img src="off.png" style="display: none" id="imgchbox" width="12" height="12" alt="">

some text

</label>

<script>myCheckBox = new ImgCheckbox("imgchbox", "chbox", "on.png", "off.png")</script>

Нетрудно расширить функциональность такого чекбокса — например, научить его реагировать на наведение мыши без нажатия.

Недостатки

  1. на такой чекбокс (в его графическом режиме) не передаётся фокус ввода при нажатии кнопки TAB. Таким образом, форму не удастся заполнить без помощи мыши.
  2. при отключенных картинках в браузере пользователь не увидит ничего, кроме текста. Варианты решения:
    1. Вместе со сменой картинки менять и её alt — например, [ ] и [•]
    2. Привязать инициализацию объекта к событию onload img-элемента (которое не наступит при отключённых картинках)
Powered by POEM™ Engine Copyright © 2002-2005