idを作りながらページ内目次をつくる

id属性のないh2要素

「応用 ページ内目次をつくる」ではidの書いていない h2 要素は目次にはなりましたが、リンクは働きません。href="" に書くべき文字列が取得できないからです。

今回はidのないh2要素にjavascriptで自動的にidをつけ、それをリンクに使うことにします。

(ただしver3.5あたりのfirefoxだとidがない場合のリンク先は「#null」になります。属性がないという意味のnullをそのまま値として使ってしまっています。これは不正だと思います。もし別にid="null"があればそちらにリンクしてしまいます。)

htmlの条件

htmlではh2タグがある。idはあってもよいしなくても良い。

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

javascriptがする作業

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

<h2>第一章</h2>

      ⬇

<a href="#auto1">第一章</a>
.......
<h2 id="auto1">第一章</h2>

olとして加える

<ol>
<li><a href="#auto0">第一章</a></li>
<li><a href="#auto1">第二章</a></li>
<li><a href="#auto2">第三章</a></li>
<li><a href="#auto3">第四章</a></li>
</ol>

もし、idがあるh2要素だったときはそのidを使います。これは他のページからの参照をさせたいh2には予めidをつけておくほうが便利だからです。

autoという文字列は安易な例です。htmlの作者がたまたま同じidをつけてしまうことがないように、使いそうもない文字列にしたほうがいいでしょう。

idがないときにも使えるプログラム

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

window.onload = function() {
   var emth2s = document.getElementsByTagName("h2");
   var emtol = document.createElement("ol");
   emth2s[0].parentNode.insertBefore(emtol,emth2s[0]);
   var ct = 0;
   for(var i=0;emth2s.length>i;i++){
      var idval   = emth2s[i].getAttribute("id");      
      if (! idval ){
          idval = "auto"+ct;
          ct=ct+1;
          emth2s[i].setAttribute("id",idval);      
       }
      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 に入れます。

idvalがnullの時や空文字列の時にidの値をautoに連番をつけたものにして、属性を設定します。

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

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

idがない場合は、

<h2>第一章</h2>
なら、
idval   = "auto0";
textval = "第一章";
とし、htmlも、
<h2 id="auto0">第一章</h2>
とします。(あくまでメモリ上です。ファイルは変更されません)

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>

この後はダミー ◆◆

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

null undefined false 0 ''

特殊な値、プリミティブ値?

100番目の要素がないときに.item()でアクセスするとnull, 配列要素としてアクセスするとundefindとなる。

function fnc201(){
    var list = document.getElementsByTagName('a');
    var elm1 = list.item(100); //null
    alert(elm1);
    var elm2 = list[100]; //undefined
    alert(elm2);
}

run

属性で title="spantitle" class="" という場合、classは空文字列、設定されていないidはnull

function fnc202(koko){
    var txttitle = koko.getAttribute("title");
    var txtclass = koko.getAttribute("class");
    var txtid = koko.getAttribute("id");
    alert("title:"+txttitle+"/ class:"+txtclass+"/ id:"+txtid);
}
// title:spantitle/ class:/ id:null

run <span title="spantitle" class="" onclick="fnc202(this)">

nullもundefinedも直接指定できる。

function fnc203(koko){
    var msg;
    msg = msg + ":var_not_set_value_yet \n";    //undefined
    var testvar = undefined;
    msg += testvar + ":var_set_to_undef \n";    //undefinedにできる
    testvar == undefined? 
           msg+=" testvar == undefined:true\n":
           msg+=" testvar == undefined:false\n";
    var testvar = null;
    msg += testvar + ":var_set_to_null \n";     //nullにできる
    testvar == null?
       msg+=" testvar ==  null:true\n":
       msg+=" testvar ==  null:false\n";
    testvar === null?
       msg+=" testvar === null:true\n":
       msg+=" testvar === null:false\n";
    var testvar = 'null';
    msg += testvar + ":var_set_to_'null' \n";   //'null'と区別できるか
    testvar == null?
       msg+=" testvar ==  null:true\n":
       msg+=" testvar ==  null:false\n";
    testvar === null?
       msg+=" testvar === null:true\n":
       msg+=" testvar === null:false\n";
    testvar == 'null'?
       msg+=" testvar ==  'null':true\n":
       msg+=" testvar ==  'null':false\n";
    testvar === 'null'? 
       msg+=" testvar === 'null':true\n":
       msg+=" testvar === 'null':false\n";
    var testnul = 'null';
    testvar = null;
    msg += "compare "+testvar+" with "+testnul+"\n";  //nullも'null'も表示は同じ
    testvar == testnul? 
       msg+=" testvar ==  testnul:true\n":
       msg+=" testvar ==  testnul:false\n";
    testvar === testnul?
       msg+=" testvar === testnul:true\n":
       msg+=" testvar === testnul:false\n";
    testvar = undefined;
    testnul = null;
    msg += "compare "+testvar+" with "+testnul+"\n";  //undefined-null
    testvar == testnul? 
       msg+=" testvar ==  testnul:true\n":
       msg+=" testvar ==  testnul:false\n";
    testvar === testnul?
       msg+=" testvar === testnul:true\n":
       msg+=" testvar === testnul:false\n";
    alert(msg);
}

run

undefined:var_not_set_value_yet 
undefined:var_set_to_undef 
 testvar == undefined:true
null:var_set_to_null 
 testvar ==  null:true
 testvar === null:true
null:var_set_to_'null' 
 testvar ==  null:false
 testvar === null:false
 testvar ==  'null':true
 testvar === 'null':true
compare null with null
 testvar ==  testnul:false
 testvar === testnul:false
compare undefined with null
 testvar ==  testnul:true
 testvar === testnul:false

リンク

JavaScript初級者から中級者になろう

木構造の操作:さまざまな機能

nullとundefined

楽:技林ブログ

コメントアウト記法まとめ

経済産業省による文字情報基盤整備事業

経済産業省による文字情報基盤整備事業

クッキー

とほほ

Cookieの概要と使い方

クッキーの利用判別

この後はダミー ◆2◆

NaNの値はNumber.NaNプロパティで取得することができます。JavaScript 1.3以降ではNumber.NaNを値に持つグローバル変数NaNが定義されていますが、グローバル変数NaNは後方互換のため、JavaScriptのプリミティブ値ではなく書き換え可能な変数として定義されています。NaNの値を取得する必要がある場合はNumber.NaNプロパティを使用してください。

alert( NaN ); // "NaN"
NaN = 1;
alert( NaN ); // "1"
alert( Number.NaN ); // "NaN"

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

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の場合 ;

nodeName,nodeType

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 初稿