Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Выбор нужного элемента дом дерева (https://javascript.ru/forum/events/30865-vybor-nuzhnogo-ehlementa-dom-dereva.html)

Elve 18.08.2012 13:33

Выбор нужного элемента дом дерева
 
Доброго времени суток, вот по чуть учу Js и столкнулся с задачей, которую не получается решить. Может вы подскажите в чем моя ошибка.
Задача: Вот так выглядит страница. В каждом вложенном диве есть еще элементы. Задача поменять местами второй и третий див. У них есть классы но нет Id. Обязательно делать именно жс и кроссбраузерно.
<div id="content-wrap">
  <div></div>
  <div></div>
  <div></div>
</div>

Вот я написал такое дело
var main = document.getElementById('content-wrap')
var divall = main.getElementsByTagName('div')
main.appendChild(divall[1])

Логика моя: Выбрали див с ид content-wrap. Пробежались по нему и выбрали все div. Див который второй взяли и перекинули в конец родителя. При таком коде мне Лисичка пишет

TypeError: main is null
var divall= main.getElementsByTagName('div')

cyber 18.08.2012 15:02

<!DOCTYPE HTML>
<html>
  <head> </head>
  <body>
<div id='wrapper'> 
    <div>1 </div>
    <div> 2</div>
    <div>3 </div>
    <div> 4</div>
  </div>  
  <script>

var wrapper_ = document.getElementById('wrapper');

var elem =  wrapper_.children[1];
   
 wrapper_.insertBefore(elem, wrapper_.children[3])  
    


    </script>

  </body>
</html>

Elve 18.08.2012 21:45

Спасибо большое, как же все просто было...

Aetae 18.08.2012 22:56

main is null
Т.е. нет элемента с таким id. С вероятностью 100% вы запускаете скрипт раньше чем в коде появляется данный элемент. Javscript выполняется по мере загрузки, а не после.(если вы специально того не обозначите)

...
<div id="content-wrap">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>
<script type="text/javascript">
var main = document.getElementById('content-wrap')
var divall = main.getElementsByTagName('div')
main.appendChild(divall[1])
</script>

Aetae 18.08.2012 23:02

И да, решение от cyber, не будет работать если элементов 3, надо так:
var wrapper_ = document.getElementById('wrapper');
var elem =  wrapper_.children[1];
wrapper_.insertBefore(elem, wrapper_.children[3] || null) //ксли вторым параметром null - работает как appeendChild, а если undefined - кидает ошибку

Elve 18.08.2012 23:21

А вот у меня возник еще один вопрос, задача стояла куда более обширно нежели тут описал в итоге поучил вот такой код
<script>
	var wrapper_ = document.getElementById('content-wrap');
	var elem =  wrapper_.children[4];
	var after_main =  wrapper_.children[2];
	after_main.style.width = "900px";
	var after_main_stage1 = after_main.children[0];
	var after_main_stage2 = after_main.children[1];
	after_main_stage1.style.cssText = "float:left;\ ";
	after_main_stage1.rule.style.cssText = "float:left;\ ";
	after_main_stage2.style.cssText = "float:left;\ ";
	var after_main_stage3 = after_main_stage2.children[1];
	after_main_stage3.style.cssText = "float:left;\
	width:300px;\ " ;
 	wrapper_.insertBefore(elem, wrapper_.children[2]) 
	wrapper_.children[2].style.width = "940px";
	var cat_ch3 = elem.children[0];
	var cat_ch4 = cat_ch3.children[1];
	var light = elem.children[1];
	var light2 = elem.children[2];
	cat_ch4.parentNode.insertBefore(light2, cat_ch4.nextSibling);
	cat_ch4.parentNode.insertBefore(light, cat_ch4.nextSibling);
	elem.children[0].style.cssText = "position:relative ; \ ";
	light.style.cssText="position:absolute;\
	bottom:45px; \ ";
	light2.style.cssText="position:absolute;\
	bottom:25px; \ ";
	var float_l = document.getElementsByTagName('td');
	var text_float = float_l[0];
	var text_float_stage1 = text_float.children[0];
	var dd_st = text_float_stage1.getElementsByTagName('dd');
	for (var i=0; i < dd_st.length; i++)
	 {
		dd_st[i].style.cssText="float:left !important; \
		width:160px;\ ";
	 }
	var dt_st = text_float_stage1.getElementsByTagName('dt');
	for (var i=0; i < dt_st.length; i++)
	 {
		dt_st[i].style.cssText="float:left !important; \
		width:120px;\ ";
	 }/**/
	var td_1 =  document.getElementsByTagName('td');
	td_1[0].style.cssText = "width:300px;\
	padding-top:21px;\
	float:left;\ ";
	td_1[1].style.cssText = "float:left; \ ";
	var float_l_stage1 = float_l[1];
	var float_l_stage2 = float_l_stage1.children[0];
	var float_l_stage3 = float_l_stage2.children[1];
	var float_l_stage4 = float_l_stage3.children[0];
	float_l_stage4.children[0].style.width = "570px";
	float_l_stage4.children[0].style.height = "125px";
	var btn = document.getElementById('btn_holder');
	var btn_prev = btn.previousElementSibling ;
	
	btn.style.cssText="float:left !important; \
	";
	btn_prev.style.cssText="float:left !important; \
	margin-left:250px;\ ";
	var width_line = document.getElementById('updates');
	width_line.children[0].style.cssText = "width:200px;\ ";
  </script>

И все бы хорошо, все работает так как надо КРОМЕ IE ниже 9... Я так понял нельзя использовать cssText , но на что заменить и как?

Aetae 18.08.2012 23:32

Нет, cssText работал всегда. Дело в previousElementSibling, ie<9 не знают такого.

Сразу напишу функцию, но на самом деле лучше вообще не использовать:
function prev( el ){
  while(el=el.previousSibling) if(el.nodeType === 1) break;
  return el
}

Elve 18.08.2012 23:40

after_main_stage1.style.cssText = "float:left;\ ";
мне отладчик ИЕ ругается на это и пишет

SCRIPT5007: Не удалось получить значение свойства "style": значением объекта является NULL или он не определен
Contact Us.htm, строка 229 символ 2

А что с этой функцией написанной вами делать? В смысле где ее вызывать и с какой целью

Aetae 18.08.2012 23:45

Очевидно, что проблема с after_main_stage1, в котором вообще нет style;
Сделайте
alert(after_main_stage1)
и посмотрите, что он вам напишет.

Цитата:

Сообщение от Elve (Сообщение 198661)
А что с этой функцией написанной вами делать? В смысле где ее вызывать и с какой целью

Вместо el.previousElementSibling использовать prev( el ).

Elve 19.08.2012 01:04

Спасибо Aetae за помощь, но вопрос актуален... Получается, что ИЕ видит Коментарии в коде и принимает их как часть кода... Как бы это обойти, может кто подскажет?

cyber 19.08.2012 02:08

Цитата:

Сообщение от Aetae (Сообщение 198651)
И да, решение от cyber, не будет работать если элементов 3, надо так:
var wrapper_ = document.getElementById('wrapper');
var elem =  wrapper_.children[1];
wrapper_.insertBefore(elem, wrapper_.children[3] || null) //ксли вторым параметром null - работает как appeendChild, а если undefined - кидает ошибку

нет, вы ошибаетесь

<!DOCTYPE HTML>
<html>
  <head> </head>
  <body>
<div id='wrapper'> 
    <div>1 </div>
    <div> 2</div>
    <div>3 </div>
    
  </div>  
  <script>

var wrapper_ = document.getElementById('wrapper');

var elem =  wrapper_.children[1];
    alert(wrapper_.children[3] == null);//wrapper_.children[3] == undefined, a undefined == null
    
 wrapper_.insertBefore(elem, wrapper_.children[3])  
    


    </script>

  </body>
</html>

cyber 19.08.2012 02:46

что бы убрать все лишние элементы (комментарии, пробелы и ...) написал функцию remove_TextNode (кроссбраузерно)
<!DOCTYPE HTML>
<html>
  <head> </head>
  <body>
<div id='wrapper'> 
    <div>1 </div>
    <div> 2</div>
  <!--text-->
    <div>3 </div>
    
  </div>  

  <script>

var wrapper_ = document.getElementById('wrapper');

 var divs = wrapper_.getElementsByTagName('div');
 


 console.log(wrapper_.childNodes);
 console.log( remove_TextNode(wrapper_.childNodes));
    
    function remove_TextNode (array) {
    
      var leng = array.length;
      var elemArray, resultArray = [];
      
      for (var i = 0; i < leng;i++) {
      
       elemArray = array[i];
     
        if (elemArray.nodeType != 1) continue;
        
        
        resultArray.push(elemArray);
      }
    
     return resultArray;
    }
    


    </script>

  </body>
</html>

lord2kim 19.08.2012 08:01

Цитата:

Сообщение от cyber (Сообщение 198682)
нет, вы ошибаетесь

<!DOCTYPE HTML>
<html>
  <head> </head>
  <body>
<div id='wrapper'> 
    <div>1 </div>
    <div> 2</div>
    <div>3 </div>
    
  </div>  
  <script>

var wrapper_ = document.getElementById('wrapper');

var elem =  wrapper_.children[1];
    alert(wrapper_.children[3] == null);//wrapper_.children[3] == undefined, a undefined == null
    
 wrapper_.insertBefore(elem, wrapper_.children[3])  
    


    </script>

  </body>
</html>

в IE < 9 как минимум ваш вариант не буит робить...нужно делать как написал Aetae

Elve 19.08.2012 11:03

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Документ без названия</title>
</head>

<body>
<div id="content-wrap">
<!--text1-->
<div></div>
<div></div>
<!--text 2 -->
<div></div>

</div>
<script>
var wrapper_ = document.getElementById('content-wrap');
	/*var elem =  wrapper_.children[4];*/
	var divs = wrapper_.getElementsByTagName('div');

	
	console.log(wrapper_.childNodes);
 	console.log(remove_TextNode(wrapper_.childNodes));
    
    function remove_TextNode (array) {
    
      var leng = array.length;
      var elemArray, resultArray = [];
      
      for (var i = 0; i < leng;i++) {
      
       elemArray = array[i];
     
        if (elemArray.nodeType != 1) continue;
        
        
        resultArray.push(elemArray);
      }
    
     return resultArray;
    }
</script>
</body>
</html>

Вот это запускаю в ИЕ и ноль на массу... :(

cyber 19.08.2012 14:46

я запускал это в ие 8 и все работало

Deff 19.08.2012 15:05

cyber,
Не робит ие6-8

cyber 19.08.2012 15:13

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Документ без названия</title>
</head>
 
<body>
<div id="content-wrap">
<!--text1-->
<div></div>
<div></div>
<!--text 2 -->
<div></div>
 
</div>
<script> 
var wrapper_ = document.getElementById('content-wrap');
	/*var elem =  wrapper_.children[4];*/
	var divs = wrapper_.getElementsByTagName('div');
 
	
	alert('до обработки ='+wrapper_.childNodes.length+" после="+remove_TextNode(wrapper_.childNodes).length);
 	
    
    function remove_TextNode (array) {
    
      var leng = array.length;
      var elemArray, resultArray = [];
      
      for (var i = 0; i < leng;i++) {
      
       elemArray = array[i];
     
        if (elemArray.nodeType != 1) continue;
        
        
        resultArray.push(elemArray);
      }
    
     return resultArray;
    }
</script>
</body>
</html>


cyber 19.08.2012 15:16

Цитата:

Сообщение от lord2kim (Сообщение 198693)
в IE < 9 как минимум ваш вариант не буит робить...нужно делать как написал Aetae

хм..
вы правы, не работает, но пародкс в том что

alert(wrapper_.children[3] == null);//возвращает true

lord2kim 19.08.2012 15:24

cyber, не важно, что он возвращает, важно что IE это не воспринимает)))

cyber 19.08.2012 15:27

Цитата:

Сообщение от lord2kim (Сообщение 198770)
cyber, не важно, что он возвращает, важно что IE это не воспринимает)))

кто вообще ие назвал браузером:-E

Aetae 19.08.2012 15:54

wrapper_.children[3] //undefined, а не null
alert(wrapper_.children[3] === null);//возвращает false

alert([ 
undefined == null,
undefined ===  null
])

cyber 19.08.2012 16:26

Цитата:

Сообщение от Aetae (Сообщение 198776)
wrapper_.children[3] //undefined, а не null
alert(wrapper_.children[3] === null);//возвращает false

alert([ 
undefined == null,
undefined ===  null
])

хм.. понял , был не прав.
а можно ссылочку прочитать про то почему они равны, потому что помню что undefined == null, а почему не могу вспомнить

Aetae 19.08.2012 16:32

Потому же почему и
alert(0==false)
и
alert('' == 0)
. Приведение типов.)

cyber 19.08.2012 16:36

Цитата:

Сообщение от Aetae (Сообщение 198787)
Потому же почему и
alert(0==false)
и
alert('' == 0)
. Приведение типов.)

ну так это понятно, false при переводе в число == 0 и со строкой тоже.
Ну если меня память не подводит то в учебнике было написано что они сравниваются "как есть"

