新ブログパーツ ScoyanSaid 改め GRANDMASTER_SAID の自分解説です。
PC版ヘッダーの左上に、すこやんのセリフをランダムに表示しています。
使用言語は JavaScript です。
需要は無くても──自己満足したいんじゃい!
以下ソース解説。
(見易くするため、一部の変数は展開 or 省略しています)
ただ、そんな風にどこかデザイン変更をするたびにテンプレートを書き換えるのは結構怖いものがあります。うっかり閉じタグひとつを書き忘れたせいで表示が滅茶苦茶になる、なんてことがたまにありますから。
またライブドアブログの場合、
そこで今回は、テンプレを直接いじらずに、ブログパーツのフリーエリアを利用してDOM要素を自動生成するようにしてみました。
新たに必要なHTML要素は、すこやんのセリフを表示するための div領域一つだけです。
文字ごとの修飾など凝った仕様にしたい場合はその下に更に div や span などを入れますが、まあ今回は取り敢えずシンプルに。
ブログのヘッダー部分のツリー構造を図にすると
テキスト色やボックスの形状は好みや必要に応じてやってもやらなくてもいいのですが、位置の設定だけは必須です。
デフォルトで static以外が指定されている場合は、必要ありません。
親要素の座標を基準にさせるため、positionプロパティを absolute に設定します。
ヘッダー領域の左上から表示させたいので、top と left で微調整します。
この定型文には無印の #grandmaster_said とは別のスタイルを指定できます(何も指定しなければ上と同じスタイルになります)。
また
以上のCSSコードを、最初に述べたようにフリーエリアにHTMLとして書き込むので、前後を<style></style>タグで括ってやります。
普通はこの呼び出し部分が無いと実行されないわけですが、ここでは読み込みだけで実行させることができる、即時関数という構文を使います。
この書き方をすれば、JSファイルの読み込みだけで実行されます。
もちろん function(){} で括らずに(処理内容)をそのまま書いても実行されますが、すると(処理内容)で定義した変数が DOM全体で有効なグローバル変数になってしまい、ほかに JSライブラリを読み込んでいる場合などに同じグローバル変数名が定義されていたらブラウザは両者を同じ変数として認識し、動作がおかしくなる可能性が高いのです。
今回はブログパーツ領域にコードを書いていくのでブログパーツ設定の読込→DOM生成 というサーバー側の動作は、厳密にいうと JSファイル読込には当らないのですが、実質的にはだいたい同じことです(アバウト)。
では、以下実際のコードの説明です。
大抵は書かなくても大丈夫ですが、万一に備えて。
この値が null であれば、操作対象であるヘッダー領域が DOM上に存在しない、ということ(エラー)なので、何もせずにこのスクリプトを抜けます。
オブジェクト変数の頭に$をつけているのは、普通の変数(数値や文字列)と区別し易くするためです。推奨しないデベロッパーの方もいるくらいで、別にルールではありません。
なお、
ただ、JavaScript ではなるべくスタイルを動的に変化させる記述にとどめ、変化しないスタイルについては CSS に定義しておいた方がいいでしょう。
個々のセリフを引用符で括って、コンマで区切り、全体を大カッコで括るだけ。
いくらでも書き足せます。
ここは結構膨大で、本来ならテキストファイルなどを別に用意してそこから読み込むべきなのでしょうが、ブログサービスのエディタで手軽に追加編集などができるように、直接 JavaScript コードの中に書いてしまいます。
これは変数というより定数で、使い所もそれぞれ一箇所なので本来そこに直接数字を書き込めばいいんですが、ここにまとめておくことでメンテがし易い意味があります。
i は表示する名言の番号、v は表示する文字の数。
ここではその初期値をセットしています。
Math.random() という関数が 0以上1未満の小数値を返すので、それを m倍し小数点以下を切り捨てる(Math.floor)ことで、0~m-1 の整数のどれかが i にセットされます。
こうしておくと、パーツにマウスオーバーした時、この文字列が表示されます。
v の値がセリフの文字列長より小さければ、vの値を1増やして v文字分を表示せよ、
v がセリフの文字列長に達したら次のセリフをランダムに選べ。
というアルゴリズムになっています。
普通、再帰関数の書き方としては
この場合、自分自身の名前ではなく arguments.callee というプロパティを呼び出してやると、再帰と同じ動作をしてくれるので、そのように書きます。
いちばん簡単なのは、
例えば FC2 だとヘッダー要素は<div id="header">になっているので、
CSS部分は
もちろんヘッダーにこだわる必要はなく、表示させたい場所の HLML要素の ID を指定すればそこに表示されます。
ソースをコピペしたフリーエリアの内部に
msg の中身を別のキャラのセリフにして、CSSのデザインをちょちょっと変えれば、オリジナルのブログパーツになりますよ。
文字を一文字づつ表示させる部分は、以前もお世話になった動くJavaScriptというサイト様の文字に関するページを参考にさせていただきました。
ここに記して御礼申し上げます。

