ラベル JavaScript の投稿を表示しています。 すべての投稿を表示
ラベル JavaScript の投稿を表示しています。 すべての投稿を表示
2012年10月23日火曜日

Backboneを学ぶ #0 環境構築

転職して新しい職場ではBackboneを使いそうなのに、今までこれで何も作ったことが無いので勉強することにしました。
ひと通り出来るようになるまで続けたいので連載にしてみます。まずは開発環境の構築など

  • サーバサイド
    • Sinatra (マイクロフレームワーク)
    • haml (テンプレートエンジン)
    • scss (cssメタ言語)
    • CoffeeScript (javascriptメタ言語)
    • Shotgun (開発用rackサーバ)
  • クライアントサイド
    • jquery.1.8.2.js
    • underscore.js
    • backbone.js
  • リポジトリ
  • サーバ
2012年7月19日木曜日

IE9でiframe内で遷移した場合window.parentのメソッドを呼べない

状況としては、ビデオ一覧ページから各ビデオをiframeを使ったレイヤーで立ち上げるページにて
ビデオはMediaElement.jsというのを使っていて、HTML5対応の判別して、ダメならFlashとかSilverlightとかに切り替えてくれるようになってます。(何も再生手段がなければmp4をDLさせます)

閉じるボタンを押してもビデオが再生されたまま

iframeが非表示になっただけでページ内に生きているから

レイヤーを表示させてるjsを調べる
なんだこれ誰かの自作じゃねえか!closeイベントとか取れねえよ!

親ウィンドウから子iframeにアクセスするか、
子iframeから親ウィンドウに渡すか

後者を選択して window.parent.videos.push(video)
親のレイヤーを非表示にするときの処理に

if (window.videos) {
  for (var i in window.videos) {
    if (!window.videos[i].paused) {
      window.videos[i].pause();
    }
  }
}

というのを挟むようにした。
IE、他ブラウザほぼ動く。

IE9だけ動かない!
iframe内で次の動画へ遷移できるようにしてあったんだけど
ビデオのhtmlは一本につき1ファイルなのでこれは単純にリンクを押してるだけ
親から直接ではなくiframe内で遷移後にエラーする。
(でもIEのステータスバーにはエラー表示が出ないんだけどね)

IE9のF12開発者ツールでブレークポイントつけてみる
「解放されたスクリプトからコードを実行できません」
ハァ(゚д゚)?

ググってみた。あぁそういえばIEではJavaScriptじゃなくてJScriptだったな……
つまり信頼性の低いスクリプトから親ウィンドウにあるオブジェクトのメソッドを実行できないってことですかね!!
というわけでpushじゃなくて代入にした。
window.parent.videos[window.parent.videos.length] = video;

動いた!
プロパティの参照と代入は問題ないみたいです。

2012年6月20日水曜日

jQuery.fn.loadのcallbackで受け取るjQuery.Event.targetはIEでDOM要素をとれない時がある

タイトルで大体言いきりました。

写真のスライドショーを作成していて、画像タグはJavaScript側で作成してDOMに追加するようにしていました。 何故こうしたかというと、環境によって画像の読み込みが終わらないうちにスライドショーの自動再生が始まってしまうのを防ぐためです。

具体的には以下のようなコードで画像の読み込み完了を待ってDOMに追加しています。

$('').attr(src: '/images/hoge.jpg?' + new Date().getTime()).load (e) =>
  $img = $ e.target
  $('#container').append $img

'?' + new Date().getTime() の部分ですが、コレをしておかないとIEがonloadイベントをサボるんですよね。。
必ずイベントを発火させるようにしています。

でIMG要素を $ e.target でjQuery化してappendという流れですが、実はこれだとIEでIMG要素がとれていないんです!
気づかずにそのまま処理を進めると画面真っ白になってお馴染みのわかりづらいエラーメッセージにかなり困惑しました。

IE8で以下の様に検証してみました。

A) e.targetでIMG要素が取得できない

$('').attr(src: '/images/hoge.jpg?' + new Date().getTime()).load (e) =>
  console.log e.target.nodeName # => #document

B) e.targetでIMG要素がとれる

$img = $ 'img.sample'
$img.attr(src: $img.attr('src') + '?' + new Date().getTime()).load (e) =>
  console.log e.target.nodeName # => IMG

違いはJSで要素を作成するか、htmlに記述されている要素を取得するかですね。

まぁぶっちゃけ loadのcallback内でthisが対象のIMG要素なのでコレ使えばいいんですよ。
でもCoffeeScriptつかってclass化したオブジェクトの中だと @(this) は常にクラスそのものとして使いたいので、 関数のthisにバインドしてくれる => を使いたいんですよね。

というわけで jQuery.Event オブジェクトの出番なわけです。
Aの方法だとIEで期待通りでないことがわかったので調べたところ、jQuery.Event.currentTarget というのがありました。
console.log e.currentTarget.nodeName でちゃんとIMGが返ってきたよ〜!

今後調べたいこと

  • $('<img />') と書いた時にブラウザ別に何が行われているのか
  • jQuery.Eventのコンストラクタを読む

追記:

  • jQuery APIの.load()を見たらDeprecatedのタグが付いてたのでbindでも試してみたけど、結果は一緒
2012年6月1日金曜日

CoffeeScriptでJavaScriptもクラス化しよう。テストを書きやすくメンテしやすく

