Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Как записать все елементы в массив, чтобы потом применить ко всем сразу событие? (https://javascript.ru/forum/dom-window/30960-kak-zapisat-vse-elementy-v-massiv-chtoby-potom-primenit-ko-vsem-srazu-sobytie.html)

platedz 22.08.2012 01:41

Как записать все елементы в массив, чтобы потом применить ко всем сразу событие?
 
Как записать все элементы в массив (или объект), чтобы потом применить ко всем ним какое-нибудь событие?
Т.е. нужно что-то навроде

var masel = [];

masel[1] = document.getElementById("id1");
masel[2] = document.getElementById("id2");
masel["onclick"] = function.....

melky 22.08.2012 07:31

for (var i = 1, m = masel.length; i < m; i++) {
    masel[i].onclick = ..............
}

platedz 22.08.2012 11:56

Спасибо за ответ. А сразу ко всем никак нельзя? Получается, что мне в каждом методе необходимо сделать цикл.

Deff 22.08.2012 13:04

platedz,
Есть Вариант отслеживания событий на общем родителе, с последующим определением элемена клика

melky 22.08.2012 14:21

Цитата:

Сообщение от platedz (Сообщение 199611)
Спасибо за ответ. А сразу ко всем никак нельзя? Получается, что мне в каждом методе необходимо сделать цикл.

http://learn.javascript.ru/event-delegation

platedz 22.08.2012 21:59

А почему так не выходит?
<div id="id1">id1</div><div id="id2">id2</div>
<script> alert(document.getElementById("id1","id2").innerHTML); </script>

bes 22.08.2012 22:12

Потому что так сделали

oneguy 22.08.2012 22:49

Цитата:

Сообщение от platedz (Сообщение 199753)
А почему так не выходит?
<div id="id1">id1</div><div id="id2">id2</div>
<script> alert(document.getElementById("id1","id2").innerHTML); </script>

Функция document.getElementById принимает только 1 параметр.

platedz 22.08.2012 23:16

Спасибо за ответ. Думаю попробовать с помощью elem.querySelectorAll(css). Вроде написано что ie8 он поддерживает, а на более низкие я уже особо не ориентируюсь.

platedz 23.08.2012 00:54

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

Т.е. чтобы обратиться к любому элементу на странице мне необходимо по идее записывать или document.onclick = function(){и здесь осуществлять проверку на то, произошло ли данное событие на нужном мне элементе}
Я верно понимаю.

Deff 23.08.2012 01:23

platedz,
лучше делегировать с ближайшей обертки всех этих элементов (или создатьеё спецом

platedz 23.08.2012 01:46

Смысл в том, чтобы к массиву элементов применить какое-нибудь одно действие.
Т.е. чтобы при нажатии на id1,id2 или id3, выполнялась какая-нибудь одна фукнция, а один точнее метод.



topmenu = (function(window) {
var elements = {};

return {
			Sattr: function(name)
				{
				try{ elements = document.querySelectorAll(name);}catch(e){}
					
					return this;
				},	
				
			functio: function()
				{
					
					for(var i = 0; i<elements.length;i++) elements[i].parentNode.removeChild(elements[i]); 
					return this;
				
				}
	
	}
	

}(window)); 

topmenu.Sattr(".eror").functio();

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

oneguy 23.08.2012 02:22

Можно сделать через встроенный метод Array.prototype.forEach (правда, не для IE<9):
topmenu = (function(window) {
var elements = {};
 
return {
            Sattr: function(name)
                {
                try{ elements = document.querySelectorAll(name);}catch(e){}
                     
                    return this;
                }, 
                 
            functio: function () {
               Array.prototype.forEach.call(elements, function(v)
                {
                     v.parentNode.removeChild(v);
                 
                });
               return this;
            }
    }
     
 
}(window));
 
topmenu.Sattr(".eror").functio();

platedz 23.08.2012 02:41

Спасибо за ответ. Но я так понимаю, разницы особой нет. Array.prototype.forEach нужно добавлять в каждый объект.

Хотелось чтобы это было както так

element(element).parentNode.removeChild(element(el ement));

или так

element.functio : function(){....}

или так

for() return{

......

}

Или я не знаю как. Как-то чтобы не писать цикл в каждом методе.

Может Sattr вынести куда-то и как-то по другому обратиться к объекту.

oneguy 23.08.2012 02:52

В моём примере ведь не используется цикл, только функция в качестве аргумента к Array.prototype.forEach.call. Если это писать долго, можно поставить этот forEach в NodeList.prototype:
NodeList.prototype.forEach=Array.prototype.forEach;

...

functio: function () {
               elements.forEach(function(v)
                {
                     v.parentNode.removeChild(v);
                  
                });
               return this;
            }

platedz 23.08.2012 13:05

Спасибо за пример. Я в основном писал на jquery, сейчас стараюсь отходить и больше писать на чистом javascript.
К сожалению опп у меня хромает, а с прототипами и вовсе плохо. Поэтому Ваш пример мне не до конца понятен, из-за плохого понимания прототипов.
В любом случае, в нем используется перебор, хоть и в виде метода, forEach - это ведь по большому счету то же цикл.
В общем-то это не главное. Главное, что этот перебор необходимо вставлять в каждый метод. Т.е. в каждом методе делать обертку ....какой_то_перебор {а тут уже сама функция}.
Я хочу избавиться непосредственно от вложенности, т.к. везде приходится делать примерно так

method: function(){

try{

for(){

и только тут уже сама функция.
}

}

}

Хотелось бы вынести перебор в отдельное место, или применить ко всем методам сразу.

oneguy 23.08.2012 16:29

Есди я правильно понял, нужно избавиться от лишнего уровня вложенности. Тогда можно так:
topmenu = (function(window) {
var elements = {};
var result={
  functio: function (el) {
    el.parentNode.removeChild(el);
  },

  //...

};
function f(callback) {
    Array.prototype.forEach.call(elements, callback);
    return this;
}
for (var method in result)
  result[method]=f.bind(topmenu, result[method]);
result.Sattr=function(name)
                {
                try{ elements = document.querySelectorAll(name);}catch(e){}
                      
                    return this;
                },
return result;
      
  
}(window));
  
topmenu.Sattr(".eror").functio();

platedz 23.08.2012 20:54

Спасибо, по идее то, что надо, но у меня не работает. А самое обидное, что я его почти не понимаю.

oneguy 24.08.2012 00:15

Цитата:

Сообщение от platedz
А самое обидное, что я его почти не понимаю.

Какую именно строчку вы не понимаете?

platedz 24.08.2012 11:49

Array.prototype.forEach.call(elements, callback);
Вот эта больше всего.

platedz 24.08.2012 11:51

for (var method in result)
result[method]=f.bind(topmenu, result[method]);
И эта тоже не очень понятна

platedz 24.08.2012 12:02

Вообще я сделал так

topmenu= (function(window) {
var elements = {};
var result={
  functio: function () {
    alert(elements);
  }

};
function f(callback) {
    Array.prototype.forEach.call(elements, callback);
    return this;
}
for (var method in result)
  result[method]=f.bind(topmenu, result[method]);
result.Sattr=function(name)
                {
                try{ elements = document.querySelectorAll(name);}catch(e){}
                      
                    return this;
                },
return result;
      
  
}(window));
  
topmenu.Sattr("div").functio();


Т.е. получается нужно сделать так чтобы functio вывела столько alert(элемент), сколько элементов.

Если бы код работал, то было бы проще его разобрать, а так я даже не понимаю где ошибка?

oneguy 24.08.2012 17:00

Нужно писать вместо
functio: function () {
    alert(elements);
  }

так:
functio: function (el) {
    alert(el);
  }

platedz 24.08.2012 22:19

Спасибо за ответ.
но
Так тоже не работает
topmenu = (function(window) {
var elements = {};
var result={
  functio: function (elements) {
    alert(elements);
  }

};
function f(callback) {
    Array.prototype.forEach.call(elements, callback);
    return this;
}
for (var method in result)
  result[method]=f.bind(topmenu, result[method]);
result.Sattr=function(name)
                {
                try{ elements = document.querySelectorAll(name);}catch(e){}
                      
                    return this;
                },
return result;
      
  
}(window));
  
topmenu.Sattr("div").functio();

oneguy 26.08.2012 19:38

Извиняюсь, я не раньше не тестировал этот код, а сейчас сделал это и оказались 2 ошибки:
1) запятая вместо точки запятой в 20-й строчке;
2) обращение к переменной topmenu идёт перед тем, как её определили (если вы её в другом месте не определили).
Так уже работает:
<!DOCTYPE html>
<html><head>
<meta http-equiv="Content-Type" content="application/xhtml+xml;charset=UTF-8" /><title></title>
</head>
<body>
<div></div>
<div></div>
<script>
var topmenu = (function(window) {
  var elements = {};
  var result={
    functio: function (elements) {
      alert(elements);
    }
  };
  function f(callback) {
    Array.prototype.forEach.call(elements, callback);
    return this;
  }
  for (var method in result)
    result[method]=f.bind(result, result[method]);
  result.Sattr=function(name)
                {
                try{ elements = document.querySelectorAll(name);}catch(e){}
                      
                    return this;
                };
  return result;
}(window));
  
