jQuery plugin - 高さ固定のAccordion

前回のシンプルなアコーディオンには不満な点が一つある。
それは同じ高さのコンテンツ要素の場合、表示/非表示の切り替え時に高さがガタガタすること。

この表現で伝わっているかちょっと疑問だが、とにかくガタガタしないものが欲しいのだよ!

ということで、今回は前回のものを流用して高さ固定のアコーディオンを作ってしまいましたとさ。

考え方:

  • ラッパー要素(親要素)の高さを固定する。
  • コンテンツ要素の高さを揃える。
  • 各トグル要素の初期位置(top)を記憶しておく。
  • クリックされたトグル要素とそれより前にある要素の position は「static」に、後にある要素は「absolute」にして記憶していたtopの位置を指定する。
という動作を行うようにする。

基本的にはこれだけ(のはず)。
それ以外外にはabsoluteにする要素のwidth指定は忘れずに。

要素の高さを揃える方法は「jQueryで要素の高さを揃える」を参照して下さい。

今回も前回と同様、どの要素をstatic/absoluteにするか、一々処理していたのでは重いので(たかが知れてるが)、トグル要素ごとに記憶させて関数をdataに保存しています。

Usage

jQuery(function($){
 $.myAccordion({
  wrap:'#itunes-navi',
  tgl:'.itunes-category-tgl',
  cont:'.itunes-genre-list'
 });
});




ファイルサイズは2.17KBとかなり小さい。

当り前のことだが、必要な機能だけあれば良いワケで、作るのが困難なものでなければ、自分で作った方がいろんな意味で有意義だね。

jQuery plugin - シンプルなアコーディオンをさらに工夫してみる

jQueryのpluginとして有名なものの一つに「Accordion」があるが、色々な動作を可能とするために、ファイルサイズが大きくなり過ぎている。

実際にはあれ程のものは必要ない。

ということで、もっとシンプルなものを作ってみる。

シンプルなアコーディオン

最もシンプルなアコーディオンはトグルとなる要素と表示するコンテンツが同じ数だけあることを前提にすれば容易に実装できる。

クリックされたトグル要素のインデックスを取得して同じインデックスのコンテンツを表示し、それ以外のコンテンツは非表示にすれば良い。

ただそれだけなら誰でも思いつくので、その他に3つの機能を追加した。

追加した機能:
1. 表示/非表示の切り替え途中(animate動作中)の再切り替え操作を無効にする
これは表示要素を切り替えている途中にまた切り替え操作を行われると、表示される要素が二つになってしまう可能性があるため。

具体的にはこのようにしている。
if(!$conts.is(':animated')){
  // ...
}
2. クリックされたトグル要素に"current"class属性を追加する
これは見た目の問題になるのですが、表示されているコンテンツと対になるトグル要素は見た目に変化がある方がユーザビリティが良くなると思われ、CSSにて、何らかの変化を加えられるようにするためです。
3. トグル要素のクリック時に呼ばれる関数をdataに保存する
トグル要素のクリック時に毎回特定の要素を取得するなどの処理を走らせるよりも、覚えさせておいてクリックされたら、そのトグル要素固有の関数を走らせた方が処理は軽くなるはず、という考えです。

