ページ

2012年11月15日木曜日

Vim チートシート



・以下で公開している.vimrcの設定で利用可能なコマンドを纏めています。
github
https://github.com/isystk/dotfiles




【カーソル移動】
上下左右 → k、j、h、l
左右(区切り文字単位) → b、w
ファイルの先頭 → gg
ファイルの末尾 → G
行の先頭 → 0
文字の先頭 → ^
行の末尾 → $
1ページ前 → <C-B>
1ページ後 → <C-F>
半ページ前 → <C-U>
半ページ後 → <C-D>
カーソル行の指定文字位置に移動 → f(文字)
対応する括弧に移動 → %
表示画面の先頭行 → <S-H>
表示画面の最終行 → <S-L>
カーソル位置を画面中央に → zz



【編集】
カーソル位置から入力 → i
カーソルの次から入力 → a
カーソル位置を消して入力 → s
カーソル位置の1単語を消して入力 →cw
カーソル位置の1単語を削除する → dw
カーソル行を消して入力 →cc
次の行から入力 → o
直前の編集を繰り返す → .
カーソル位置の文字を置換する → r
カーソル以降の文字を置換する → R
カーソル位置の文字を小文字にする → ~
入力モードから抜ける → <C-C>
カーソル位置を1文字削除 → x
カーソル行を切り取る → dd
カーソル位置から後ろを削除 → <S-D>
アンドゥ → u
リドゥ → <C-R>
カーソル位置の数字をインクリメントする → <C-A>
カーソル位置の数字をデクリメントする → <C-X>
カーソル位置の数字に25加算する → 25<C-A>
行の先頭に連番をふる → %!nl -w1 -s.\
一括でコメントアウトする(tomtom/tcomment_vim) → 選択状態で <C-_>
3行目から6行目までをコピー → :3,6y
1行目から3行目を5行目に移動 → :1,3m3
2から3行目の左に10文字スペースを開ける → :2,3left 10
全行を120文字幅で中央寄せにする → :%center 120
選択部分を2タブインデントする → 選択状態で 2>
1行コピー → yy
カーソル位置にペースト → P
カーソル後ろにペースト → p
複数行を選択してコピーする → 範囲状態で y
複数行を選択して切り取る → d
最新のヤンクをペーストする → "0P
選択範囲をオートインデントする → 選択状態で =
ZenCodingを利用する(ZenCoding.vim) → <C-Y>
ヤンク履歴からペーストする → ペースト後に <C-P>
ヤンク履歴からペーストする(後方検索) → ペースト後に <C-N>
Javascriptのコメントを生成する(tanabe/WriteJSDocComment.vim) → <C-C>
5行目から10行目までをソートする → :5,10sort
ファイル全体を降順でソートする → :sort!
重複している行を取り除く → :sort u
データをカンマで区切って3番目の数値でソートする → :%!sort -t, -k 3,3n




【ファイル】
終了 → :q
保存せずに強制終了 → :q!
別名で保存して終了 → :w (ファイル名)
保存して終了 → ZZ
カーソル位置にある文字をファイル名として開く → gf
権限のないファイルを編集してしまった時に保存する → :w !sudo tee %