topmenu.Sattr("div").functio();

</script>
</body>
</html>

platedz 27.08.2012 13:48

Спасибо большое. Буду разбираться. Еще бы от bind избавиться, раз он только под ie9. Читал, что его можно эмулировать, но пока не пробовал.

platedz 27.08.2012 16:12

Объясните пожалуйста, чем отличается эта запись
Array.prototype.forEach.call(elements, function(item){ alert(item); });


от этой
elements.forEach(function(item){ alert(item); });


Последняя возвращает

Object #<NodeList> has no method 'forEach'

melky 27.08.2012 17:58

потому что это разные типы.

Array и NodeList.

они имеют сходства внешне, но внутренне они различны.

platedz 27.08.2012 18:39

Спасибо за пояснение, но можно как-то поподробнее.
Насколько я понимаю forEach работает только с массивами.
При этом используя конструкцию Array.prototype мы преобразуем объект NodeList в массив. При этом не очень понятно, что же происходит на самом деле, и вообще очень плохо понимаю прототипы и как они работают.
И есть ли какая-нибудь разница между NodeList объектом и массивом состоящим из тех же элементов?

melky 27.08.2012 20:35

Цитата:

Сообщение от platedz
Array.prototype мы преобразуем объект NodeList в массив

нет. мы просто заимствуем метод у массива. А т.к. у NodeList есть свойство length, да и свойства пронумерованы от нуля, то forEach схавает его, как массив.

