Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   проверки с in (https://javascript.ru/forum/misc/27472-proverki-s.html)

bes 13.04.2012 23:26

проверки с in
 
Знатоки, подскажите каким образом осуществлять подобные проверки.

Например, есть div со ссылкой: div - родительский элемент, ссылка - дочерний.
Нужно, чтобы при уходе мыши с div этот div скрывался, кроме тех случаев, когда уход происходит на его дочерний элемент (ссылку).
Решение, как видится, заключается во фразе "если уходишь не на дочерний элемент, то скрывайся".

Для браузеров с поддержкой target/relatedTarget, код такой.

Код:

<div id=div1 style="background: gray"
  onmouseout = "
    if (!(event.relatedTarget in this.children)) this.style.display = 'none';
">
<a href="">content</a>
</div>

Проверка event.relatedTarget in this.children почему-то всегда возвращает значение true.
Как правильно осуществить данную проверку?

Раед 13.04.2012 23:32

for (var i=0;i<this.children.length;i++) if(!(event.relatedTarget==this.children[i])) this.style.display = 'none';

bes 13.04.2012 23:52

Раед, спасибо, код работает (наверное ты сознательно использовал в цикле children, а не children[i]).
Но можно ли в принципе осуществить подобную проверку с in (и тем самым избавиться от использования цикла)?

Gvozd 13.04.2012 23:56

Цитата:

Сообщение от bes
Проверка event.relatedTarget in this.children почему-то всегда возвращает значение true.

вообще-то она ничего не возвращает и вызывает ошибку, потому что ее нельзя применять для this.children, потому что это не массив
И этот оператор ожидает левым операндом строку - имя индекса в объекте, поэтому его нельзя использовать для проверки наличия элемента в объекте
его надо использовать для проверки наличия элемента с указанным именем.
http://javascript.ru/in

Gvozd 14.04.2012 00:00

Цитата:

Сообщение от bes
наверное ты сознательно использовал в цикле children, а не children[i]

что за слепая вера?
Неужели трудно проанализировать три строчки кода, понять что они делают, и понять что это опечатка?!
Цитата:

Сообщение от bes
Но можно ли в принципе осуществить подобную проверку с in (и тем самым избавиться от использования цикла)?

МОжно проверять наоборот.
Вместо проверки что целевой элемент является потомком исходного, можно проверять является ли исходный элемент предком целевого

Gvozd 14.04.2012 00:15

Maxmaxmахimus,
У Вас jQuery головного мозга

bes 14.04.2012 00:50

Цитата:

Сообщение от Gvozd
вообще-то она ничего не возвращает и вызывает ошибку

Тем не менее, она возвращает true и не вызывает ошибки.

Цитата:

Сообщение от Gvozd
потому что ее нельзя применять для this.children, потому что это не массив

Что же это?

Цитата:

Сообщение от Gvozd
что за слепая вера?
Неужели трудно проанализировать три строчки кода, понять что они делают, и понять что это опечатка?!

Я поэтому и написал "сознательно": как я полагаю, приводился проверенный код, а [i] был убран для того, чтобы человек немного подумал.

Цитата:

Сообщение от Gvozd
МОжно проверять наоборот.
Вместо проверки что целевой элемент является потомком исходного, можно проверять является ли исходный элемент предком целевого

Причём здесь оператор in и как поместить эту проверку в обработчик события исходного элемента?

Цитата:

Сообщение от Maxmaxmахimus
jQuery('selector').mouseenter()
jQuery('selector').mouseleave()

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

Gvozd 14.04.2012 01:01

Цитата:

Сообщение от Maxmaxmахimus
у вас программирование ради прогарммирования, а не программирование ради продуктов.

Веткой форма не ошиблись?
Программирование ради продукта - это в разделе Работа.
Во всех остальных разделах форума цель - обмен и накопление опыта, обучение.
И если на этапе обучения пропустить основы языка, и написание велосипедов, то можно получить в итоге говнокодера.
Именно для этого обучающиеся пишут с нуля сортировки, реализуют с нуля двунаправленные списки и деревья, хотя все это уже релизовано сотни раз до них.
Или Вы сразу на jQuery научились писать, минуя этап обучения?
Цитата:

Сообщение от Maxmaxmахimus
Короли велосипедные - мы их называем.

Собирать каждый день по новому велосипеду - излишняя и ненужная работа.
Но не зная как устроен велосипед, далеко уехать не получится. Не дальше, чем сломается велосипед, или понадобится велосипед которого еще никто не создал, но который легко можно создать зная как устроены другие велосипеды.

Когда вам понадобится сделать 4-х колесный велосипед(чтоб им дети пользовались), вам будет недостаточно взять два уже существующих велосипеда и примотать синей изолентой друг к другу.
Получившаяся конструкция будет уродливой, и обладать рядом других минусов, чем если бы вы сделали 4-х колесный велосипед с нуля.

В общем если обойти этап создания велосипедов в процессе обучения, можно остаться простым пользователем чужих велосипедов, и не стать профессионалом.

Gvozd 14.04.2012 01:19

Цитата:

Сообщение от bes
Тем не менее, она возвращает true и не вызывает ошибки.

Да, я ошибся
Только true все-таки возвращается не event.relatedTarget in this.children, а !(event.relatedTarget in this.children)
event.relatedTarget in this.children возвращает false
Цитата:

Сообщение от bes
Что же это?

HTMLCollection, также известный в DOM-е как ChildNodeList
Он не является массивом, хотя и похож на него.
У него нету некоторых методов массивов(например сортировки, мклейки и иных)
А самое главное, он живой в отличии от массива - если вы возьмете HTMLCollection, то при изменении DOM-модели, он также изменится
Например(запускать на вашем HTML_коде)
var a = document.getElementsByTagName('a');//тоже HTMLCollection
console.log(a.length);//1
console.log(a[0]);//<a href="">
console.log(a[0].innerHTML);//content
document.getElementsByTagName('div')[0].innerHTML = 'qwe';
console.log(a.length);//0
console.log(a[0]);//undefined
console.log(a[0].innerHTML);//Ошибка - элемента уже нет


Цитата:

Сообщение от bes
Причём здесь оператор in и как поместить эту проверку в обработчик события исходного элемента?

Не при чем. Просто таким образом также можно проверить в одну строчку интересующее вас условие.
В одну строчку но, без in
Вы очень хотите использовать именно этот понравившийся вам оператор?

bes 14.04.2012 10:03

Цитата:

Сообщение от Gvozd
Только true все-таки возвращается не event.relatedTarget in this.children, а !(event.relatedTarget in this.children)
event.relatedTarget in this.children возвращает false

Да, здесь я блажанул.

Цитата:

Сообщение от Gvozd
Вы очень хотите использовать именно этот понравившийся вам оператор?

Если работает, почему бы и нет, тем более, что этим удалось бы избежать использование цикла (в который, кстати, я думаю, нужно было ещё добавить и return, чтобы не перебирались элементы после того элемента, на который собственно была наведёна мышь).

Цитата:

Сообщение от Gvozd
HTMLCollection, также известный в DOM-е как ChildNodeList
Он не является массивом, хотя и похож на него.
У него нету некоторых методов массивов(например сортировки, мклейки и иных)

Говорит ли это о том, что псевдомассивы (такие как HTMLCollection) отличаются от массивов только тем, что у них нет некоторых методов массивов?

Правильно ли я понимаю, что псевдомассивы хранят в качестве элементов ссылки на некоторые элементы (через которые собственно можно получить к ним доступ), ведь мы можем обращаться к доступным свойствам этих элементов (например, a[0].innerHTML), хотя приведённый вами пример, Gvozd, вернул строку <a href=""> для a[0] .

Pavel M. 14.04.2012 12:35

bes,
посмотрите как эмулируются для неподдерживающих броузеров события mouseenter mouseleave http://learn.javascript.ru/mouse-eve...ter-mouseleave

там проверяется parentNode - удобнее и с объектами событий все сделано кроссбраузерно

Gvozd 14.04.2012 13:38

Цитата:

Сообщение от bes
Говорит ли это о том, что псевдомассивы (такие как HTMLCollection) отличаются от массивов только тем, что у них нет некоторых методов массивов?

Нет.
Вы процитировали мое сообщение не полностью, опустив более важное отличие, а именно живость массива.
Вот пример приведенного кода, только a - это уже массив, с одним элементом - ссылкой. Запускать на вашем HTML-е
var a_elem = document.getElementsByTagName('a')[0];
var a = [a_elem];
console.log(a.length);//1
console.log(a[0]);//<a href="">
console.log(a[0].innerHTML);//content
document.getElementsByTagName('div')[0].innerHTML = 'qwe';
console.log(a.length);//1
console.log(a[0]);//<a href="">
console.log(a[0].innerHTML);//content

Как видим для настоящего массива количество элементов не изменилось, и он даже все еще хранит некоторую информацию об элементе которого уже нету в DOM-модели.
А HTMLCollection в данном случае вместе с ичсчезновением ссылки, и сам переставал ссылатся на нее, и становился размера 0
================================================== ======
Вообще массивом является только то, что выдает true на x instanceof Array
var construct = function(){//конструктор объектов - наследующих массив
    for(var i =0; i < arguments.length; i++){
        this.push(arguments[i]);
    }
};
construct.prototype = [];


var a = document.getElementsByTagName('a');
var b = {};
b[0] = 'qwe';
var c = ['qwe']
d = new construct('qwe');

console.log(a.length, a[0], a instanceof Array);//false
console.log(b.length, b[0], b instanceof Array);//false
console.log(c.length, c[0], c instanceof Array);//true
console.log(d.length, d[0], d instanceof Array);//true

Результат:
Код:

1 <a href=""> false
undefined qwe false
1 qwe true
1 qwe true

Как видим, только c и d являются массивами(второй - наследует его свойства), хотя у всех объектов в данном случае можно получить нулевой элемент

Gvozd 14.04.2012 13:50

Цитата:

Сообщение от bes
Правильно ли я понимаю, что псевдомассивы хранят в качестве элементов ссылки на некоторые элементы (через которые собственно можно получить к ним доступ), ведь мы можем обращаться к доступным свойствам этих элементов (например, a[0].innerHTML)

Да.
Только для HTMLCollection эти ссылки будут хранится только на живые элементы, если они есть.
ПРи их исчезновении, коллекция будет уменьшатся в размерах.
А при добавлении новых элементов, наоборот даже расти:
var a = document.getElementsByTagName('a');
console.log(a.length);//1
document.getElementsByTagName('div')[0].innerHTML += '<a href="">content</a>';
console.log(a.length);//2, потому что ссылок уже две


Цитата:

Сообщение от bes
хотя приведённый вами пример, Gvozd, вернул строку <a href=""> для a[0] .

Вообще-то тут возвращается сам элемент.
Просто в консоли отладчика он выглядит как такая строка, которую я сюда скопипастил.
Запустите мои примеры в консоли firebug(это плагин для FireFox), например.
Можно и в отладочной консоли любого другого браузера, благо она есть сейчас во многих браузерах.
Цитата:

Сообщение от bes
Если работает, почему бы и нет

Как я уже сказал, в данном случае оператор in не будет работать так как вы хотите.
Зато я привел вам столь же короткий способ решения, без циклов, который будет работать.
Даже Pavel M., уже вам говорит о том же самом

bes 15.04.2012 09:28

Цитата:

Сообщение от Pavel M.
посмотрите как эмулируются для неподдерживающих броузеров события mouseenter mouseleave http://learn.javascript.ru/mouse-eve...ter-mouseleave

Да, я видел этот способ, просто хотелось для простейших случаев, как мне показалось, использовать более простой и короткий способ, когда весь код помещается в обработчик onmouseout родительского элемента, а дочерние элементы обработчиками не обременяются (даже путём их "короткого" задания во внешнем по отношению к ним коде), для этого достаточно было сформировать ряд условий, варианты реализации одного из этих условий и были помещены в тему обсуждения.

Gvozd, спасибо за пояснения, разницу между массивами и HTML-коллекциями я почувствовал.

Цитата:

Сообщение от Gvozd
Сообщение от bes: Eсли работает, почему бы и нет
Как я уже сказал, в данном случае оператор in не будет работать так как вы хотите.

Я и не утверждал, что собираюсь использовать in, даже если он здесь не работает, просто хотелось понять, не работает ли он здесь потому что он здесь совсем не работает или потому что я его как -то неправильно использую.

Цитата:

Сообщение от Gvozd
Зато я привел вам столь же короткий способ решения, без циклов, который будет работать.

О каком коротком способе без циклов идёт речь?
Если о вариантах получения единственного элемента-ссылки, то в случае с несколькими элементами-ссылками всё равно придётся использовать цикл.

Цитата:

Сообщение от Gvozd
Даже Pavel M., уже вам говорит о том же самом

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

bes 15.04.2012 10:45

Кстати, статья http://learn.javascript.ru/mouse-events теперь расположена по адресу http://learn.javascript.ru/mousemove-events.

bes 15.04.2012 11:16

Удалось получить простой и кроссбраузерно работающий код, когда скрытие div происходит только при уходе с него (Pavel M., способ с parentNode в статье, действительно, пригодился, по ходу я просто не понял этой фишки, читая статью до этого, то ли обновлённая статья стала понятнее).

Код:

<div id=div1 style="background: gray"
  onmouseout = "
  var rt = event.relatedTarget || event.toElement;

  while (rt && rt !== this) rt = rt.parentNode;

  if (rt == this) return; else this.style.display = 'none';
">
<a href="">content1</a><br>
<a href="">content2</a>
</div>


nerv_ 15.04.2012 23:07

Цитата:

Сообщение от Раед
for (var i=0;i<this.children.length;i++) if(!(event.relatedTarget==this.children[i])) this.style.display = 'none';

Что за мода все в одну строчку лепить?

Раед 15.04.2012 23:09

Цитата:

Сообщение от nerv_
Что за мода все в одну строчку лепить?

На мой взгляд, для простых конструкций это самый оптимальный вариант

nerv_ 15.04.2012 23:12

Раед, на мой взгляд простая конструкция это
var foo = null;

;)

Gvozd 15.04.2012 23:28

Цитата:

Сообщение от Раед
На мой взгляд, для простых конструкций это самый оптимальный вариант

Это в каком из общепринятых стандартов оформления кода?
Практически уверен, что нету ни одного стандарта, допускающего такие вольности, и ваш взгляд ошибочен

Раед 16.04.2012 16:09

for (var i=0;i<this.children.length;i++) {
 if(!(event.relatedTarget==this.children[i])) this.style.display = 'none';
}
Gvozd, nerv_,
По вашему так лучше?

Gvozd 16.04.2012 21:16

Раед,
Вы все еще лепите конструкции в одну строку.
Незачем экономить пробелы, или строчки, в ущерб читаемости.
То есть экономия строчки никогда неоправдана

Вот так гораздо лучше:
for (var i = 0; i < this.children.length; i++) {
	if (!(event.relatedTarget == this.children[i])) {
		this.style.display = 'none';
	}
}

Каждая инструкция в своей строке.
Четко видно где начинается и заканчивается блок


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