Дерево: проверка клика на заголовке
Есть кликабельное JavaScript-дерево UL/LI (см. задачу Раскрывающееся дерево).
<ul>
<li>Млекопитающие
<ul>
<li>Коровы</li>
<li>Ослы</li>
<li>Собаки</li>
<li>Тигры</li>
</ul>
</li>
</ul>
При клике на заголовке его список его детей скрывается-раскрывается. Выглядит это так: (кликайте на заголовки)
Однако, проблема в том, что скрытие-раскрытие происходит даже при клике вне заголовка, на пустом пространстве справа от него.
Как скрывать/раскрывать детей только при клике на заголовок?
В задаче Раскрывающееся дерево это решено так: заголовки завёрнуты в элементы SPAN
и проверяются клики только на них. Представим на минуту, что мы не хотим оборачивать текст в SPAN
, а хотим оставить как есть. Например, по соображениям производительности, если дерево и так очень большое, ведь оборачивание всех заголовков в SPAN
увеличит количество DOM-узлов в 2 раза.
Решите задачу без обёртывания заголовков в SPAN
, используя работу с координатами.
Исходный документ содержит кликабельное дерево.
P.S. Задача – скорее на сообразительность, однако подход может быть полезен в реальной жизни.
Подсказка
У события клика есть координаты. Проверьте по ним, попал ли клик на заголовок.
Самый глубокий узел на координатах можно получить вызовом document.elementFromPoint(clientX, clientY).
…Но заголовок является текстовым узлом, поэтому эта функция для него работать не будет. Однако это, всё же, можно обойти. Как?
Подсказка 2
Можно при клике на LI
сделать временный SPAN
и переместить в него текстовый узел-заголовок.
После этого проверить, попал ли клик в него и вернуть всё как было.
// 1) заворачиваем текстовый узел в SPAN
// 2) проверяем
var elem = document.elementFromPoint(e.clientX, e.clientY);
var isClickOnTitle = (elem == span);
// 3) возвращаем текстовый узел обратно из SPAN
На шаге 3 текстовый узел вынимается обратно из SPAN
, всё возвращается в исходное состояние.