【検索・置換】
文字を検索する → /(検索文字)<CR>
文字を逆方向に検索する → ?(検索文字)<CR>
カーソル位置にある単語を検索 → *
次の検索結果 → n
前の検索結果 → <S-N>
JSファイル内をgrep検索する → :vimgrep /(検索文字)/ **/*.js
確認しながら文字を置換する → :%s/(変更前の文字)/(変更後の文字)/gc
選択範囲内で文字を置換する → :'<,'>s/(変更前の文字)/(変更後の文字)/g
カーソル位置にある単語を選択して、すべて置換する → # :%s//(変更後の文字)/gc



【領域選択】
領域を選択する → v
領域を矩形選択する → <C-V>
領域を行単位で選択する → <S-V>
カーソル位置の単語を選択する → viw
カーソル位置の括弧内を選択する → vi{



【タグ移動】
タグを生成する → vimshellを開いて ctags -R
カーソル位置の関数定義位置に移動する → <C-]>
直前のタグへ戻る → <C-T>



【ウィンドウ】
ファイラーを開く(Shougo/vimfiler) → :e .
画面を分割して交互に画面を移動する(Shougo/vimfiler) → <Tab>
カーソル上のファイルを編集する(Shougo/vimfiler) → e
カーソル上のファイルを、縦分割して編集する(Shougo/vimfiler) → v
ドットファイルを表示する(Shougo/vimfiler) → .
異なるウィンドウ間を移動する → <C-W>
ウィンドウを広げる → <C-W>+
ウィンドウを縮める → <C-W>-
ひとつ上のディレクトリを開く(Shougo/vimfiler) → h
ドライブの切替(Shougo/vimfiler) → <S-L>
ホームディレクトリを開く(Shougo/vimfiler) → ~
ルートディレクトリを開く(Shougo/vimfiler) → \
カーソル上のファイルに対して、様々なアクションを選択して実行(Shougo/vimfiler) → a
vimfiler上のカレントディレクトリを、システムのエクスプローラで開く(Shougo/vimfiler) → ge
カーソル上のファイルを、システムに関連付けされたアプリケーション(コマンド)で実行する(Shougo/vimfiler) → x
カーソル上のファイルにマークをつける、または、はずす(Shougo/vimfiler) → Space
マークしたファイルをコピー(Shougo/vimfiler) → c
マークしたファイルを移動(Shougo/vimfiler) → m
マークしたファイルを削除(Shougo/vimfiler) → d
マークしたファイルの名前を変更(Shougo/vimfiler) → r
新規ディレクトリを作成(Shougo/vimfiler) → K
新規ファイルを作成(Shougo/vimfiler) → N



【タブ】
新しいタブを作成する → :tabnew
次のタブを表示する → gt
最初のタブを表示する → :tabfirst
最後のタブを表示する → :tablast



【バッファ管理】
バッファに保存中のファイルを確認する → :ls
バッファから特定のファイルを呼び出す → :b(番号)<CR>
次のバッファのファイルを開く → :bn
前のバッファのファイルを開く → :bN



【レジスタ管理】
選択範囲をレジスタaに保存 → "ay
今いる行をレジスタaに保存 → "ayy
レジスタaの内容をカーソル位置にペースト → "ap
レジスタに格納されている情報の一覧 → :reg



【マーク】
現在位置のカーソルをマークaに保存 → ma
マークaの位置に移動 → 'a
マークの一覧を表示する → :marks



【折りたたみ】
選択領域を折りたたむ → zf
折りたたみを展開する → <Space>



【単語補完】
単語を保管する(Shougo/neocomplcache) → <Tab>
単語を保管する → <C-P>
単語を保管する(後方検索) → <C-N>



【操作記憶】
操作の記録を開始し、レジスタaに保存する → qa
操作の記録を終了する → q
レジスタaに保存された操作を再生する → @a
レジスタaに保存された操作を5回再生する → 5@a
前回再生した操作を連続再生する → @@



【外部コマンド連携】
vimshellを開く(Shougo/vimfiler) → ,is
コマンド入力位置を先頭に移動 → <C-A>
コマンド入力位置を末尾に移動 → <C-E>
コマンド入力位置を右に移動 → <C-F>
コマンド入力位置を左に移動 → <C-B>
外部コマンドを実行する → :!(コマンド)
外部コマンドを実行結果を取り込む → :r!(コマンド)
コマンドの履歴を確認する → q:
編集中のファイルをGistに投稿する(mattn/gist-vim) → :Gist
Scalaを起動する → ,iscala
SpiderMonkeyを起動する → ,ijs



【その他】
プラグインをインストールする → :BundleInstall
プラグインを再インストールする → :BundleInstall!





■ おすすめのVim関連サイト

・vimgolf
http://vimgolf.com/

・Vimコマンド ツイート BOT
@be_vimmer_jp





2012年10月15日月曜日

Underscore.js について纏めてみた


Underscore.jsは、便利なユーティリティ関数を詰め合わせたライブラリです。


大きく6つの機能に分類される



【コレクション】

each
~ listの要素をイテレートする。すべての要素はiterator関数にyieldされる。
  iteratorには(element, index, list)の3つの引数が渡される。
  もしlistがJavascript Objectだった場合は(value, key, list)になる。
_.each([1, 2, 3], function(num){ alert(num); });
=> alerts each number in turn...
_.each({one : 1, two : 2, three : 3}, function(num, key){ alert(num); });
=> alerts each number in turn...

map
~ listのすべての要素を操作関数(iterator)でマッピングし、新しい配列を作る。
  もしlistがJavascript Objectだった場合、iteratorへの引数は(value, key, list)になる。
_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]
_.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]

reduce
~ listの要素を1つの値に集約する。memoが初期値。
  iteratorはステップごとに値を返さなければいけない。
var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
=> 6

reduceRight
~ 右方向からのreduce。
var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
=> [4, 5, 2, 3, 0, 1]

find
~ リストの要素の中から、一番最初に真値テスト(iterator)を通過したものを返す。
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2

filter
~ リストの要素の中から、真値テスト(iterator)を通過したものを返す。
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

reject
~ リストの要素の中から、真値テスト(iterator)を通過しなかったものを返す。selectの反対。
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [1, 3, 5]

all
~ リストの要素がすべて真値テスト(iterator)を通過した場合、trueを返す。
  そうでない場合はfalseを返す。
  iteratorが与えられなかった場合、代わりに真理値が使用される。
_.all([true, 1, null, 'yes'], _.identity);
=> false

any
~ listの要素が1つでも真値テストを通過した場合、trueを返す。そうでない場合はfalseを返す。
_.any([null, 0, 'yes', false]);
=> true

include
~ valueがlistに含まれている場合、trueを返す。そうでない場合はfalseを返す。
  値の比較は===演算子で行われる。
_.include([1, 2, 3], 3);
=> true

invoke
~ listの各要素に対してmethodNameで指定した関数を実行する。
  *argumentsは、指定された関数に引き渡される。
_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
=> [[1, 5, 7], [1, 2, 3]]

pluck
~ mapの便利バージョン。指定したプロパティ名に対応する値を集める。
var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
_.pluck(stooges, 'name');
=> ["moe", "larry", "curly"]

max
~ listの中の最大値を求める。
  iteratorが渡された場合、iteratorの返り値がランク付けの基準として使用される。
var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
_.max(stooges, function(stooge){ return stooge.age; });
=> {name : 'curly', age : 60};

min
~ listの中の最小値を求める。
  iteratorが渡された場合、iteratorの返り値がランク付けの基準として使用される。
var numbers = [10, 5, 100, 2, 1000];
_.min(numbers);
=> 2

sortBy
~ 各要素をiteratorの返り値でランク付けし、それと元にソートされたlistを返す。
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]

groupBy
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
=> {1: [1.3], 2: [2.1, 2.4]}
_.groupBy(['one', 'two', 'three'], 'length');
=> {3: ["one", "two"], 5: ["three"]}

sortedIndex
~ 二分探索で、valueがlistの挿入されるべき位置を調べ、それを返す。
  iteratorが渡された場合、iteratorの返り値がランク付けの基準として使用される。
_.sortedIndex([10, 20, 30, 40, 50], 35);
=> 3

shuffle
_.shuffle([1, 2, 3, 4, 5, 6]);
=> [4, 1, 6, 3, 5, 2]

toArray
~ list(イテレートできるものならなんでも)をArrayに変換する。引数を変形するのに便利。
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
=> [2, 3, 4]

size
~ listに含まれている要素の数を返す。
_.size({one : 1, two : 2, three : 3});
=> 3



【配列】

first
~ 配列の一番目の要素を返す。nを指定しすると、先頭からn番目の要素までの配列を返す。
_.first([5, 4, 3, 2, 1]);
=> 5

initial
_.initial([5, 4, 3, 2, 1]);
=> [5, 4, 3, 2]

last
~ 配列の最後にある要素を返す。
_.last([5, 4, 3, 2, 1]);
=> 1

rest
~ 先頭の要素を取り除いた配列を返す。
  indexを指定すると、index番目以降の要素を配列として返す。
_.rest([5, 4, 3, 2, 1]);
=> [4, 3, 2, 1]

compact
~ 曖昧な値であるfalse, null, 0, "", undefinedを取り除いた配列を返す。非破壊的。
_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]

flatten
~ 多次元配列を一次元化する。非破壊的。
_.flatten([1, [2], [3, [[4]]]]);
=> [1, 2, 3, 4];
_.flatten([1, [2], [3, [[4]]]], true);
=> [1, 2, 3, [[4]]];

without
~ valuesを取り除いた配列を返す。===演算子で比較される。非破壊的。
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]

union
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

intersection
~ 複数の配列の共通集合を返す。
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]

difference
_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

uniq
~ 配列から重複を取り除く。===演算子で比較される。
  配列がソートされている場合は、isSrotedをtrueにすると処理が早くなる。非破壊的。
_.uniq([1, 2, 1, 3, 1, 4]);
=> [1, 2, 3, 4]

zip
~ 複数の配列の、同じ位置にある要素をマージする。
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

indexOf
~ 配列にvalueが含まれていた場合、valueが一番最初に現れた位置を返す。
  含まれていなかった場合は-1を返す。
  配列がソートされている場合は、isSrotedをtrueにすると処理が早くなる。
_.indexOf([1, 2, 3], 2);
=> 1

lastIndexOf
~ 配列にvalueが含まれていた場合、valueが一番最後に現れた位置を返す。
  含まれていなかった場合は-1を返す。
_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
=> 4

range
~ startからstopまでstepずつ増加(または減少)する整数のリストを作る。排他的。
  startのデフォルト値は0。stepのデフォルト値は1。
_.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0);=> []



【関数】

bind
~ オブジェクトを関数にバインドする。
  関数が呼ばれたとき、thisがobjectの値をとるということ。カリー化。
var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name : 'moe'}, 'hi');
func();
=> 'hi: moe'

bindAll
~ 複数の関数をオブジェクトにバインドする。
  イベントハンドラーに関数をバインドするときに便利。
var buttonView = {
    label   : 'underscore',
    onClick : function(){
        alert('clicked: ' + this.label);
    },
    onHover : function(){
        console.log('hovering: ' + this.label);
    }
};
_.bindAll(buttonView);
jQuery('#underscore_button').bind('click', buttonView.onClick);
=> When the button is clicked, this.label will have the correct value...

memoize
~ 関数の計算結果をキャッシュする。メモ化。
  hasFunctionが指定された場合、結果をストアするためのハッシュキーとして利用される。
  hasFunctionのデフォルト値は一番最初の引数。
var fibonacci = _.memoize(function(n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
});

delay
~ setTimeoutのように、ミリ秒後に関数を呼び出す。
  argumentsを指定した場合、それが呼び出される関数に引き渡される。
var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.

defer
~ コールスタックが空になるまで、関数の呼び出しを遅延させる。
  delay = 0でsetTimeoutを使う場合と同じ。
  複雑な計算を行ったり、UIスレッドをブロックせずにまとまったHTMLレンダリングを行いたいときに便利。
_.defer(function(){ alert('deferred'); });
// Returns from the function before the alert runs.

throttle
~ スロットル化された関数を返す。
  ラップされた関数はwaitミリ秒に多くても一度しか実行されない。
  レートが制限されたイベントを起こすのに便利。
var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);

debounce
~ 関数が実行されてからwaitミリ秒が経過するまで、繰り返しの呼び出しを抑止する。
  何らかの入力がストップしたときに実行される振る舞いを実装したいときに便利。
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

once
~ 一度しか実行されない関数を作成する。
  修正された関数の二度目以降の呼び出しは、なんの影響も与えず、最初に呼び出されたときの返り値を返す。
  初期化処理に便利。
var initialize = _.once(createApplication);initialize();
initialize();

after
var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
    note.asyncSave({success: renderNotes});
});

wrap
~ 最初の引数で指定した関数をwrapper関数の中にラップする。
  wrapper関数には指定された関数の実行の前後で行われる処理を記述することができる。
var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
    return "before, " + func("moe") + ", after";
});
hello();
=> 'before, hello: moe, after'

compose
~ 複数の関数の合成関数を返す。関数は次の関数の返り値を引数としてとる。
  関数f(), g(), h()を合成しすると関数f(g(h()))ができる。
var greet    = function(name){ return "hi: " + name; };
var exclaim  = function(statement){ return statement + "!"; };
var welcome = _.compose(exclaim, greet);
welcome('moe');
=> 'hi: moe!'



【オブジェクト】


keys
~ objectのプロパティ名をすべて取り出す。
_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]

values
~ objectのプロパティ値をすべて取り出す。
_.values({one : 1, two : 2, three : 3});
=> [1, 2, 3]

functions
~ objectが持つすべての関数プロパティ名をソートして返す。
_.functions(_);
=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...

extend
~ soucesオブジェクトのすべてのプロパティをdestinationオブジェクトにコピーする。
  sourcesの中に同じ名前のプロパティが含まれていた場合、より後のもので上書きされる。
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}

pick
_.pick({name : 'moe', age: 50, userid : 'moe1'}, 'name', 'age');
=> {name : 'moe', age : 50}

defaults
~ objectがdefaultsオブジェクトのプロパティを持っていない場合、objectにそのdefaultsオブジェクトのプロパティを付与する。
var iceCream = {flavor : "chocolate"};
_.defaults(iceCream, {flavor : "vanilla", sprinkles : "lots"});
=> {flavor : "chocolate", sprinkles : "lots"}

clone
~ objectのシャローコピーうを作る。ネストされたオブジェクトや配列は、参照コピーされる。
_.clone({name : 'moe'});
=> {name : 'moe'};

tap
_.chain([1,2,3,200])
    .filter(function(num) { return num % 2 == 0; })
    .tap(alert)
    .map(function(num) { return num * num })
    .value();
=> // [2, 200] (alerted)
=> [4, 40000]

has
_.has({a: 1, b: 2, c: 3}, "b");
=> true

isEqual
var moe   = {name : 'moe', luckyNumbers : [13, 27, 34]};
var clone = {name : 'moe', luckyNumbers : [13, 27, 34]};
moe == clone;
=> false

_.isEqual(moe, clone);
=> true

isEmpty
_.isEmpty([1, 2, 3]);
=> false
_.isEmpty({});
=> true

isElement
_.isElement(jQuery('body')[0]);
=> true

isArray
(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true

isObject
_.isObject({});
=> true
_.isObject(1);
=> false

isArguments
(function(){ return _.isArguments(arguments); })(1, 2, 3);
=> true
_.isArguments([1,2,3]);
=> false

isFunction
_.isFunction(alert);
=> true

isString
_.isString("moe");
=> true

isNumber
_.isNumber(8.4 * 5);
=> true

isFinite
_.isFinite(-101);
=> true
_.isFinite(-Infinity);
=> false

isBoolean
_.isBoolean(null);
=> false

isDate
_.isDate(new Date());
=> true

isRegExp
_.isRegExp(/moe/);
=> true

isNaN
_.isNaN(NaN);
=> true
isNaN(undefined);
=> true
_.isNaN(undefined);
=> false

isNull
_.isNull(null);
=> true
_.isNull(undefined);
=> false

isUndefined
_.isUndefined(window.missingVariable);
=> true



【ユーティリティ】


noConflict
var underscore = _.noConflict();

identity
var moe = {name : 'moe'};
moe === _.identity(moe);
=> true

times
_(3).times(function(){ genie.grantWish(); });

mixin
_.mixin({
    capitalize : function(string) {
        return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
    }
});
_("fabio").capitalize();
=> "Fabio"

uniqueId
_.uniqueId('contact_');
=> 'contact_104'

escape
_.escape('Curly, Larry & Moe');
=> "Curly, Larry & Moe"

result
var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }};
_.result(object, 'cheese');
=> "crumpets"
_.result(object, 'stuff');
=> "nonsense"

template
var compiled = _.template("hello: <%= name %>");
compiled({name : 'moe'});
=> "hello: moe"

var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <% }); %>";
_.template(list, {people : ['moe', 'curly', 'larry']});
=> "<li>moe</li><li>curly</li><li>larry</li>"

var template = _.template("<b><%- value %></b>");
template({value : '<script>'});
=> "<b><script></b>"

var compiled = _.template("<% print('Hello ' + epithet); %>");
compiled({epithet: "stooge"});
=> "Hello stooge."

_.templateSettings = {
    interpolate : /\{\{(.+?)\}\}/g
};
var template = _.template("Hello {{ name }}!");
template({name : "Mustache"});
=> "Hello Mustache!"

_.template("Using 'with': <%= data.answer %>", {answer: 'no'}, {variable: 'data'});
=> "Using 'with': no"

<script>
    JST.project = <%= _.template(jstText).source %>;
</script>
※注意:値をバインドする際に<%= を使いがちですが、サニタイズの必要がある場合は、<%- を利用してHTML文字をエスケープするようにしましょう。


【チェーン】

chain
var stooges = [{name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23}];
var youngest = _.chain(stooges)
    .sortBy(function(stooge){
        return stooge.age;
    })
    .map(function(stooge){
        return stooge.name + ' is ' + stooge.age;
    })
    .first()
    .value();
=> "moe is 21"

value
_([1, 2, 3]).value();
=> [1, 2, 3]

公式サイト
http://underscorejs.org/


2012年10月12日金曜日

JQueryMobile パフォーマンスチューニング TIPS


JQueryMobileの開発で役立ちそうなTIPを纏めました。


■ パフォーマンス関連のTIPS


何度も表示される利用性の高いページを、素早く表示させたい。

【対処方法】
Ajax遷移すると、始めにロードしたページと現在表示されているページの2つのDOMがHTML内に存在している。この属性を追加するとページ遷移してもDOMが消えずに残るようになる為、読み込み速度が早くなる。ただし、その分メモリーを消費する為、検討が必要です。

<div data-role="page" data-dom-cache="true">  


ページがスムーズにスクロールしない。

【対処方法】
マウスオーバーのアニメーションが原因でスクロールがスムーズに動かない事がある。カーソルが要素の上に乗った際のスタイルの実行を遅らせる事で対応できる。
$.mobile.buttonMarkup.hoverDelay = 5000;


デバイスの性能が足らず、ページ遷移アニメーションが遅くなる

【対処方法1】
もっとも早いフェードでも300msのオーバーヘッドが生まれる。パフォーマンスを重視するのであれば、いっそのことページ遷移アニメーションを無効にする。
 $.mobile.defaultPageTransition = 'none';

【対処方法2】
ページ遷移中に重たいJavascriptが処理中だとページ遷移アニメーションが遅くなる事がある。ページのJavascriptファイルを遅れて読み込ませる事で改善できる。

 <script type="javascript/lazy" src="hoge.js" />
$(document).on('pageshow', '#page-id', function() {
     var jsLazy = $('script[type="javascript/lazy"]');
     jsLazy.attr('type', 'text/javascript').remove().appendTo('head');
});


ページ遷移の際にアニメーションがチカチカと点滅して表示される。

【対処方法】
表示するページの高さは、ページ遷移アニメーションのパフォーマンスに大きく影響する為、検索結果一覧などの長くなりがちなコンテンツを非表示としておき、遅れて表示させる事で改善できる。
<div class="lazy" style="display:none;" >
・・・
</div>
$('[data-role="page"]').live('pageshow', function(){
     $('.lazy').show();
});
$('[data-role="page"]').live('pagebeforehide', function() {
     $('.lazy').hide();
});



タップした時の反応時間を短縮する

【対処方法】
tapイベントやclickイベントは、長押しやダブルクリックに対応するために、300msの遅延が発生する。vclickイベントを利用する事でこの待ち時間を無くすことが出来る。
$(document).delegate('a', 'vclick', function(e){
    e.preventDefault();
    var link = $(this);
    $.mobile.changePage(link.attr('href'), {
        transition: link.jqmData('transition')
    });
});
※ ただし、一部のAndroidデバイスで、event.preventDefault(); で Aタグのデフォルトイベントをキャンセルしても、Aタグのhrefが先に処理されてしまう事象が確認された。href属性は、javascript:void(0);として利用する事で回避する事が出来る。


その他のパフォーマンス関連

・リンク先のページを先に読み込む。data-prefetch要素を付けることで、画面表示にリンク先のDOMを事前に読み込んでおくことができる。
<a href="/hoge" data-prefetch>ページ2</a>

・戻るページのスクロール位置を復元させないようにすることで、画面再描画のパフォーマンスをあげる。
$.mobile.minScrollBack = 9999;

・実機だと、スワイプ画像などのアニメーションがスムーズに動かない場合がある。GPUアクセラレータを利用する事で改善出来る可能性がある。

-webkit-transform:translate3d(0,0,0)

・カスタムビルドで、すべてのフォームとウィジットを外す。必要最低限の機能だけを利用する事で余計なオーバーヘッドを減らすことが出来る。 http://jquerymobile.com/download-builder/

・画面を指定サイズ以上スクロールした場合は、ページ遷移アニメーションを行わない。
$.mobile.getMaxScrollForTransition = function () {
    return 480;
};


■ ハマったこと

・ 画面遷移後にhistory.back()して、再度画面遷移すると、遷移前の画面に自動で戻ってしまう現象がP01-Dなど一部のAndroid端末で発生する。以下の何れかの設定をすることが回避が出来る。

【対処方法1】
$.mobile.hashListeningEnabled = false;
→ 但し、Ajax遷移する場合に、history.backしても元の画面が表示されなくなる。Ajaxを利用しない場合や、戻るボタンを考慮する必要がない場合は、こちらで対応します。

【対処方法2】
$.mobile.pushStateEnabled = false;
→ 但し、Ajax遷移した場合に、http://xxxx/?q=xx#/xxxx/?type=1 のように、次画面のURLがハッシュの後ろに表示される。(リロードした場合は、画面ロード後にハッシュの後ろのURLがAjaxで読み込まれる。)


■ POSTでAjax遷移する場合の注意(検索条件が多いなどの理由でGETパラメータの文字数制限を回避する場合など)

・リロード時すると保持していたクエリーが消えてしまう。

【対処方法】:data-role="page" を指定したタグに、data-url属性を追加して、ページのURLを指定する。
<div data-role="page" data-url="${currentUrl}">

・iOS6だとAjaxのPOSTがキャッシュされてしまう。

【対処方法1】:レスポンスヘッダに「Cache-Control: no-cache」を指定する。
SetEnvIf Request_Method "POST" IS_POST
Header set Cache-Control "no-cache" env=IS_POS

【対処方法2】:POSTするデータに毎回違う値を付加する。
'time=' + new Date().getTime()


■ 知ってると便利なこと

$.mobile.firstPage
→ 画面遷移した際の始めのページのDOMを取得する。(Ajax遷移の場合に便利)

$.mobile.activePage
→ 今表示されているページのDOMを取得する。(Ajax遷移の場合に便利)

$.mobile.showPageLoadingMsg();
→ ページローダーを表示する

$.mobile.hidePageLoadingMsg();
→ ページローダーを非表示にする

$.mobile.path.parseUrl(URL);
→ URLをエンコードする

$.mobile.showPageLoadingMsg('a', 'ページのロードに失敗しました。', true);
→ メッセージを表示する




2012年5月12日土曜日

Meteorを使ってみた!!


■ Meteorとは
Node.jsを基盤としたフレームワーク

■ Meteorのすごいところ
・サーバー側のソースを修正しても、再起動が不要で反映される。
・クライアント側のソースを修正すると、自動でリロードされる。
・MongoDBを別途インストール不要。
meteor.com がホストしているクラウド環境を無料で利用できる
・独自のパッケージシステムをもっている。サーバーのソースは「server」フォルダ。クライアントのソースは「client」フォルダ。
・jquery、underscore、deps、logging、backbone などのライブラリがバンドルされており設定不要で利用できる。


■ Meteorのインストール
curl  install.meteor.com | sh

■ サンプルの作成と起動
# leaderboardというサンプルを作成
meteor create --example leaderboard
# 生成されたディレクトリに移動
cd leaderboard
# meteorコマンドを実行
meteor

http://localhost:3000 にアクセス

■ meteorで利用するmongoDBにログインする
meteor mongo

■ meteor.comのクラウド環境を利用する
meteor deploy firstapp
(初回のみ meteor deploy firstapp --password)


■ meteorコマンド一覧
meteorで使用できるコマンドは以下のとおり。
run    [デフォルト] プロジェクトをローカルの開発環境で動かします
create    新しいプロジェクトを作成します
update     Meteorを最新バージョンにアップデートします
add    プロジェクトにパッケージを追加します
remove    プロジェクトからパッケージを取り除きます
list    利用可能なパッケージをリスト表示します
bundle    プロジェクトをtarballに固めます
mongo    特定のサイトのMongoDBに接続します
deploy    Meteorにプロジェクトをデプロイします
logs    指定されたサイトのログを表示します
reset    プロジェクトの状態をリセットし、ローカルのデータベースを削除します

2012年2月17日金曜日

CentOS6に、jenkins・Nodejs・MongoDBの環境を構築する

■Jenkinsのインストール
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
sudo yum install jenkins

設定を変更
sudo vim /etc/sysconfig/jenkins
19 JENKINS_JAVA_CMD=""
29 JENKINS_USER="jenkins"
47 JENKINS_PORT="8080"
57 JENKINS_AJP_PORT="8009"

パーミッションを変更
sudo chown -R "jenkins":"jenkins" /var/log/jenkins

jenkinsユーザーがパスワードなしでsudo出来るように設定
sudo /usr/sbin/visudo
jenkins  ALL=(ALL) NOPASSWD:ALL

jankinsの起動にはJavaが必要なのでインストール
wget http://download.oracle.com/otn-pub/java/jdk/6u31-b04/jdk-6u31-linux-x64-rpm.bin
chmod 755 jdk-6u31-linux-x64-rpm.bin
sudo ./jdk-6u31-linux-x64-rpm.bin

起動
sudo /etc/init.d/jenkins start
sudo chkconfig jenkins on



■Node.jsのインストール
wget http://nodejs.org/dist/v0.6.10/node-v0.6.10.tar.gz
tar xvf ./node-v0.6.10.tar.gz
cd node-v0.6.10
sudo yum install gcc-c++
sudo yum install openssl-devel
./configure --prefix=/usr/local/node
make
make install



■mongoのインストール
sudo vi /etc/yum.repos.d/10gen-mongodb.repo
[10gen]
name=10gen Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64
gpgcheck=0
sudo yum install mongo-10gen mongo-10gen-server
sudo /etc/init.d/mongod start
自動起動に設定
sudo chkconfig --levels 235 mongod on