Отправляет email-рассылки с помощью сервиса Sendsay

Программирование на JavaScript

  Все выпуски  

Древовидное меню с помощью JavaScript


Информационный Канал Subscribe.Ru


Азы и секреты программирования на JavaScript N 24

Ссылка на архив предыдущих выпусков: http://subscribe.ru/
Статистика рассылки: http://subscribe.ru/

Древовидное меню (окончание)

Вначале хочу извиниться за небольшую неточность, случайно допущенную мной в предыдущем выпуске рассылки, в примере файла меню mnu.js. Чтобы меню отображалось правильно, необходимо, чтобы символы табуляции входили в состав частей текстовых строк и были внутри кавычек. А в приведенном примере в строках 5-8 отступы табуляции оказались слева от кавычек. Для корректной работы необходимо, чтобы символ кавычек стоял в первой позиции строки.

Нам осталось рассмотреть еще несколько элементов, чтобы разрабатываемое древовидное меню навигации начало работать. Ключевым моментом здесь является, конечно индексный HTML-файл. Название "индексный" здесь условное. Имя файла может быть любое. Просто по-умолчанию первой грузится страница с именем "index" или "default" - я выбрал первый вариант. Рассмотрим его состав в сокращенном виде:

<HTML><HEAD><TITLE>Построение древовидного меню</TITLE>
<SCRIPT SRC="mnu.js">     /* меню */  </SCRIPT>
<SCRIPT SRC="stack.js">   /* класс стека */  </SCRIPT>
<SCRIPT SRC="simptree.js">/* класс дерева */ </SCRIPT>
<SCRIPT SRC="treecon.js"> /* контроллер */   </SCRIPT>
<SCRIPT SRC="hdrtree.js"> /* конструктор */   </SCRIPT>
</HEAD>
<BODY onload="headerController(window.mnuTree,myHTMLmnu)">
<table cellpadding="10" height="100%" width="100%"><tr height="5%">
<td colspan="2" align="center" bgcolor="#E3E3E3" valign="middle">
<FONT FACE="MS Sans Serif" COLOR="#FF0080" size="5">Древовидное меню</FONT>
</td></tr><tr><td valign="top" width="20%" bgcolor="#E3E3E3">

<DIV id=mnuTree>Загрузка меню - подождите...</DIV>

</td><td width="80%" valign="top">
<iframe name="mainfr" src="href_0.html" width="100%" height="100%" frameborder="0"></iframe>
</td></tr></table>
</BODY></HTML>

Что здесь наиболее важно? В заголовке файла указано, что вначале надо загрузить пять файлов JavaScript. Конечно, вы можете объединить код всех пяти файлов в один и разместить код непосредственно в данном HTML-файле. Но если нам надо использовать отдельные блоки кода повторно, то логично разделить их в разные файлы по смысловому содержанию. Кроме того, так удобнее модифицировать код, когда чисто зрительно видишь логически завершенный и работающий компактный блок кода.

Назначение первых трех модулей нам уже известно: mnu.js - это содержание меню; stack.js - структура, описывающая класс стека; simptree.js - структура, описывающая класс древовидной структуры. Кроме этих файлов появились еще два - это контроллер, который отвечает за работу структуры меню на HTML страничке, за внешний вид меню и отклик на события мыши. И файл hdrtree.js, который я условно назвал "конструктор". Этот файл выполняет непосредственное построение структуры меню, используя информацию, полученную из массива, описывающего меню в файле mnu.js.


/* Файл "treecon.js"
создание древовидного контроллера
----------------------------------*/

function TreeController(theOb,theTree){
//  alert(theOb);
  this.theOb = theOb; // Указывает на элемент, куда вставлять меню
  this.theTree = theTree; // Указывает, что вставлять
  this.name = theOb.id;
  TreeController[this.name]=this;
  this.init(); //формирует контроллер
}

function tc_init(){
// фомирует контроллер меню и заносит его в указанный элемент страницы
  this.path = '';
  this.path+="TreeController."+this.name+".";
  var HT = this.consControl(this.theTree,"");
  this.theOb.innerHTML = HT.length==0?"Меню недоступно.":HT;
  //замена текста "Загрузка меню..." в указанном элементе
  this.setULs(this.theTree,this.theOb);
}

function tc_setULs(tree,ob){
  tree.ul=ob; // создает UL таги
  for(var i=0;i<tree.numChildren();i++)
    tc_setULs(tree.getNth(i),ob.children[1+2*i])
}

function tc_toggle(imageObj,ev){
// переключатель иконок в меню
  var tAddr = imageObj.name.substring(2);
  var T=this.theTree.getSubTree(tAddr);
  var ul=T.ul;
  if(!ul){alert("help, no list for image "+imageObj.name); return;}
  if(ul.className=="closed"){ul.className="open";imageObj.src='open.gif';}
  else {ul.className="closed";imageObj.src='close.gif';}
  ev.cancelBubble=true;
}

function tc_consTitle(label,tAddr,hasChildren){
// формирует заголовки меню
  var imclickStr= " onclick='"+this.path+"toggle(this,event)'";
  var imStr;
  if(hasChildren) {
   imStr="<IMG name='im"+tAddr+"' SRC='close.gif'"+imclickStr+
    " style="\""cursor:hand;\" title=\"развернуть/свернуть ветвь\"> ";
  } else {
   imStr="<IMG SRC=\"empty.gif\"> ";
  }
  var S="<SPAN>"+ imStr + label + "<BR></SPAN>";
  return S;
}