в forEach примерно такой код:
for (var i = 0; i < this.length; i++) {
    callback( this[i], i, this );
}


Цитата:

Сообщение от platedz
И есть ли какая-нибудь разница между NodeList объектом и массивом состоящим из тех же элементов

да - nodeList живой.
http://habrahabr.ru/post/121803/#comment_3985850

platedz 27.08.2012 21:48

Спасибо за пояснение.

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

Особенно интересуют следующая часть кода
function f(callback) {
    Array.prototype.forEach.call(elements, callback);
    return this;
  }
  for (var method in result)
    result[method]=f.bind(result, result[method]);



Больше всего мне непонятно, что же происходит здесь, и как после всего этого выглядит result в итоге
for (var method in result)
    result[method]=f.bind(result, result[method]);

melky 27.08.2012 21:50

мы не телепаты. Учитесь пользоваться консолью.

platedz 27.08.2012 21:54

Да нет все работает. Просто я не понимаю принцип работы кода.

bes 27.08.2012 21:57

http://es5.javascript.ru/x15.3.html#x15.3.4.5

platedz 27.08.2012 21:57

Да и от bind не мешало бы избавиться, т.к. тогда весь код не будет работать в ie8

platedz 28.08.2012 13:03

Немного переделал так
var topmenu= (function(window) {
  var elements = [];
  var result={
    functio: function () {
      alert(arguments[0].innerHTML);
    }
  };
  function f(callback) {
   
    elements.forEach(callback);
	
    return this;
  }
  
  for (var method in result)
    result[method]=f.bind(result, result[method]);
	
  result.Sattr=function(name)
                {
                try{ elements = Array.prototype.slice.apply(document.querySelectorAll(name));}catch(e){}
                   
                    return this;
                };
  return result;
}(window));
topmenu.Sattr("div").functio().functio();


