AngularJSでhover
AngularJSでmoment.js使いたいとき
urish/angular-moment · GitHubってやつがあった。
ほかにもangular-momentjsって名前のやつがいくつかあるけど、↑のやつが一番よさそう。
こんな感じで使う。
$scope.date = new Date() $scope.epoch = 1000000000000
<time am-time-ago="date"></time> <time am-time-ago="epoch"></time>
数字を渡すと、エポック秒と判断して、内部でnew Date(value)
してくれる。
2014/01/01 12:00:00みたいに文字列を渡したい場合は、
<time am-time-ago="'2014/01/01 12:00:00'" am-format="YYYY/MM/DD HH:mm:ss"></time>
ってやってあげると良いらしい。
am-time-agoのシングルクォーテーションを忘れずに。
am-formatに関する記述がREADMEになくて、最初使えないなーって思ってた。
他にも、
<time>{{ date | amDateFormat:'dddd, MMMM Do YYYY, h:mm:ss a'}}</time>
みたいなフィルターもあるけど、READMEに書いてあるので読めば分かる。
ngShowの表示非表示でアニメーションさせる
ng-hideにdisplay: none !important
がかかっているので、こんな感じにかけばいいらしい。
これで、アニメ終わったらdisplay: noneしてくれるので、アニメ要素が上にかぶってタップできない、みたいなことも起きないはず。
HTML
<div class="animation-element" ng-show="show"> なんかなんかなんかなんかなんかなんか </div>
SCSS
.animation-element { @include transition(150ms linear all); // アニメ中はblockにしてやる &.ng-hide-add, &.ng-hide-remove { display: block !important; } // 表示→非表示 &.ng-hide-add { @include translate3d(0, 0, 0); opacity: 1; } &.ng-hide-add-active { @include translate3d(0, 20px, 0); opacity: 0; } // 非表示→表示 &.ng-hide-remove { @include translate3d(0, 20px, 0); opacity: 0; } &.ng-hide-remove-active { @include translate3d(0, 0, 0); opacity: 1; } }
同じ動き
これでもOKだけど、スペックの低いスマホの場合、クラスの付け替えでチカチカする恐れあるので上のほうが安全そう。
.animation-element { @include transition(150ms linear all); @include translate3d(0, 0, 0); opacity: 1; // アニメ中はblockにしてやる &.ng-hide-add, &.ng-hide-remove { display: block !important; } &.ng-hide { @include translate3d(0, 20px, 0); opacity: 0; } }
AQUOS PHONEでposition: fixedを指定した要素より後でキーボードが開かない
ヘッダーとかフッターとか固定するのにposition: fixedを使用すると、Android2.3ではもろもろ問題が起こるんだけど、その一例としてAQUOS PHONEでキーボードが開かなくなるようだ。
どう解決したもんかなと思ったけど、ヘッダー/フッターみたいな感じで位置固定しているならbodyのいちばん後ろに書いても表示位置変わらないじゃんと思って、いちばん下に持って行ったら解決した。
Android2系滅びろ。
一部のAndroid4.x端末でtouchstartでe.preventDefault()してもclickイベントが発火する
Galaxy Nexus(Android 4.2.2)とか他のAndroid4.1.2の端末で、e.preventDefault()しているにも関わらずclickイベントが呼ばれてしまうバグ?
背景
iScrollを使用しているサービスを一部のAndroid 4.2.2, 4.1.2端末で見ると、clickイベントが2回呼ばれてしまう。
どうも、iScroll内では、touchstartでe.preventDefault()して、touchendでclickイベントを発火しているのだが、デフォルトのclickと、iScrollのclickの二回呼ばれるらしい。
問題の端末 | Galaxy Nexus(android4.2.2) SO-01E(android4.1.2) Nexus S(android 4.1.2) |
対象のブラウザ | WebView, 標準ブラウザ (Chromeは問題なし) |
使用ライブラリ | iScroll 4 |
SO-04E(android4.1.2)、SC-04E(android4.2.2)や(4.0|2)系端末だと問題は起きない。もちろんiPhoneも。
コード
iScrollでは、touchendで、ダブルタップ検出のために250ms待ってからclickイベント発火させるみたいなことしているので、擬似的なのを実装。
<div id="click">ここをクリックすると</div> <div id="result"></div> <script> (function() { $('#click').on('touchstart', function(e) { e.preventDefault(); }).on('touchend', function() { $(this).trigger('click', ['clickされたで']); }).on('click', function(e, message) { message = message || 'こいつぁ。。。'; $('#result').append('<div class="child">' + message + '</div>'); }); })();
DEMO
スマホしか対応してないけど。
動作
PCとか普通のブラウザの場合
クリックすると「clickされたで」だけが表示。10回クリックすれば10個表示。
問題の端末
クリックすると「clickされたで」「こいつぁ。。。」の要素が表示される。
対策
どうしようかな…。
フラグ的な何かで管理するとか?
(function() { $('#click').on('touchstart', function(e) { e.preventDefault(); $.data(this, 'is_preventdefault', 1); }).on('touchend', function() { $(this).trigger('click', ['clickされたで']); }).on('click', function(e, message) { if ($.data(this, 'is_preventdefault') === 0) return; $.data(this, 'is_preventdefault', 0); message = message || 'こいつぁ。。。'; $('#result').append('<div class="child">' + message + '</div>'); }); })();
iScroll 5にするとか
iScroll5だと大丈夫なんだけど、コードが違いすぎて、何が原因でなおってるのか分からん…。
e.stopImmediatePropagation(), e.stopPropagation()あたりかなと思いつつ、上のコードに仕掛けてみたけどダメだった。
まとめ
e.preventDefault()をtouchstartで呼ぶと、clickイベントが発火しないって認識だったんだけど、違うのかな。他の端末では認識通りの挙動したけど、単純にブラウザによって違うだけ?それともバグ?
よく分からんが、こういうケースに出会いましたよってメモで。
手元のトピックブランチをmasterにマージしたか確認する
いろんなブランチさわっていると、どれをmasterにマージしたか忘れてしまって、マージしてないのに終わった気になってgit branch -dとかしちゃいそうなので、まるっと確認するコマンド考えた。
% git co master % git branch | grep -v '*' | xargs -t -I% git --no-pager log --oneline master..%
手元のブランチ名全部取ってきて、トピックブランチにはあるけどmasterにはないcommitがあるかどうかを一覧してくれる。
xargsの-tは実行前にコマンドラインを標準エラー出力に表示してくれるやつ。
マージされたやつだけを探すなら次のコマンドで十分ですね。
% git co master % git log --oneline --merges
と思ったら
ふつーーーーーにこんなのがあった!!!
% git branch --no-merged % git branch --merged
悲しい。最初にヘルプ見ろって話ですね!
compassでcssスプライトするときの出力をできるだけ少なくする試み
概要
Sprite layouts | Compass Documentation
compassでのcssスプライトを試してみたのでメモ。
sprite-backgroundっていうmixinは結構色々な人がブログに書いてるんだけど、retina対応していなかったり、無駄な処理が入っていたりしてなんかしっくりこなかったので自分で実装してみた。
完成品
以下のファイルは使い回せるので、mixins/_sprite.scssみたいにプロジェクトに依存しないファイルとして置いておく。
@mixin sprite-background-size($name, $sprites, $device-pixel-ratio: 2) { $_width: image-width(sprite-file($sprites, $name)) / $device-pixel-ratio; $_height: image-height(sprite-file($sprites, $name)) / $device-pixel-ratio; height: $_height; width: $_width; background-size: $_width auto; } @mixin sprite-background-position($name, $sprites, $device-pixel-ratio: 2) { $_pos: sprite-position($sprites, $name); $_x: round(nth($_pos, 1) / $device-pixel-ratio); $_y: round(nth($_pos, 2) / $device-pixel-ratio); background-position: $_x $_y; } @mixin sprite-background-image($name, $sprites, $sprites-image, $display: block) { display: $display; background-image: $sprites-image; background-repeat: no-repeat; } // shortcut @mixin sprite-background($name, $sprites, $sprites-image, $display: block, $device-pixel-ratio: 2) { @include sprite-background-image($name, $sprites, $sprites-image, $display); @include sprite-background-position($name, $sprites, $device-pixel-ratio); @include sprite-background-size($name, $sprites, $device-pixel-ratio); }
使用方法
単純に色々な画像突っ込んだsprite画像の場合、またはCSS大きくても気にしないよって場合
scss
$sprites-all: sprite-map("all/*.png", $layout: smart); $sprites-all-image: sprite-url($sprites-all); .star { @include sprite-background('star', $sprites-all, $sprites-all-image); } .banner { @include sprite-background('banner', $sprites-all, $sprites-all-image); } .logo { @include sprite-background('logo', $sprites-all, $sprites-all-image); }
css
.star { display: block; background-image: url('/img/all-s5858cd14d5.png'); background-repeat: no-repeat; background-position: 0 0; height: 16px; width: 16px; background-size: 16px auto; } .banner { display: block; background-image: url('/img/all-s5858cd14d5.png'); background-position: -16px 0; background-repeat: no-repeat; height: 30px; width: 80px; background-size: 80px auto; } .logo { display: block; background-image: url('/img/all-s5858cd14d5.png'); background-position: 0 -16px; background-repeat: no-repeat; height: 40px; width: 120px; background-size: 120px auto; }
アイコンとかhoverとか同じサイズの画像が並んだsprite画像の場合
width, heightとか余計にアレするの嫌なので、そういうのは共通のクラスでやって、個別にはpositionしか書かない。
scss
$sprites-pager: sprite-map("pager/*.png", $layout: smart); $sprites-pager-image: sprite-url($sprites-pager); @mixin sprite-background-pager-base($name) { @include sprite-background-image($name, $sprites-pager, $sprites-pager-image); @include sprite-background-size($name, $sprites-pager); } @mixin sprite-background-pager-position($name) { @include sprite-background-position($name, $sprites-pager); } .prev-pager { @include sprite-background-pager-base('prev'); @include sprite-background-pager-position('prev'); &:hover { @include sprite-background-pager-position('prev-hover'); } &.disable { @include sprite-background-pager-position('prev-disable'); }
css
.prev-pager { display: block; background-image: url('/img/pager/pager-s3354cd445.png'); background-repeat: no-repeat; height: 40px; width: 70px; background-size: 70px auto; background-position: 0 0; } .prev-pager:hover { background-position: 0 -40px; } .prev-pager.disable { background-position: 0 -80px; }
特徴
optionで表示をカスタマイズしやすく
- sprite画像使う要素のdisplayはblockにしたいときとinline-blockにしたいときがあったのでoptionで渡せるようにした
- retina対応用にdevice-pixel-ratioを渡せるようにした
- 普通に"/ 2"とかやると、何やってるのかわかりづらいので変数名で何やっているのかわかりやすくした
mixinを細かく分けて出力をカスタマイズしやすく
- positionだけ渡したいなと思って、positionだけ吐くmixinを用意してsprite-backgroundで@includeするようにした
- 細かくimage, size, positionに分けたのでさらに頑張りたい場合は、それぞれの画像サイズが違うspriteの場合でもimageの部分だけ共通クラスにあてることもできる
その他細かいところ
- sprite-urlを@mixinの外でやっているのはコンパイルの高速化のため
- sprite-mapで$layout: smartすると余白を埋める感じで画像作ってくれる