function tc_consControl(tree,tAddr){
//формирование HTML текста меню для вывода в броузер
  if(!tree)return "";
  var N=tree.numChildren();
  tree.tAddr=tAddr;
  if(!this.showTop && tAddr==""){
    var S="";
    for(var i=0;i<N;i++)S+=this.consControl(tree.getNth(i),""+(i+1));
    return S;
  }
  var S= this.consTitle(tree.label,tAddr,N>0);
  S+= "<UL class=closed name='ul"+tAddr+"'>\n ";
  for(var i=0;i<N;i++){
    S+=this.consControl(tree.getNth(i),tAddr+"."+(i+1));
    }
  return S+"</UL>\n";
}
function tc_openTree(addr){ // Открывает ветку
  if(!addr)return; var T=this.theTree;
  addr=addr.split(".");
  for(var i=0;i<addr.length;i++){
    var N=parseInt(addr[i],10)-1;
    var img=T.ul.children[2*N].children[0]; if(!img)return;
    img.src="open.gif";
    T=T.getNth(N);
    T.ul.className="open";
  }
}
function tc_closeTree(){// Закрывает ветку
  var A=new Array(); A[0]=this.theTree;
  while (A.length>0){
    var T=A[A.length-1];A.length-=1;
    if(T.ul)T.ul.className="closed";
    for(var i=0;i<T.numChildren();i++){
      A[A.length]=T.getNth(i);
      var img=T.ul.children[2*i].children[0];
      if(img)img.src="close.gif";
      }
    }
}
TreeController.prototype.init=tc_init;
TreeController.prototype.setULs=tc_setULs;
TreeController.prototype.toggle = tc_toggle;
TreeController.prototype.consTitle = tc_consTitle;
TreeController.prototype.consControl = tc_consControl;
TreeController.prototype.openTree=tc_openTree;
TreeController.prototype.closeTree=tc_closeTree;
// файл hdrtree.js
// ====================
function headerController(mnuTag,mnuArray){
  var hTree=getTopHeaderTree(mnuArray);
  var TC= new TreeController(mnuTag,hTree);
}
function getTopHeaderTree(MnuArrow){
  var HG=new Traverser(MnuArrow);
  var T= makeHeaderTree(HG);
  return T;
}
function makeHeaderTree(HG){
// Функция формирования дерева меню
  var item = HG.current;
  var strMnu;
  strMnu = getText(item);
  if (!(getHref(item)==-1)) {
 strMnu = "<A class=\"mnu\" href=\"" +
  getHref(item) + "\" title=\"" +
  getTitle(item) + "\" target=\"" + mnuTarget + "\">" + strMnu + "</A>";
  }
  var T=new Tree(strMnu);
  HG.getNext();  // the next header after "item"
  while(myhdrLevel(HG.current) > myhdrLevel(item))
   T.addLeg(makeHeaderTree(HG));
  return T;
}
function getText(item) {
// Получение текста ссылки
 if (!item) return -1;
 else {
  tmpArr=new Array();
  tmpArr=item.split("|");
  return tmpArr[0];
 }
}
function getHref(item) {
// Возвращает адрес ссылки, если он существует
 if (!item) return -1;
 else {
  tmpArr=new Array();
  tmpArr=item.split("|");
  if (!tmpArr[1]) return -1;
  else return tmpArr[1];
 }
}
function getTitle(item) {
// Возвращает подсказку для ссылки
 if (!item) return -1;
 else {
  tmpArr=new Array();
  tmpArr=item.split("|");
  if (!tmpArr[2]) return "";
  else return tmpArr[2];
 }
}
// Подсчет табуляторов перед строкой меню
function myhdrLevel(str){
 if (!str) return -1;
 else{
  var k=0;
  for(var i=0;str.length;i++){
   if(str.charAt(i)=="\t"){
    k++;
   }else{return k}}
  return k;
 }
}
/*class: конструктор и один метод */
function Traverser(mArr){
// Заносим в стек все элементы массива меню
  this.Stk=new Stack();
  for(var i=mArr.length-1;i>=0;i--){
   this.Stk.push(mArr[i]);
  }
}
function trav_Next(){
  while(true){
    if(this.Stk.isEmpty())return this.current = null;
    var x=this.Stk.pop();
    return this.current = x;
    }
}
Traverser.prototype.getNext=trav_Next;

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

Вот в общем и все. После загрузки HTML странички в броузер событие onload вызывает функцию с двумя параметрами
onload="headerController(window.mnuTree,myHTMLmnu)".
Первый параметр (window.mnuTree) указывает на идентификатор HTML - элемента, расположенного на страничке, который обозначает место, где расположить меню. Текст в этом элементе будет заменен текстом меню после загрузки. Второй параметр (myHTMLmnu) указывает на имя массива, откуда берется информация для построения меню (массив расположен в файле mnu.js).

Рабочий пример меню с комментариями расположен на script.inc.ru.


Eсли Вы ищете качественный и недорогой web-хостинг, лично я рекомендую PeterHost.Ru. Российский (поддержим наших!), прекрасные каналы, сервис "на уровне".

Автор и ведущий рассылки И. Балезин
Лучший хостинг в Рунете

InterReklama Advertizing
Интерреклама. Интернет

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное