応用 ページ内目次をつくる

次のようにリンクを書くことで、クリックで id="hoge" とあるタグのところが表示されるようになります。

<a href="#hoge">id="hoge" とあるタグのところへ</a>

id="hoge" とあるタグのところへ

長くスクロールするページの場合、このリンクがあれば「目次」として使えて便利です。

でもこの目次を手作業で作るのは面倒なのでjavascriptにさせようというわけです。

htmlの条件

htmlではh2タグにidが記述されている。

headにjavascriptがあり、onloadで実行されるようにする。

javascriptがする作業

h2タグのidをリンクに、h2の内容をリンク文字列にする

<h2 id="chap01">第一章</h2>

      ⬇

<a href="#chap01">第一章</a>

olとして加える

<ol>
<li><a href="#chap01">第一章</a></li>
<li><a href="#chap02">第二章</a></li>
<li><a href="#chap03">第三章</a></li>
<li><a href="#chap04">第四章</a></li>
</ol>

プログラム

window.onload = function() { … } と書くことで、ページが読み込まれたときに実行されます。

window.onload = function() {
   var emth2s = document.getElementsByTagName("h2");
   var emtol = document.createElement("ol");
   emth2s[0].parentNode.insertBefore(emtol,emth2s[0]);

   for(var i=0;emth2s.length>i;i++){
      var idval   = emth2s[i].getAttribute("id");      
      var textval = emth2s[i].firstChild.nodeValue;
      var textnd = document.createTextNode(textval);
      var emta = document.createElement("a");
      emta.appendChild(textnd);
      emta.href = "#"+idval;
      var emtli = document.createElement("li");
      emtli.appendChild(emta);
      emtol.appendChild(emtli);
   }
}

まずページ内の h2 要素を拾って配列をつくり emth2s という名前をつけます。

新しく ol要素をつくり、emtol という名前をつけます。

最初のh2要素(emth2s[0])の前に配置(insertBefore)します。

このol要素はまだ空っぽですが、この後詰め込んでいきます。もちろん先にol要素の内容まで作って置いてから最後にinsertBeforeしてもかまいません。

forを使ってh2要素の数だけ繰り返します。

h2要素のid属性の値を idval に入れます。

h2要素の中のテキストノードからテキストを取り出して textval に入れます。

<h2 id="chap01">第一章</h2>
なら、
idval   = "chap01";
textval = "第一章";
とすることです。

textval からテキストノードを作って、textnd と名前をつけます。

a要素を作って emta と名前をつけます。

そのa要素 emta にテキストノード textnd を付け加え、

さらに href属性を付け加えます。href属性の値は idval に # 文字を加えたものにします。

<a href="#idval">textval</a>
(実際には idval, textval の内容が入ります)

li要素を作って emtli と名前をつけます。

そのli要素 emtli に a要素 emta を付け加え、

そのli要素 emtli を ol要素 emtol に加えます。

<ol>
<li><a href="#idval">textval</a></li>
</ol>

課題 ファイル名 dom5.html

このページ「応用 ページ内目次をつくる」の説明にしたがってページ内目次が自動でできるページをつくりなさい。

内容は何でも構わないが、テキストのページをそのままコピーしたものは課題をやったことにしない。

index.htmlからは「ページ内目次」という名前のリンクから行けるようにすること。

この後はダミー ◆◆

この後は説明のためh2を増やしています。内容は関係ありません

DOMの歴史

WWWコンソーシアム(W3C),DOMの標準化。 1997年に策定作業が開始され, 1998年に「DOM Level 1」勧告 大幅に機能の強化を図った「DOM Level 2」が2003年1月に勧告 「DOM Level 3」が2004年4月に勧告

W3C DOMは,プログラミング言語に依存しない規定として策定されています。実際には,JAVA,PHP,Perlといったなじみのプログラミング言語でも,書き方に違いはあるものの,W3C DOMをサポート

最もシェアが高いInternet Explorerが,W3C DOMの準拠が遅れているため,完全には同じコードで済ますことはできません。しかし,W3C DOMとほぼ同じことがInternet Explorerでも独自の方法で利用することが可能です。

配列かリストか

var list = document.getElementsByTagName('a');
var elm = list.item(1);
alert(elm.href);
var elm = list[1];
alert(elm.href);

run

後方互換性

未対応のブラウザが誤動作をするのを防ぐため

if (!document.getElementsByTagName) return false;
if (!document.getElementById) return false;
if (!document.getElementById("hoge")) return false;

ファンクションのチェック

jsが無効にされているときを考慮して、aタグにイベントをつけている場合、jsが優先して実行されるので、js側では return false を最後に書き加えればaのリンクを無効にできる

function hoge(){
  .....
  .....
  return false;
}

逆に、js側に問題が発生したときに return true とすれば、jsの代わりに本来のaタグのリンクが有効になる。

if (!document.getElementById("hoge")) return true;

本文とjsを別ファイルで用意するとき、本文中の構造が期待通りに維持されないことが想定される。そのようなときの対策として有効。

JSによるイベントハンドラの追加

ノードリスト(getElementsByTagNameで得られる)はArray()や[]で作られる配列とは異なりpop()やshift()は使えない

.onclickで追加する

 obj.onclick = function() {......}

objはエレメントノードでないとだめなはず。ノードリストの要素でもよい。

function()は無名ファンクションといい、その場で生成する方法。

読み込み終了後実行

これば引数をつけられない

window.onload = functionname;

無名ファンクションを使えるが、これは()が必要。

window.onload = function(){
  functionname1();
  functionname2();
}

Simon Willson(http://simon.incutio.com)の方法

function addLoadEvent(func){
  var oldonload = window.onload;
  if ( typeof window.onload != 'function'){
    window.onload = func;
  } else {
     window.onload = function(){
       oldonload();
       func();
     }
  }
}

使い方は

addloadEvent(function1);
addloadEvent(function2);

nullと空文字列

nullは言語ごとに表現が異なるのでjsではnullであると強調しておく

タイトル属性がないのはnull

var elm = document.getElementById('nulltest');
var msg  = "title is null:" + (elm.getAttribute("title")==null) + "\n";
    msg += "title string :" + (elm.getAttribute("title"));
alert(msg);

run

タイトル属性が空文字列なのは null でなく空文字列

var elm = document.getElementById('emptyltest');
var msg  = "title is null:" + (elm.getAttribute("title")==null) + "\n";
    msg += "title string :" + (elm.getAttribute("title"));
alert(msg);

run

タイトル属性があり、空文字列でないのは、もちろん null ではない。

var elm = document.getElementById('hastitletest');
var msg  = "title is null:" + (elm.getAttribute("title")==null) + "\n";
    msg += "title string :" + (elm.getAttribute("title"));
alert(msg);

run

title属性がない title="" title="string"
elm.getAttribute("title")==null true false false
elm.getAttribute("title")!=null false true true
elm.getAttribute("title") null "" string

getAttribute("title")の値はgetAttribute("title")!=nullの値と異なるが、同様に使用できるという。

3項演算子 ( = ? : 構文)

ternery operator

変数 = 条件 ? trueの場合 : falseの場合 ;

この項目のidはnullである

この項目のidはnull。次の項目のフラグメントがnullなので、「nodeName,nodeType」をクリックしてもこの項目が表示されるはず。idがないときに#nullに設定されるのは不正だと思う。

nodeName,nodeType

この項目にはidがない。

nodeNameはすべて大文字となる

目的のノードがtextノードなのか確認するにはnodeTypeを使う

DOM-CORE, HTML-DOM

doc.getElementsByTagName("form") doc.form
elm.getAttribute("src") elm.src
var src = elm.getAttribute("href"); var src = elm.href;
elm.setAttribute("src",hoge); elm.src = hoge;

残したもの

画像を含むノードを作成しsetAttributeを試す。IEのテストになる

Chapter8 してはいけないことの説明の後、有用な使用例3つ。省略語のリスト、出典へのリンク、アクセスキー

スタイル

Chapter9

要素ノードは(要素オブジェクトは)プロパティを持つ

parentNode, nextSibling, previousSibling, childNodes, firstChild, lastChild,, nodeType, nodeName,, style

このstyleはオブジェクトで、スタイル情報はstyleはオブジェクトのプロパティとして保存されている。

要素.style.プロパティ

ハイフォンを含むものはマイナスと区別するためキャメルケースとする

要素.style.color
要素.style.fontFamily  /* for font-familly */

colorの値はrgb( , , )の形式に統一される

外部スタイルやstyleタグの設定はこれで読むことができない

スタイルの設定はできる

要素.style.プロパティ = 値

普通はテキストで指定するが、変数も可能

要素.style.color = "blue";
要素.style.fontFamily = 'monospace';

使うべき場所

適用すべき要素を特定

p.205 nextSiblingとnodeTypeを使ってh1の次の要素のスタイルを変える

反復的な指定

1行置きに背景色を変化させる

イベントによって変更

a要素以外にhoverを実現する(IEでもできる)

rows[i].onmouseover = function(){
  this.style.fontWeight = "bold";
}
rows[i].onmouseout = function(){
  this.style.fontWeight = "normal";
}

class変更でstyleを

jsでスタイルを設定するのは、構造、表現、振る舞いの3つを分けるという意味合いからは後味が悪い。

jsでclassを変更し、cssにしたがって見栄えが変わるほうがよく分離されているといえる

elm.setAttribute("class","rei");

または、

elm.className = "rei";

すでにあるクラスを上書きしてしまう。必要ならばクラスを調べて新しいクラスを半角スペースで連結することで解決できる

elm.className += " rei";

createElementでできるのは参照

toplinkというエレメントを作って全部のh2要素に加えるつもりだったが、objectなので最後に加えた所だけに配置される。

var topstr = "topelementdefbyjavascript";                   //String
var targetp = document.getElementsByTagName("h1").item(0);  //h1に
targetp.setAttribute("id",topstr);                          //idをつける

var items = document.getElementsByTagName("h2");            //h2タグの配列

var toptext = document.createTextNode("▲");
var toplink = document.createElement("a");
toplink.appendChild(toptext);
toplink.href = "#" + topstr;                        //リンクのノード作成

for(var i=0;items.length>i;i++){
   items[i].appendChild(toplink);  //全部のh2に同じものを
}                                                   //appendできない

appendChildメソッドが代入のようなコピーではないのは予想できる。参照ならばひとつのオブジェクトが複数から参照されることもあり得る。しかし本当にオブジェクトがあってどこかにappendするので最後にappendしたところに落ち着く。

ここがhogeです。


ウェブページ(Mar.2011)
聖愛中学高等学校
http://www.seiai.ed.jp/
Jan.2010 初稿