Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Изменение размера элемента при клике (https://javascript.ru/forum/dom-window/43401-izmenenie-razmera-ehlementa-pri-klike.html)

Derekovich 04.12.2013 02:11

Изменение размера элемента при клике
 
Доброго времени суток! 3 дня не ем и не сплю пытаюсь сделать такую вещь:
есть элемент, при клике на него необходимо сделать увеличение его размеров, и уменьшение при очередном клике. НО! необходимо также сделать уменьшение, если человек щелкнул мышью вне этого элемента на экране. Все это должно работать одновременно. Сейчас код выглядит примерно так:
$('.float').click(function() {
 $('.float').toggleClass('size');
  });

При клике добавляю/убираю класс с увеличенным размером. Как сделать еще клик со свободной областью ума не приложу. Если делать общий клик по документу то он перебивает клик по селектору.
Помогите пожалуйста! Заранее благодарен!

danik.js 04.12.2013 03:00

Вероятно не самый лучший вариант..
<style>
.float{height: 20px;background: yellow}
.size{height:100px}
</style>
<div class="float"></div>
<script>
(function(){
var onDocumentClick = function() {
    setTimeout(function(){
        element.addEventListener('click', onElementClick);
    });
    document.removeEventListener('click', onDocumentClick);
    element.classList.remove('size');
};
var onElementClick = function() {
    setTimeout(function(){
        document.addEventListener('click', onDocumentClick);
    });
    element.removeEventListener('click', onElementClick);
    element.classList.add('size');
};

var element = document.querySelector('.float');
element.addEventListener('click', onElementClick);
})();
</script>

Derekovich 04.12.2013 03:09

Спасибо за решение, буду сидеть разбираться... делаю на jquery, поэтому для чистого js нужно немного вникнуть.

danik.js 04.12.2013 03:35

Единственное, что возможно вызывает непонимание - это setTimeout в onElementClick.
Без него, событие тут же отрабатывает на документе и логика ломается.
Вместо setTimeout() можно просто остановить всплытие события: event.stopPropagation();
Причем в обработчике onDocumentClick setTimeout лишний - его можно удалить.

Vlasenko Fedor 04.12.2013 04:00

еще решение
<body>
    <style>
      .float {
        height: 20px;
        background: yellow
      }
      .size {
        height:100px
      }
    </style>
    <div class="float"></div>
    <script>
      (function () {
        var element = document.querySelector('.float');
        document.onclick = function (e) {
          var target = e && e.target || e.srcElement;
          element.classList[target.className == 'float' ? 'add' : 'remove']('size');
          return false;
        }
      })();
    </script>
  </body>

danik.js 04.12.2013 04:54

Забыл отметить что addEventListener нету в IE8, а classList - нету даже в IE9, и в старых версиях других браузеров. (но для всего этого есть костыли (polyfills))

Poznakomlus, твой вариант на мой взгляд, ибо нерационально - ловить все клики, когда есть возможность ловить не все.

рони 04.12.2013 07:11

Derekovich,
http://javascript.ru/forum/jquery/39...tml#post256052

Vlasenko Fedor 04.12.2013 13:04

Цитата:

Сообщение от danik.js (Сообщение 284393)
Poznakomlus твой вариант на мой взгляд

эт смотря при каких условиях и задачах, можно еще тонн кода написать и фреймворки по подключать :)
<head>
    <style>
      .float {
        height: 20px;
        background: yellow
      }
      .size {
        height:100px
      }
    </style>
  </head>
<body>
<a href="http://mail.ru">Mail.ru</a>
<div class="float"></div>
<script>
  (function () {
	var element = document.querySelector('.float');
	document.onclick = function (event) {
	  event = event || window.event;
	  var target = event.target || event.srcElement;
	  element.className = 'float' + (target.className == 'float' ? ' size' : '');
	  return target.tagName == 'A';
	}
  })();
</script>
</body>

http://learn.javascript.ru/play/7BWXn
Поправил исходя из советов danik.js ниже

danik.js 04.12.2013 13:34

<зануда_mode>
1) Элемент <style> не должен быть внутри <body> (разве что с атрибутом scoped)
2) Твой скрипт отключит переход по ссылкам, так как ты предотвращаешь действие по умолчанию
3) Нет смысла переобъявлять переменную event (она уже объявлена как параметр)
</зануда_mode>

danik.js 04.12.2013 15:19

Цитата:

Сообщение от Poznakomlus
это не так

Ты наверно не понял. Ты конечно же можешь. Но браузер будет вынужден в процессе парсинга исправить твой косяк и в конечном итоге твой <style> все-равно попадет в <head>. Это описано в стандарте.
Можешь открыть инспектор и убедиться в этом. Хотя в общем то ничто не мешает поместить его в любое место скриптом в уже сформированном DOM-е.

Между прочим, такая запись будет правильной:
<style>/* тут стили */</style>
<div>тут содержимое body</div>


Браузер автоматом сформирует <head> и <body>, причем ошибок парсинга не возникнет, в отличие от твоего варианта.

danik.js 04.12.2013 16:10

Цитата:

Сообщение от Poznakomlus
return target.tagName == 'A';

А как же кнопки, селекты, чекбоксы и тд и тп. Ты все это собрался перечислить? Ну удачи :)

Vlasenko Fedor 04.12.2013 23:48

Цитата:

Сообщение от danik.js (Сообщение 284536)
Ты все это собрался перечислить

Да нет. Я за спичками то зашел, а то в каждом посте все новые задачи. Может они и не нужны были Т.С.
<head>
    <style>
      .float {
        height: 20px;
        background: yellow;
      }
      .size {
        height:100px
      }
    </style>
  </head>
  <body>
    <a href="http://mail.ru">Mail.ru</a>
    <div class="float"></div>
    <script>
      (function () {
        var element = document.querySelector('.float');
        document.onclick = function (event) {
          event = event || window.event;
          var target = event.target || event.srcElement;
          if (target.tagName == "DIV" && (target.className == 'float' || target.className == 'float size')) {
            element.className = 'float' + (target.className == 'float' ? ' size' : '');
            return false;
          }
          if (element.className == 'float size') {
            element.className = 'float';
          }

        }
      })();
    </script>
  </body>

http://learn.javascript.ru/play/FaPQPb

Derekovich 05.12.2013 02:20

$('.float').click(function() {
$('.float').toggleClass('size');
});

$(document).click(function(event){
if($(event.target).hasClass('float') return;
if(!$(event.target).hasClass('size') && $('.float').hasClass('size')){
$('.float').toggleClass('size');
}
});

Вообще пробую так как написал выше. Делаю проверку, если клик на элементе, то возврат. Если клик вне элемента и элемент имеет класс size то тогда убирать класс у него. На одном элементе работает такая схема, а когда элементов несколько то беда... Задача была у меня следующая: есть 4 картинки с описанием каждой, при клике на картинку необходимо увеличивать ее размер и показывать описание, мой способ работает если документ один, когда элементов несколько не хочет, плывет css весь( и вообще похоже это все на говнокод) я слабоват еще)

danik.js 05.12.2013 02:40

Мой вариант, переписанный с использованием jQuery и слегка измененный.
<style>
.float{height: 20px;background: yellow;margin-bottom:10px;}
.size{height:100px}
</style>
<div class="float"></div>
<div class="float"></div>
<div class="float"></div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
(function(){

var $target = null;
var skipClick = false;

var onDocumentClick = function() {
    $target.removeClass('size');
    $target = null;
    return false;
};
var onElementClick = function() {
    if (!skipClick) {
        setTimeout(function(){
            $(document).one('click', onDocumentClick);
        });
        skipClick = true;
        $target = $(this);
        $target.addClass('size');
        return false;
    }
    skipClick = false;
};

$('.float').click(onElementClick);

})();
</script>

Vlasenko Fedor 05.12.2013 03:05

<!DOCTYPE HTML>
  <head>
    <style>
      .float {
        height: 80px;
        background: yellow;
        width:120px;
        margin: 5px;
        float: left;
      }
      .size {
        height:160px
      }
    </style>
  </head>
  
  <body>
    <div class="float">
      <div>Test</div>
    </div>
    <div class="float"></div>
    <div class="float"></div>
    <div class="float"></div>
    <script>
      (function () {
        document.onclick = function (event) {
          event = event || window.event;
          var target = event.target || event.srcElement,
            active = this.querySelector('.size'),
            elCls;
          while (target != this) {
            elCls = target.className;
            elCls == 'float' && (target.className += ' size') ||
            elCls == 'float size' && (target.className = 'float');
            target = target.parentNode;
          }
          active && (active.className = 'float');
        }
      }());
    </script>
  </body>

http://learn.javascript.ru/play/YGn0Sb:dance:
А код то становится все короче

рони 05.12.2013 03:36

Derekovich, при клике по элементу чередование открытия закрытия - вне элемента все закрываются
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style>
.float{height: 20px;background: yellow;margin-bottom:10px;}
.size{height:100px}
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>

</script>
</head>

<body>

<div class="float"></div>
<div class="float"></div>
<div class="float"></div>

<script>
$('.float').click(function(event) {
event.stopPropagation();
$(this).toggleClass('size');
});
$(document).click(function(){
$('.float').removeClass('size');
});

</script>
</body>

</html>

рони 05.12.2013 03:46

Derekovich,
Вариант клик по другому элементу закрывает предыдущий - всё остальное как выше
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style>
.float{height: 20px;background: yellow;margin-bottom:10px;}
.size{height:100px}
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>

</script>
</head>

<body>

<div class="float"></div>
<div class="float"></div>
<div class="float"></div>

<script>
var floats = $('.float');
floats.click(function (event) {
    event.stopPropagation();
    floats.not(this).removeClass('size');
    $(this).toggleClass('size');
});
$(document).click(function () {
    floats.removeClass('size');
});</script>
</body>

</html>

рони 05.12.2013 10:03

Derekovich,
Ещё вариант варианта выше )))
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style>
.float{height: 20px;background: yellow;margin-bottom:10px;}
.size{height:100px}
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>

</script>
</head>

<body>

<div class="float"></div>
<div class="float"></div>
<div class="float"></div>

<script>
var floats = $('.float');
$(document).click(function (event) {
    $('.size').not(event.target).removeClass('size');
    $(event.target, floats).toggleClass('size');
});
</script>
</body>

</html>

Derekovich 05.12.2013 14:02

В данном примере меняется только добавление/удаление единственного класса к элементу. А вот например как сделать, если есть 3 элемента с разными классами, и при клике должно также отображаться описание текста к картинке. Привожу пример самого блока:

<div class="section_1">
<div class="size_image"><img src="skin/frontend/default/il/images/img1.png" alt="" /></div>
<div class="text_img1">
<p>TEXT only for img1</p>
</div>
</div>

Таких картинок на странице 3 штуки, добавляю только в конце класса порядковый номер другой типа class="section_2", class="text_img2" и т.д. Возможно я неправильно сделал разметку, сейчас получается мне нужно для каждого клика необходимо писать обработчик клика, что не есть хорошо. Заранее благодарен!

danik.js 05.12.2013 14:58

Цитата:

Сообщение от Derekovich
добавляю только в конце класса порядковый номер

Зачем? Не нужно этого делать.

Derekovich 05.12.2013 15:05

А как например тогда определить какое описание текста к картинке выводить?

danik.js 05.12.2013 15:13

Цитата:

Сообщение от Derekovich
А как например тогда определить какое описание текста к картинке выводить?

Где определить? У тебя скриптом добавляется текст? И какой в этом смысл? Или ты текст через аякс подтягиваешь по требованию?

Derekovich 05.12.2013 15:18

<p>TEXT only for img1</p>

Текст находится в блоке у каждого элемента. Понимаю что все это не совсем правильно....но...

danik.js 05.12.2013 15:20

Цитата:

Сообщение от Derekovich
Текст находится в блоке у каждого элемента. Понимаю что все это не совсем правильно....но...

Так в чем тогда проблема, не понимаю? Твоя задумка реализуется уже предложенными вариантами, без каких либо изменений. Тебе осталось прописать css.

Derekovich 05.12.2013 15:29

Я пишу click() для каждого элемента с указанием его в селекторе, все вышепоказанные примеры в селекторе указывают только один класс. У мня же так не получится, я имею 3 блока, у каждого разный класс, в нем есть картинка и описание, в зависимости от клика я отображаю содержимое и увеличиваю картинку. Если например убрать классы которые заканчиваются на 1,2,3, то как пойму, что именно для этого элемента необходимо вывести именно это описание. Поэтому сделал 3 класса, но приходится тогда делать 3 раза обработчик клика, где в селекторе ставлю каждый класс. Как-то так....

danik.js 05.12.2013 20:45

Цитата:

Сообщение от Derekovich
Если например убрать классы которые заканчиваются на 1,2,3, то как пойму, что именно для этого элемента необходимо вывести именно это описание.

Тут ничего понимать не надо. Просто добавляй/убирай второй класс у section и в зависимости от этого класса (через css) скрывай/отображай текст.


Часовой пояс GMT +3, время: 10:26.