CoffeeScriptを知ったのはRailsに組み込まれたからですが、Rails3.1で採用されてすぐに飛びついたわけではなく、しばらく敬遠してた時期もありました。しかし使い始めてからはもう手放せなくなりました。
そして次第にCoffeeScriptのclass構文を使えばよりよいJavaScriptの開発ができるのではないかと思うようになりました。
今回は最近CoffeeScriptを使ってどのように開発しているかを紹介したいと思います。

CoffeeScriptでのclass定義はこうやります

class Person
  constructor: (@my_name) ->

  greeting: ->
    alert "Hello! my name is #{@my_name}."

window.Person = window.Person || Person

コンパイルすると以下のようなJavaScriptになります

(function() {
  var Person;

  Person = (function() {

    Person.name = 'Person';

    function Person(my_name) {
      this.myname = my_name;
    }

    Person.prototype.greeting = function() {
      return alert("Hello! my name is " + this.my_name);
    };

    return Person;

  })();

  window.Person = window.Person || Person;
}).call(this);

※nameプロパティを使うと上書きしてしまうのでmynameとしました

例えばこのようなコードを person というファイル名で保存し、インスタンス生成は main という別ファイルで実行します。

main.coffee
$ ->
  kozo = new window.Person 'kozo'
  kozo.greeting()
main.js
(function() {
  $(function() {
    var kozo;
    kozo = new window.Person('kozo');
    return kozo.greeting();
  });
}).call(this);

こうすることでまず管理がしやすくなりますし、テストも気持ちよく書けると思います。

テストフレームワークはよく jasmine をつかっています。その前は QUnit だったんですが jasmine の方がドキュメントが探しやすいのとツールが整っている印象ですし、なによりコードが書きやすく後からでも見やすいですね。人によるかも知れませんが。
僕の場合CoffeeScript を使うときはほぼ Rails か sinatra 上ですので jasmine-headless-webkit というgemをつかってます。これを使うとCUIで実行結果が得られます。(jasmine-railsはこれに依存しています)

jasmineの諸々の設定は省略しますがテストコードはこんな感じにしています。

person_spec.coffee
describe "Person", ->

  beforeEach ->
    @person = new window.Person 'sample'

  afterEach ->
    delete @person

  describe "propaties", ->
    it "have 'my_name' string", ->
      expect(typeof @person.my_name).toBe "string"

  describe "greeting method", ->
    beforeEach ->
      spyOn window, "alert"
      @person.greeting()

    it "alert greeting text", ->
      expect(window.alert).toHaveBeenCalledWith "Hello! my name is sample."

DOMが絡むテストは jasmine-fixture というのをhelperとして読み込んで使っています。jqueryに依存しているのですが、むしろ使わない事のほうが少ないので気にしないです。affix という便利メソッドが使えるようになって、jqueryオブジェクトのprototypeにも追加されるので気に入ってます。

以上のような形で開発を進めてるのですが、クラスファイルと実行ファイルを分けてなるべくDOMの情報とかは実行ファイルに書き込むようにするといいと思います。
サイトのトップページにスライドショー的なものを設置するなら例えば以下の様な感じです。

main.coffee
$ ->
  slideshow = new window.Slideshow {
    container_id: '#hoge-slideshow'
    controller_id: '#hoge-controller'
    duration: 800
    wait: 3000
  }
  slideshow.start()

要はリテラル値をまとめて書いておくということです。

ただこのように実行ファイルに分けていてもファイル名が script とかにする人がいたりして…それはそれでわからなくはないのですが、mainの方が無難じゃないですかねぇ。

あぁマシン持ち寄ってこうゆう話ししながら酒を呑む仲間がほしいなぁ…

2012年5月30日水曜日

jQueryのプラグイン limp と airy を書いた

ひょんなことからjQueryの視覚系プラグインを2つ書きました。

jquery.limp.js

ソースというかデモサイトまるごとgithubにあります。
jquery.limp.js

要素をfixed配置に変えて縦スクロールに対して少し遅れてついてくるというものです。
いわゆるパララックス効果的に使えるんじゃないかと思います。

DEMO

limpという名前はlimpbizkitからとりました。僕の青春です。

jquery.airy.js

こちらもデモサイトまるごとgithubにあります。
jquery.airy.js

要素をabsoluteで配置しておくとフワフワとその場を浮遊するというものです。
こちらは使い道が難しいですね。

DEMO

両者ともcoffeescriptで書いてsinatraでサーブしてるのですが、素のjavascript書くのしんどいですね最近……

2012年5月18日金曜日

WebGLに感動したのでThree.jsを触ってみた

このギャラリーの作品はどれもレベル高くてすごい

Chrome Experiments - WebGL Experiments

見てたらWebGLをかじってみたくなったのでThree.jsというのを試してみた。

mrdoob/three.js

リポジトリを落としてきてsinatraに乗っけてherokuにアップしときました。
Three.js Learning
トップページはexamplesの一覧です。

とりあえず本家のGet Startting試してみたけど、動かないとつまらないのでマウスの動きに反応するようにした。

うーん道のり長そうだなぁ

iPhoneだと動かないのかな?

2011年11月20日日曜日

jQueryを使用したJavaScriptコーディングスタイル



こんな感じに落ち着いてる。
CoffeeScript覚えるのめんどくさい。