裏ワザサンプル集(書籍)に、JavaScriptを利用してステータスバー
にパラパラアニメーション形式でメッセージをながすトリック(サンプルソース http://home.impress.co.jp/books/urawaza/tipsbook2/027/index.htm )が掲載されていました。是非自分のページにもとり入れてみたいのですが、二つのメッセージが交互にながれるように変更したいです。いろいろ自分でやってみましたが(msgの部分をmsg1とmsg2に分けたり)、エラーになったり、片方だけのメッセージしかでな
かったり、結局自力では解決できせんでした。みなさんのお力をかしていただけないでしょうか。(本の発行者は読者の質問に答えていないそうです。)
自分は、サンプル集をお手本に数字やメッセージの部分を書き換えたりすることくらいしかできない程度のJavaScript初心者です。どこをどう変更したらいいのか細かいところまで教えてくださると助かります。
例えばこんな感じでは? スクリプトの部分だけ書き換えました。
<SCRIPT LANGUAGE="JavaScript">
<!--
var maxSpacing = 20;
var messages = new Array;
messages[0] = "Do you like TIPS & TRICKS ?";
messages[1] = "What do you want to do?";
var spacedMessages;
function init() {
var blanks = '';
var i,j,k;
for (i = 0; i < maxSpacing; ++i) blanks += ' ';
spacedMessages = new Array;
for (i = 0; i < messages.length; ++i) {
spacedMessages[i] = new Array;
for (j = 0; j < maxSpacing; ++j) {
spacedMessages[i][j] = '';
for (k = 0; k < messages[i].length; ++k) {
spacedMessages[i][j] += messages[i].charAt(k) + blanks.substring(0, j);
}
}
}
timerID=setTimeout('wiper()', 100);
}
var timerID;
var messageID = 0;
var currentSpacing = maxSpacing - 1;
function wiper() {
if (currentSpacing < 0) {
currentSpacing = maxSpacing - 1;
++messageID;
}
if (messageID >= messages.length) {
messageID = 0;
}
window.status = spacedMessages[messageID][currentSpacing];
clearTimeout(timerID);
--currentSpacing;
timerID = setTimeout("wiper()", 100);
}
//-->
</SCRIPT>
及ばないかもしれませんが、勉強のために私もやってみてました。^^
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=Shift_JIS">
<script type="text/javascript">
<!--
// 設定ここから
var vMsg = new Array( "Do you like TIPS & TRICKS ?"
, "cogito, ergo, sum ?"
, "改革なくして成長なし ?"
); // メッセージ
var vMove = 20; // 動作コマ数 (0以上)
var vWait = 20; // 待機コマ数 (0以上)
// 設定ここまで
var vNowM = 0;
var vNowF = vMove;
var vReg = new Array();
for (h = 0; h < vMsg.length; h++) {
vReg[h] = new Array();
vReg[h][0] = vMsg[h];
for (i = 1; i <= vMove; i++) {
for (j = 1, vSp = ''; j < i; j++) { vSp += ' '; }
for (j = 0, vReg[h][i] = ''; j < vMsg[h].length; j++) { vReg[h][i] += vMsg[h].charAt(j) + vSp; }
}
}
function wiper() {
if (vNowF > 0) { window.status = vReg[vNowM][vNowF]; }
if (--vNowF < -vWait) {
vNowF = vMove;
vNowM = (vNowM + 1 >= vMsg.length) ? 0 : vNowM + 1;
}
setTimeout('wiper()', 100);
}
//-->
</script>
</head>
<body onload="setTimeout('wiper()', 100)">
</body>
</html>
''
' '
' '
' '
というように、空白は20回のループで作られる。最初に定数にすべき(配列に格納)。メッセージのパラパラを作る時のループで動的に生成しているのは、無駄な処理。場合によっては致命的。
元ページでは、その辺の常識は考慮されているのだが。
何にせよ、IEなどでリンク先を見れないのではどうしようもない。
# エラソウにほざいてしまったから、書いてみた。
# win2k ie6 でしか見ていない。
// 視覚健常者の内、IE 5.5以上を使っている人だけが恩恵(嫌がらせ)を受ける。
// 他では一切何も起こらない。
/*@cc_on @if (5 < @_jscript_version && (@_win32 || @_win16))
// 8<-----------設定。
wiper.messages = new Array (
'abc def ghi jkl',
'あいうえお',
'Don\'t use client-side scripts on web pages.'
);
wiper.divider = ' ';
// で設定した、言わば、挿入用文字単位が0個から、
wiper.frames_length = 20;
// で設定される個数まで連結される。例えば、「'-=-'が5個まで連結される」とは、
// ''
// '-=-'
// '-=--=-'
// '-=--=--=-'
// '-=--=--=--=-'
// という5種類の挿入用文字が作られるということ。
// 更に、例えば、'hoge'というメッセージがあった時、
// 'hoge'
// 'h-=-o-=-g-=-e'
// 'h-=--=-o-=--=-g-=--=-e'
// 'h-=--=--=-o-=--=--=-g-=--=--=-e'
// 'h-=--=--=--=-o-=--=--=--=-g-=--=--=--=-e'
// の5種類が出来上がる。これを紙に書いてパラパラアニメを作るのと仕組みは同じ。
wiper.stay_length = 20;
// で設定された正整数と次のwiper.cycleの積が、大まかに待機時間[ミリ秒]を設定する。
wiper.cycle = 100;
// で設定されたミリ秒毎に、パラパラとめくられる。
// 8<----------- 設定終わり。
wiper.stay_length = -wiper.stay_length;
wiper.frameNumber = wiper.frames_length;
wiper.messages_length = wiper.messages.length;
wiper.messageNumber = 0;
wiper.build = function($frames_length) {
var
frames = new Array($frames_length),
paddings = new Array($frames_length),
i, j;
buildDividers($frames_length - 1, wiper.divider.length);
buildMessages(wiper.messages_length, /.{0}/g);
delete String.prototype.x;
delete wiper.divider;
delete wiper.build;
function buildDividers($frames_lastIndex, $divider_length) {
frames[$frames_lastIndex] = wiper.divider. x ($frames_lastIndex);
buildPaddings($frames_lastIndex);
i = $frames_lastIndex;
while (i--) {
frames[i] = frames[$frames_lastIndex].slice(0, i * $divider_length);
buildPaddings(i);
}
function buildPaddings($i) {
paddings[$i] = new Object;
paddings[$i].left = $i * $divider_length;
paddings[$i].right = -paddings[$i].left;
}
}
function buildMessages($messages_length, $zeroCharacters) {
while (++i < $messages_length) {
wiper.messages[i] = new String(wiper.messages[i]);
j = $frames_length;
while (1 < j--)
wiper.messages[i][j] = wiper.messages[i]
.replace($zeroCharacters, frames[j])
.slice(paddings[j].left, paddings[j].right);
wiper.messages[i][0] = wiper.messages[i];
}
}
}
wiper.pause = function() {
clearTimeout(wiper.timeout);
}
wiper.start = function() {
wiper.timeout = setTimeout(wiper, wiper.cycle);
}
wiper.run = function() {
wiper.frameNumber--;
status = wiper.messages[wiper.messageNumber][wiper.frameNumber];
wiper.start();
}
wiper.stay = function() {
wiper.frameNumber--;
clearTimeout(wiper.timeout);
wiper.start();
}
wiper.next = function() {
wiper.messageNumber++;
if (wiper.messageNumber == wiper.messages_length)
wiper.messageNumber = 0;
wiper.frameNumber = wiper.frames_length;
wiper.start();
}
function wiper() {
0 < wiper.frameNumber ? wiper.run()
: wiper.stay_length < wiper.frameNumber ? wiper.stay()
: wiper.next();
}
// リンク先のuri表示を阻害しない。
// 但し、複合的なイベント (focus --> mouseover --> mouseout 等) には対応していない。
// 必要ならば、適当に。
// また、リンクから別ページに遷移して、バックしてきた、という場合に、
// リンクがfocusされているから、当然、ステータスバーに動く文字は表示されない。
// これまでも阻害してしまうことはナンセンス。
attachEvent(
'onload',
function() {
var
links = document.links,
i = links.length;
while (i--) {
links[i].attachEvent('onblur', wiper.start);
links[i].attachEvent('onfocus', wiper.pause);
links[i].attachEvent('onmouseout', wiper.start);
links[i].attachEvent('onmouseover', wiper.pause);
}
}
);
// ページ読み込み完了までは、ステータスバーに表示される文字を変更しない。
attachEvent('onload', wiper.start);
String.prototype.x = function($repetition) {
var
string = new Array($repetition);
while ($repetition--)
string[$repetition] = this;
return string.join('');
}
wiper.build(wiper.frames_length);
@end @*/
ma-toさん、おはようございます。
一通り読みましたが、いろいろ勉強できそうで、得した気分です。(^^
JavaSctiptはここまでオブジェクト指向貫くものなんですね。
イベント処理の仕方にも得るものがありました。
もしよろしければ、一つ教えて下さい。
function buildDividers の1行目、
frames[$frames_lastIndex] = wiper.divider. x ($frames_lastIndex);
の「divider. x 」あたりはどう解釈したらよいのでしょうか。
> ここまでオブジェクト指向貫くものなんですね。
何のことかよく分かりませんが、ともかく。
貫いていません。グローバル変数を0個(事実上1個)にして、コピペしやすくしただけです。
> どう解釈したらよいのでしょうか。
一回しか使わないにも関わらず、関数内部の行数を短くするためだけに、Perlのxオペレーター(の一部の機能)を猿真似しました。最後の方に書いてあります。
// string_prototype_x.js ---->8
String.prototype.x = function($repetition) {
for (var i = 0, string = new Array($repetition); i < $repetition; i++)
string[i] = this;
return string.join('');
}
// ---->8
# Windows, PerlをJavaScript 1.5で猿真似した。
C:\> perl -e "print 'm' x 10;"
mmmmmmmmmm
C:\> jsshell
js> load('string_prototype_x.js');
js> print('m'.x(10));
mmmmmmmmmm
ありがとうございます。x のこと解りました。
先ほど試してみるまで、識別子を結ぶ "." の前後にスペースを入れてもよいことを知りませんでした。
x の前後にスペースを入れてあるのは、あえて演算子に見立てている訳ですね。
prototype についても、一つ新しいことを教えて頂きました。
> 最初に定数にすべき(配列に格納)。
という 2003/04/30 00:31 の指摘も、これですっきり納得です。
> グローバル変数を0個(事実上1個)にして、コピペしやすくしただけです。
ごめんなさい。グローバル変数をなくすとコピペしやすい、というのがぴんと来ません。
# 「8<--」とか「-->8」とか何のことだろうと思っていましたが、もしかしてハサミだったんですか?
# また、常識を知らないといわれるのかな…(^^;
hrmさん、dailangさん、ma-toさん、みなさんご丁寧に教えてくださってありがとうございました。自分が初めに想像していたものよりもはるかに複雑そうでしたが、長いスクリプトの記述の上に詳しい説明までしてくださってうれしいです。
ma-toさんとdailangさんのスクリプトをさっそく自分のページで試してみたところ、確かに三つのメッセージがパラパラアニメーションで表示されました!こちらの手違いかもしれませんが、なぜかhrmさんのはエラーになってしまいました。
「完了」押し忘れました。