CSS классы в классе Tag
Пусть у нас дан вот такой инпут с атрибутом
class
:
<input class="eee bbb kkk">
Как вы видите, атрибут class
содержит
в себе несколько значений, разделенных пробелами.
Эти значения представляют собой несколько
CSS классов нашего элемента.
Давайте реализуем в нашем классе Tag
набор методов, которые будут работать с этими
CSS классами. Например, было бы удобно иметь
метод addClass
, добавляющий еще один
класс в строку с классами.
При этом наш метод должен проверять то, что добавляемый класс еще не присутствует среди классов элемента, иначе добавление нового класса будет приводить к тому, что у элемента будет несколько одинаковых классов, что, конечно же, неправильно.
Пример использования желаемого нами метода:
<?php
// Выведет <input class="eee bbb">:
echo (new Tag('input'))->addClass('eee')->addClass('bbb')->open();
?>
Было бы также удобно иметь метод removeClass
для удаления заданного класса элемента.
Практическое применение этих методов вы еще увидите в следующих уроках.
Давайте реализуем описанные методы.
Добавление класса
Как вы знаете, наш класс Tag
хранит
атрибуты тега в свойстве $this->attrs
.
Данное свойство представляет собой массив.
В этом массиве может быть элемент с ключом
class
, содержащий CSS классы элемента.
Элемента с таким ключом может, однако, и не быть.
Все зависит от того, был ли при создании
тега вызван метод setAttr
для установки
атрибута class
или нет.
Вот пример того, когда он был вызван:
<?php
// Выведет <input class="eee bbb">:
echo (new Tag('input'))->setAttr('class', 'eee bbb')->open();
?>
А вот пример того, когда он не был вызван:
<?php
// Выведет <input id="test">:
echo (new Tag('input'))->setAttr('id', 'test')->open();
?>
В реализации нашего метода addClass
нужно будет учесть оба варианта.
Получается, что если у элемента не заданы
CSS классы, то вызов метода addClass
должен просто создавать в массиве $this->attrs
новый элемент с ключом class
и записывать
в него переданный класс:
<?php
public function addClass($className)
{
// Если ключа class нет в массиве $this->attrs:
if (!isset($this->attrs['class'])) {
$this->attrs['class'] = $className; // запишем наш CSS класс
}
return $this; // возвращаем $this для работы цепочки
}
?>
Обратите внимание на то, что параметр метода
называется $className
, а не $class
,
так как слово class
является зарезервированным в PHP
и его нельзя использовать в качестве имени переменной.
Давайте теперь рассмотрим второй вариант,
когда в $this->attrs['class']
уже
есть один или несколько классов. Как уже
упоминалось выше, эти классы были добавлены
ранее с помощью метода setAttr
. Эти
классы также могли быть добавлены с помощью
вызова метода (или цепочки методов) addClass
.
Способ добавления, в общем-то, не имеет никакого
значения, главное, что, если классы есть,
то они хранятся в виде строки, разделенные
пробелами. Либо, если там один класс, то
в $this->attrs['class']
просто хранится
его имя, без пробелов.
Пусть в $this->attrs['class']
хранится
несколько классов. В этом случае будет удобнее
работать не со строкой с пробелами, а с массивом
CSS классов. Для этого можно просто разбить
нашу строку в массив с помощью функции explode
:
<?php
public function addClass($className)
{
if (isset($this->attrs['class'])) {
// Получаем массив классов:
$classNames = explode(' ', $this->attrs['class']);
}
return $this;
}
?>
Затем необходимо проверить отсутствие переданного
класса в этом массиве классов. Это легко
сделать с помощью функции in_array
:
<?php
public function addClass($className)
{
if (isset($this->attrs['class'])) {
$classNames = explode(' ', $this->attrs['class']);
// Если такого класса нет в массиве классов:
if (!in_array($className, $classNames)) {
// добавим новый класс
}
}
return $this;
}
?>
Если переданного класса нет в массиве классов, то добавим его к уже существующим классам. А если есть - то просто ничего не будем делать.
Давайте реализуем добавление класса:
<?php
public function addClass($className)
{
if (isset($this->attrs['class'])) {
$classNames = explode(' ', $this->attrs['class']);
if (!in_array($className, $classNames)) {
// Добавим новый класс в массив с классами:
$classNames[] = $className;
// Сольем массив в строку и запишем ее в $this->attrs['class']:
$this->attrs['class'] = implode(' ', $classNames);
}
}
return $this;
}
?>
Рассмотрим теперь вариант, когда в $this->attrs['class']
хранится только один класс. На самом деле,
реализованный выше код будет прекрасно работать
и в этом случае: применение explode
к строке без пробела просто вернет массив
из одного элемента, представляющего собой
эту строку. Ну и далее все наши манипуляции
будут работать также.
Давайте соберем весь наш код вместе:
<?php
public function addClass($className)
{
if (isset($this->attrs['class'])) {
$classNames = explode(' ', $this->attrs['class']);
if (!in_array($className, $classNames)) {
$classNames[] = $className;
$this->attrs['class'] = implode(' ', $classNames);
}
} else {
$this->attrs['class'] = $className;
}
return $this;
}
?>
Самостоятельно реализуйте описанный метод
и добавьте его в ваш класс Tag
. Проверьте
работу созданного метода, используя приведенные
ниже примеры:
<?php
// Выведет <input class="eee">:
echo (new Tag('input'))->addClass('eee')->open();
?>
<?php
// Выведет <input class="eee bbb">:
echo (new Tag('input'))->addClass('eee')->addClass('bbb')->open();
?>
<?php
// Выведет <input class="eee bbb kkk">:
echo (new Tag('input'))
->setAttr('class', 'eee bbb')
->addClass('kkk')->open();
?>
<?php
// Выведет <input class="eee bbb">:
echo (new Tag('input'))
->setAttr('class', 'eee bbb')
->addClass('eee') // такой класс уже есть и не добавится
->open();
?>
<?php
// Выведет <input class="eee bbb">:
echo (new Tag('input'))
->addClass('eee')
->addClass('bbb')
->addClass('eee') // такой класс уже есть и не добавится
->open();
?>
Удаление класса
Давайте теперь реализуем удаление CSS класса. Для этого было бы удобно иметь вспомогательный метод, который будет удалять элемент из массива по тексту этого элемента. В PHP, к сожалению, нет такой встроенной функции, поэтому реализуем ее в виде приватного метода:
<?php
private function removeElem($elem, $arr)
{
$key = array_search($elem, $arr); // находим ключ элемента по его тексту
array_splice($arr, $key, 1); // удаляем элемент
return $arr; // возвращаем измененный массив
}
?>
Используя метод removeElem
мы теперь
можем реализовать метод removeClass
для удаления CSS классов. Реализуем:
<?php
public function removeClass($className)
{
if (isset($this->attrs['class'])) {
$classNames = explode(' ', $this->attrs['class']);
if (in_array($className, $classNames)) {
$classNames = $this->removeElem($className, $classNames);
$this->attrs['class'] = implode(' ', $classNames);
}
}
return $this;
}
?>
Самостоятельно реализуйте описанный метод
и добавьте его в ваш класс Tag
. Проверьте
его работу, например, так:
<?php
echo (new Tag('input'))
->setAttr('class', 'eee zzz kkk') // добавим 3 класса
->removeClass('zzz') // удалим класс 'zzz'
->open(); // выведет <input class="eee kkk">
?>