後は以下のようにして呼び出すだけなのでラク。
$(tgl).click( function(e) {
                $.data(e.target, key).call(e.target);
                return false;
}

Usage

$.simpleAccordion({
  tgl:'.ac-tgl',
  cont:'.ac-cont'
});



jQueryでulリストを簡単に生成する関数を書いてみた

別にulじゃなくてolでもいいんですが、「もっと簡単にリストを生成したい」とか思ってしまったんで、書いてみた。

まず最初に書いたのがこれ。

Code

$.toList1 = function(arr, callback){
  return '<ul><li>' + $.map(arr, function(x, i){
      return callback.call(this, x, i);
    }).join('</li><li>') + '</li></ul>';
}
実際のリストの内容は引数として渡されるcallback Functionで行う構造なので結構応用が利くはず。

内部処理は変数の宣言を必要としない「いかにもjQuery的」な感じなのだが、やっぱりjQueryに頼りすぎると処理速度が不安になる。

ということで、もう一つ、mapを使わないのも書いてみた。
$.toList2 = function(arr, callback){
  var lst = [];
  for (var i = 0, k = arr.length; i < k; i++)
    lst.push(callback.call(this, arr[i], i));

  return '<ul><li>' + lst.join('</li><li>') + '</li></ul>';
}


Usage

ブログのフィードを取得してリストにして表示する。
$.gFeed({
  'q': 'http://googleblog.blogspot.com/feeds/posts/default'
  }, function(feed){
      $(document.body).append($.toList(feed.entries, function(entry, i){
        return '<a href=\'' + entry.link + '\'>' + entry.title + '</a> ';
      }));
});



処理時間を計測し、比較してみる

書いたら実際に処理にかかる時間を比較しなければ、ということで上記のブログのフィードを取得してリストにして表示する処理を10000 x 100回行い処理速度を比較してみた。
console.time("test");
for (var i = 0, k = 10000; i < k; i++){
  // something...
}
console.timeEnd("test");

10000 x 100 avg.:Result


相対的な比較ということを念のため。

約1.5倍ですか、結構差があるものですね。

with文を使わず、冗長なコードにならないために

例えば以下のように、複数のスタイルを適用する場合『with』を使わないと冗長になってしまう。

var div = document.createElement('div');

div.style.backgroundColor = '#eee';
div.style.border = '1px solid #ccc';
div.style.color = '#1a1a1a';

これではちょっとイケてないので、こんな関数を用意する。

Code

function setStyle (elm, styles){
  for(var s in styles){
    if(styles.hasOwnProperty(s))
      elm.style[s] = styles[s];
  }
}

Usage

var div = document.createElement('div');
div.appendChild(document.createTextNode('foo'));

setStyle(div,{
  backgroundColor:'#eee',
  border:'1px solid #ccc',
  color:'#1a1a1a'
});

document.body.appendChild(div);
少しはマシになったかと。

もっと汎用性があった方がイイならこんなモンでどうでしょう。
function substituteForWith(o, v){
  for(var s in v){
    if(v.hasOwnProperty(s))
      o[s] = v[s];
  }
}

でも、こうした方がもっとシンプルか?
var
div = document.createElement('div'),
ds = div.style;

ds['backgroundColor'] = '#eee';
ds['border'] = '1px solid #ccc';
ds['color'] = '#1a1a1a';

div.appendChild(document.createTextNode('foo'));
document.body.appendChild(div);
つまり、まず変数に格納することにより、冗長にならないようにする。

この程度のことは好みの問題か?とも思うのだが、jQueryのplugin内部での処理を書いていて、そのpluginの処理速度に問題があるようではそのpuluginを使う気になれないので、速度を気にするならこういった処理が必要になってくる。

もし処理速度を気にしないのならjQueryの場合、以下のように書けば良い。
$(document.createElement('div')).css({
  backgroundColor:'#eee',
  border:'1px solid #ccc',
  color:'#1a1a1a'
}).appendTo(document.body);
簡単だけど上の処理に比べれば処理速度に時間が掛る。

jQuery plugin - Overlay

lightboxをはじめ、ウィンドウ内をレイヤー要素で覆うエフェクトがメジャーになりましたが、jQueryのプラグインで汎用性のあるモノではメジャーなところで『blockUI』というものがありますが、実際のところ、私にとってはボリュームがありすぎる。

例えば「ダイアログを表示するだけ」といった程度のことにこれだけのモノは必要ない。

あまり汎用性を求めれば、比例してコード量が増えたり、処理速度に影響したりするワケで、落としドコロが難しいのですが、私的にはもっと砕いて小さな部品が欲しいわけですよ。
つまり、「ページを覆うモノ」ただそれだけのモノが一つの部品(plugin)として存在した方が、より拡張性や汎用性があると思うワケです。

ということで、もっと軽くて使いやすい「ページを覆うモノ」が欲しくなったので自分で作ってみました。

ソースはこちら。


ファイルサイズは blockUI の約1/5の2.98KBです。
ちなみにblockUIは全く参考にしていないので中身も当然全くの別モノです。

動作確認はこちらで。

引数(options)

  • css: Layer要素のStyle
  • animateParams: animateで使用するParam
  • animateOptions: animateで使用するOption

jQueryで要素の高さを揃える

要素の高さを揃えるのに、何やら面倒なことをしているのを目にしたこともあり、jQueryで簡単に要素の高さを揃えてみる。

Code

$.fn.sameHeight = function(){
  var h = 0;
  return this.each(function(){
    h = Math.max(h, $(this).outerHeight());
  }).height(h);
}

ポイントは『outerHeight』を使っていること。

後はメソッドチェーンで最後に高さの最大値を適用しているところがjQueryらしい。

Usage

$('.foo').sameHeight();

これで高さが揃わなければ、この方法を疑うより、対象要素の構造やスタイルを見直した方がイイかも。

objectをマージする - javascript

objectの連想配列をマージしたいとき、jQueryを使っていれば extend があるが、そうでないときのために、マージする関数を書いておく。

Code

function merge(){

  var
  args = Array.prototype.slice.call(arguments),
  len = args.length,
  ret = {},
  itm;
  
  for( var i = 0; i < len ; i++ ){
    var arg = args[i];
    for (itm in arg) {
      if (arg.hasOwnProperty(itm))
        ret[itm] = arg[itm];
    }
  }
  
  return ret;

}

私的にはこれで十分。

Usage

var
foo = {
  a:1,
  b:2
},
hoge = {
  a:'a',
  c:3
},
 fuga = {
  a:'A',
  c:'c'
}

var re = merge(foo, hoge, fuga);

for(var i in re)
  console.log(i +'='+ re[i]);

Results:
a=A
b=2
c=c

iTunes + YouTubeで「iTube」

iTunesのToday's Ranking Feedを取得して、曲名やアーチスト名をキーワードにYouTubeの動画を検索して閲覧できる「iTube」を作ってみました。

iTunesのFeedはGoogle Ajax Feed APIを使えば簡単に取得できる。
自分でごにょごにょしたいなら、こんなものも作ってみたので気が向いたらどぞ。



YouTubeのAPIも使っていますが難しいことは何もしておらず、keywordを投げて動画を検索して、返ってきたものを表示する、それだけです。
参考程度にjQueryで簡単な関数にして使用したものを貼っときます。


実際に動画を見るために使用しているのが、AJAX Libraries APIからホスティングされている、SWFObjectです。
これを使用しなくても動画を見ることは可能なのかもしれませんが、私の場合、Firefox3では問題ないのですが、IEだと動画を再生できないことに悩んでいたので、これを使用して解決しました。


一々"HQ"ボタンを押すのが面倒なので、最初からHigh Quality Mode("HQ"ボタンを押した状態)にならないかといろいろ触ってみたのですが、結局分かりませんでした。
よくある「fmt=18」などはダメでしたが、"HQ"ではなく、"HD"なら「hd=1」でいけました。
"HD"が「hd=1」なら"HQ"は「hq=1」でイケんじゃね~、とか思って試したがこれももちろんダメ。 ...orz


これを作ってる最中に Lady GaGa の曲を聞いてるうちにだんだん好きになったり、 Taylor Swift や Jonas Brothers なんかを知ったりなど、いろいろ発見があった。まあ、それが目的で作ったんだけどね。



参考:

Javascript Regular Expressions Pattern Check をリニューアル

Google Page Creatorからの移動も兼ねて、Javascript Regular Expressions Pattern Checkをリニューアルしました。

GAEのサイトから公開しています。

その他にも color and font style testerString Replace もリニューアルしています。

とりあえず、スタティックなファイルとしてアップロードしているだけですが、これから徐々にGAEを触りながら機能を増やしていけたらと考えています。


公開しているページ(ツール)の説明

Javascript Regular Expressions Pattern Check
JavaScriptの正規表現パターンのチェックを行うツールです。 正規表現に関する簡単な説明と正規表現のパターンを入力して実際に動作を試すことが出来ます。 基本的なパターンの他、郵便番号や携帯電話などの実際に使用可能な正規表現パターンも掲載しています。
確認可能な動作:
  • match
  • replace
  • test
  • search
  • exec
color and font style tester
HTMLのフォントカラーやフォントスタイルをテストするツールです。 実際にHTML上でどのように見えるのか、色やフォントの種類、スタイルなどを簡単に切り替えて確認することが出来たら便利だと思い作ってみました。切り替えられるものは、color、background-color、font-family、font-style、font-weight、font-size、そして実際に表示する文字を書き換えることができます。
String Replace
例えばブログにコードなどの特殊文字が含まれたテキストを投稿するとき、それらの文字を変換する必要がある場合がありますが、一々そんなことを自力で行うのは面倒なので、このツールで特殊文字を一発で変換します。
その他にも、prettify や Syntax Highlighter を使用している場合、タグで囲んだり class 属性や name 属性を書き込む必要がありますが、それもこのツールによって簡単に行うことができます。

Google ReaderのAPIを使ってFeedを取得する

ワザワザこんなことをしなくてもGoogle Feed APIを使えばいいのだが、こんなことも出来るよ、程度の話で。

基本的なURLは以下の通り

http://www.google.com/reader/public/javascript/feed/[url]

これをjQueryのメソッドにしてみる。

Code

(function($){
$.gReaderFeed = function(url, options, fn){
  var opt = $.extend({
    n:10
  }, options);
  
  $.getJSON('http://www.google.com/reader/public/javascript/feed/' + url + '?callback=?', opt, fn);
}
})(jQuery);

Usage

気まぐれでjQueryを使わずに書いてみた。
$.gReaderFeed('http://googleblog.blogspot.com/feeds/posts/default',
  {'alt':'json'}, 
  function ( data ){    
    var list = document.createElement('ul');
    
    for (i in data.items) {
      var item = data.items[i];
      var post = document.createElement('li');
      
      var link = document.createElement('a');
      link.appendChild(document.createTextNode(item.title));
      link.href = item.alternate.href;
      post.appendChild(link);
      
      var timestamp = document.createElement('span');
      timestamp.appendChild(document.createTextNode(' - ' + 
        (function( date ){
          return date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日';
        })(new Date(item.published * 1000))));
      post.appendChild(timestamp);
      
      list.appendChild(post);
    }
    
    document.body.appendChild(list);
});
どんな引数があるか調べてみないと分からないが、多分資料は出てこないだろう。

Recent Posts