使用言語は JavaScript です。
需要は無くても──自己満足したいんじゃい!
以下ソース解説。
HTMLの確認
まず、弊ブログのHTMLテンプレートを御覧下さい。(見易くするため、一部の変数は展開 or 省略しています)
<header id="blog-header"> <hgroup> <h1 id="blog-title"> <a href="<$BlogUrl$>"> ブログタイトルの記述(略) </a> </h1> <h2 id="blog-description"><$BlogDescription$></h2> </hgroup> </header>101行目のブログタイトルの記述(略)、という部分はもともとライブドアブログのテンプレ用変数で、<$BlogTitle$>と書いてあったのですが、タイトル文字をアニメーションさせるためにそれを削除して、HTMLの記述をカスタマイズした箇所です。
ただ、そんな風にどこかデザイン変更をするたびにテンプレートを書き換えるのは結構怖いものがあります。うっかり閉じタグひとつを書き忘れたせいで表示が滅茶苦茶になる、なんてことがたまにありますから。
またライブドアブログの場合、
- トップページ
- 個別記事ページ
- カテゴリ別ページ
- 月別ページ
そこで今回は、テンプレを直接いじらずに、ブログパーツのフリーエリアを利用してDOM要素を自動生成するようにしてみました。
新たに必要なHTML要素は、すこやんのセリフを表示するための div領域一つだけです。
文字ごとの修飾など凝った仕様にしたい場合はその下に更に div や span などを入れますが、まあ今回は取り敢えずシンプルに。
ブログのヘッダー部分のツリー構造を図にすると
<header id="blog-header">━<hgroup>┳<h1 id="blog-title">━… ┗<h2 id="blog-description">こんな感じで、とにかくヘッダー部分に表示させたいので、<header>直下にすこやんのセリフ領域(赤い下線の部分↓)を作ることにしました。
<header id="blog-header">┳<hgroup>┳<h1 id="blog-title">━… ┃ ┗<h2 id="blog-description"> ┗<div id="grandmaster_said">この領域は後ほど JavaScript で生成しますから、HTMLテンプレートは一切編集する必要がありません。
CSS
デザインの設定をします。テキスト色やボックスの形状は好みや必要に応じてやってもやらなくてもいいのですが、位置の設定だけは必須です。
#blog-header{ position: relative; }CSSのテンプレで #blog-header の positionプロパティがstaticになっているか、何も指定されていなければ、上記のように relativeで上書きします。
デフォルトで static以外が指定されている場合は、必要ありません。
#grandmaster_said{ position: absolute; top: -5px; left: 10px;セリフの表示領域のスタイルです。
親要素の座標を基準にさせるため、positionプロパティを absolute に設定します。
ヘッダー領域の左上から表示させたいので、top と left で微調整します。
width: 100%;height: 1.2em;幅と高さを指定します。
display: inline; vertical-align: middle;以上が(ほぼ)必須項目で、以下はオプションになります。
background-color: rgba(255,255,255,.2); color: rgba(85,85,85,.9); font-size: .94em; font-family: 'メイリオ'; }背景画像の関係で文字が見づらければ、背景色とフォントを指定します。
#grandmaster_said:before{ content: 'GRANDMASTER SAID '; font-size: .8em; font-weight: bold; color: steelblue; padding-left: 1em; text-shadow: 1px 1px 1px lightskyblue; vertical-align: bottom; cursor: default; }セリフの表示領域に :before という疑似クラスを与えると、領域の頭に contentプロパティで指定した定型文を表示させることができます。
この定型文には無印の #grandmaster_said とは別のスタイルを指定できます(何も指定しなければ上と同じスタイルになります)。
また
content: url('http://xxx.xxx/scoyan.png');などとして、文字ではなくアイコン的な画像を表示させることもできます。
以上のCSSコードを、最初に述べたようにフリーエリアにHTMLとして書き込むので、前後を<style></style>タグで括ってやります。
JavaScript
即時関数について
JavaScript を実行するには、HTML の<head>タグ内に<script src="http://xxx.xx/xxx/xxxx.js"></script>という<script>タグを書いて JS(女子小学生じゃないよ)ファイルを読み込ませ、<body>タグ内に
<script type="text/javascript">xxxx();</script>と書いて、ファイル内に定義した xxxx() という関数を呼び出します。
普通はこの呼び出し部分が無いと実行されないわけですが、ここでは読み込みだけで実行させることができる、即時関数という構文を使います。
function saki(){ (処理内容) }という関数を即時関数にするには、関数全体を () で括ってやり、さらに最後に (); をつけてやります。
(function saki(){ (処理内容) })();因みに、呼び出す必要がなくなった saki という関数名も、他に必要が無ければ
(function(){ (処理内容) })();と、無名化することができます。
この書き方をすれば、JSファイルの読み込みだけで実行されます。
もちろん function(){} で括らずに(処理内容)をそのまま書いても実行されますが、すると(処理内容)で定義した変数が DOM全体で有効なグローバル変数になってしまい、ほかに JSライブラリを読み込んでいる場合などに同じグローバル変数名が定義されていたらブラウザは両者を同じ変数として認識し、動作がおかしくなる可能性が高いのです。
今回はブログパーツ領域にコードを書いていくのでブログパーツ設定の読込→DOM生成 というサーバー側の動作は、厳密にいうと JSファイル読込には当らないのですが、実質的にはだいたい同じことです(アバウト)。
では、以下実際のコードの説明です。
最初が肝心
;(function(){1行目の頭の ; は誤記ではなく、誤動作防止のおまじないです。
大抵は書かなくても大丈夫ですが、万一に備えて。
ヘッダー領域の取得
2行目以下が上で言う(処理内容)に当ります。var $h = document.getElementById('blog-header'); if($h==null) return;$hという変数に、IDが"blog-header"であるHTMLオブジェクト(上で見たヘッダー領域)を格納します。
この値が null であれば、操作対象であるヘッダー領域が DOM上に存在しない、ということ(エラー)なので、何もせずにこのスクリプトを抜けます。
セリフ表示領域の生成
var $div = document.createElement('div');DOM上に div要素を生成し、$divという変数に格納します。
オブジェクト変数の頭に$をつけているのは、普通の変数(数値や文字列)と区別し易くするためです。推奨しないデベロッパーの方もいるくらいで、別にルールではありません。
$div.id = 'grandmaster_said';この div要素に"grandmaster_said"という ID を与えます。このプログラム内では $div という変数名がすでにあるので ID は不要ですが、CSSの方でこの ID を使ってスタイルを指定します。
$h.appendChild($div);生成した div要素を、ヘッダー要素の子要素として登録します。
なお、
$div.style.backgroundColor = 'rgba(255,255,255,0.2)';のように書いていけば、CSSを使わずに JavaScript の中でスタイルを指定することができます。
ただ、JavaScript ではなるべくスタイルを動的に変化させる記述にとどめ、変化しないスタイルについては CSS に定義しておいた方がいいでしょう。
名言データの定義
var msg = [配列の定義の仕方がいろいろある中で、一番簡単な書き方をしました。
'臨海女子は今まで15年連続で地区代表だってば!',
・
・
・
'そんなことないよ!?' ];
個々のセリフを引用符で括って、コンマで区切り、全体を大カッコで括るだけ。
いくらでも書き足せます。
ここは結構膨大で、本来ならテキストファイルなどを別に用意してそこから読み込むべきなのでしょうが、ブログサービスのエディタで手軽に追加編集などができるように、直接 JavaScript コードの中に書いてしまいます。
変数の定義/初期値
var speed = 50; var speed2 = 2000;speed は次の文字が、speed2 は次の行が表示されるまでの時間です(単位:㍉秒)。
これは変数というより定数で、使い所もそれぞれ一箇所なので本来そこに直接数字を書き込めばいいんですが、ここにまとめておくことでメンテがし易い意味があります。
var m = msg.length, i = Math.floor(m * Math.random()), v = 0;m は配列長つまり名言の数(定数)。
i は表示する名言の番号、v は表示する文字の数。
ここではその初期値をセットしています。
Math.random() という関数が 0以上1未満の小数値を返すので、それを m倍し小数点以下を切り捨てる(Math.floor)ことで、0~m-1 の整数のどれかが i にセットされます。
隠し味
$div.setAttribute('title',セリフの表示領域である要素の title属性に、m を表示する文字列をセットします。
'現在'+m+'件の名言が登録されています');
こうしておくと、パーツにマウスオーバーした時、この文字列が表示されます。
再帰関数の定義と実行
function Rndmsg(){ $div.innerHTML = msg[i].substring(0,v); if (v < msg[i].length){ v++; setTimeout(arguments.callee,speed); } else if (v==msg[i].length){ i = Math.floor(m * Math.random(v)), v = 0; setTimeout(arguments.callee,speed2); } }ここでこのプログラムの要所、再帰関数 Rndmsg() を定義しています。
v の値がセリフの文字列長より小さければ、vの値を1増やして v文字分を表示せよ、
v がセリフの文字列長に達したら次のセリフをランダムに選べ。
というアルゴリズムになっています。
普通、再帰関数の書き方としては
setTimeout('Rndmsg()',speed);と、自分自身の名前を呼び出すわけですが、本スクリプト全体は即時関数なので、呼び出した時点で定義が終わってないじょというエラーになってしまいます。
この場合、自分自身の名前ではなく arguments.callee というプロパティを呼び出してやると、再帰と同じ動作をしてくれるので、そのように書きます。
Rndmsg();ここでその Rndmsg()を実行しています。
})();最後に即時関数を閉じて、おしまい。
実装
本記事の CSSコードを<style>タグで、JavaScriptコードを<script>タグで括り、ブログパーツとして貼りつければ、実装できます。いちばん簡単なのは、
- 右クリックでこのページのソースを表示
- GRANDMASTER_SAIDなどで検索
- その部分をフリーエリアにコピペ
例えば FC2 だとヘッダー要素は<div id="header">になっているので、
CSS部分は
#header{ position: relative; }JavaScript部分は
var $h = document.getElementById('header');という感じです。
もちろんヘッダーにこだわる必要はなく、表示させたい場所の HLML要素の ID を指定すればそこに表示されます。
ソースをコピペしたフリーエリアの内部に
<div id="saki"></div>などと書いても吉です。
msg の中身を別のキャラのセリフにして、CSSのデザインをちょちょっと変えれば、オリジナルのブログパーツになりますよ。
文字を一文字づつ表示させる部分は、以前もお世話になった動くJavaScriptというサイト様の文字に関するページを参考にさせていただきました。
ここに記して御礼申し上げます。
コメント