Elve 19.08.2012 21:17

Спасибо за помощь
 
Сбасибо Aetae и cyber за то, что помогли новичку разобраться в работе с DOM деревом. Итак теперь код, который работает для тех, кто возможно столкнется с подобной задачей
Код:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Документ без названия</title>
</head>
 
<body>
<div id="content-wrap">
<!--text1-->
<div>1</div>
<div>2</div>
<!--text 2 -->
<div>3</div>
 
</div>
<script>
      function prev( el ){
                  while(el=el.previousSibling) if(el.nodeType === 1) break;
                  return el
        }
        var wrapper_ = document.getElementById('content-wrap');
        var elem =  wrapper_.children[2];
        var divs = wrapper_.getElementsByTagName('div');
 
       
        alert('до обработки ='+wrapper_.childNodes.length+" после="+remove_TextNode(wrapper_.childNodes).length);
        console.log(wrapper_.childNodes);
        wrapper_n = remove_TextNode(wrapper_.childNodes);

   
    function remove_TextNode (array) {
   
      var leng = array.length;
      var elemArray, resultArray = [];
     
      for (var i = 0; i < leng;i++) {
     
      elemArray = array[i];
   
        if (elemArray.nodeType != 1) continue;
       
       
        resultArray.push(elemArray);
      }
   
    return resultArray;
    }
        after_main =  wrapper_n[2]
        wrapper_.insertBefore(elem, wrapper_n[1] || null);