Сложнее всего до моего понимания доходит эта строка

for (var method in result) result[method]=f.bind(result, result[method]);

Насколько я понимаю,
1) мы передаем текущий объект в функцию f
2) в ней через foreach применяем к каждому отдельному элементу массива callback, которым является каждый метод текущего объекта т.е. result[method]

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

Т.е. если перед циклом for поставить alert(elements.length); толку не будет.

Что как бы говорит о том, что все указанные действия вне методов вызываются либо сразу, либо при каждом обращении к объекту через его метод.

Кроме прочего насколько я понимаю bind - это своего рода внутренняя функция, которую можно повторить и в устаревших браузерах.

В общем, второй день сижу, пытаясь разобраться, что да как, запутался уже. Помогите, пожалуйста, разобраться, и заодно симулировать bind.

melky 28.08.2012 15:59

Цитата:

Сообщение от platedz
1) мы передаем текущий объект в функцию f

текущий объект - это this. а в коде передаётся result.

Цитата:

Сообщение от platedz
При этом мне вовсе не яcно, как функция вообще получает elements. Т.к. попытка вызвать его вне метода не дает результата.

посредством замыкания.

Цитата:

Сообщение от platedz
Кроме прочего насколько я понимаю bind - это своего рода внутренняя функция, которую можно повторить и в устаревших браузерах.

функция, которая имеет примерно такой код (словами объяснять долго):

кроме того, bind имеет некоторые особенности, которые не реализуемы посредством JavaScript (другими словами, полного костыля не получится создать.).. об особенностях посмотрите в интернете.
/*  ----------  ОПИСАНИЕ  ---------- */

Function.prototype._bind = function (context /*, arg0, arg1, ... argN */) {
    
    // сохраним переданные аргументы в замыкании. Именно "1", потому что нулевой элемент - контекст.
    var args = Array.prototype.slice.call(arguments, 1);

    // сохраним текущую функцию в замыкании, ибо ...
    var func = this; 

    // ... в этой функции this уже будет window (по-умолчанию, во всех функциях так).    
    return function () {

        // преобразуем объект текущих аргументов в массив
        var newArgs = Array.prototype.slice.call(arguments);

        // добавим к переданным вначале аргументам переданные сейчас.
        newArgs = args.concat(newArgs);

        // и вызовем apply, передав контекст, и аргументы.
        func.apply( context, newArgs );

    };
};

/*  ----------  ТЕСТИРОВАНИЕ  ---------- */

// функция просто выведет алертом свойство "FOO" своего контекста, добавив к нему первый аргумент, и второй.
// this сейчас равен window (по-умолчанию).
var test = function (first, second) {  alert( this.FOO + first + second );  };

// объект со свойством "FOO"
var obj = {  "FOO": "Hello" };

// применим связывание.
// this в test_binded будет равен obj.
// а первый аргумент ( first в функции "test" ) будет равен строке ", "
var test_binded = test._bind( obj, ", " );

// вызовем связанную функцию, передав ей ещё один аргумент ( это уже будет "second" )
test_binded( "World!" );

// Связывание и вызов связанной функции аналогичны этой строке :
test.call( obj, ", ", "World!" );

oneguy 28.08.2012 20:47

melky,
спасибо. Здесь https://developer.mozilla.org/en-US/.../Function/bind есть ещё костыль для bind (в разделе Compatibility).

platedz 28.08.2012 22:04

Большое всем спасибо, буду разбираться.

platedz 02.09.2012 21:56

Интерестно, а foreach какие версии браузеров поддерживают?


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