</script>
</body>
</html>

И П.С. К этому счастью: function prev( el ) - функция замена previousSibiling для работы кроссбраузерно
function remove_TextNode (array) - для работы с массивом вложенных элементов в том случае, если в коде есть комментарии ( Коменты ИЕ видит как отдельный элемент и поэтому работа под ИЕ и под другими браузерами будет сильно отличаться.)
children в ие ниже 9 версии вроде работает( лично у меня работает в 7 и 8 версии)

cyber 19.08.2012 21:42

хочу уточнить что функции remove_TextNode отсеивает все кроме обьектов (тэгов), т.е удаляет комментарии , текстовые узлы ...

Dargonaks 20.03.2015 16:58

Всем доброго время, подскажите пожалуйста как заставить работать такую конструкцию
<script type="text/javascript">
window.onload = afterLoad;
function afterLoad() {
	var maina = document.getElementsByClassName('top_menu_test'); // находим узел
	var newAttr1 = document.createAttribute('rel'); // создаем атрибут
	newAttr1.value = 'nofollow';  // устанавливаем значение
	maina.setAttributeNode(newAttr1);  // привязываем атрибут
};

</script>
<a class="top_menu_test" href="http://mail.ru">http://mail.ru</a>

Aetae 20.03.2015 17:43

var maina = document.getElement*!*s*/!*ByClassName('top_menu_test')*!*[0]*/!*;
Elements - множественное число, результат NodeList(массивоподобный объект) и если элемент с таким классом один - значит он там нулевой.

А вообще лучше не использовать getElementsByClassName (ибо не работает в ie8), в вашем случае отлично подойдёт:
var maina = document.querySelector('.top_menu_test');

Dargonaks 21.03.2015 22:45

большое спасибо добрый человек

Dargonaks 23.03.2015 09:45

а на будующее не могли бы подсказать пример для такого случая:
<script type="text/javascript">
window.onload = afterLoad;
function afterLoad() {
	var maina = document.querySelectorAll('.top_menu_test'); // находим узел
	var newAttr1 = document.createAttribute('rel'); // создаем атрибут
	newAttr1.value = 'nofollow';  // устанавливаем значение
	maina.setAttributeNode(newAttr1);  // привязываем атрибут
};

</script>


<a class="top_menu_test" href="http://mail.ru">http://mail.ru</a><br>
<a class="top_menu_test" href="http://yandex.ru">http://yandex.ru</a><br>
<a class="top_menu_test" href="http://google.ru">http://google.ru</a><br>

Aetae 23.03.2015 14:38

Dargonaks,
http://learn.javascript.ru/while-for


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