2015.03.29

jQuery iOSでもひよこを止めろ!

以前jQuery スクロールに付いてくるtopに戻るボタンという記事を書きました。
iPhoneでは謎の挙動で実現できなかった下までスクロールしたらfooterの他の物と重ならない位置に追随ボタンを固定したい。という望みが一応、叶いましたので備忘録として書き留めたいと思います。

ヘンな高さを算出してる問題

Mobile Safariの ’$(window).height()’で取得する数値が変なのよねーという問題だったようです。
当時は調べ方が悪く.scrollまわりのバグ?という情報しか拾えませんでしたが、scrollは関係なかったもよう。

正しいwindowの高さを取得するには、javascriptのinnerHeightを使うとのこと。

参考サイト:
jQueryでMobile Safariの$(window).height()の正しい値を得る方法 – memo.yomukaku.net

まるっと頂きました。

画像やAjaxを読み込む前に高さを算出してる問題

原因はもう一つ。
症状は止めたい位置にボタンがさしかかるといきなり画面上から消えてしまうというものでした。表示外のとんでもない位置に固定されていたんですねw 画像が全て読み込まれないreadyイベントの段階でdocument全体の高さを習得していたのも原因のようです。
画像を含めたページ全体の読み込みが出来たところで、documentの高さを.height()で取得するために
今回はjQueryの

を使うことにしました。

最初のスライド動作がぎこちなくなるものの、ボタンがどっかに行っちゃうことはなくなりました。

でもでも、画像の読み込み後の処理は別にした方が良くない?問題

これでいいかなぁーと思っていたのですが、既にreadyイベントの中で’$(window).on(‘load’,function{..’ を使っている部分があったのを思い出しました。
モバイルなどでは、ページ読み込み完了前にスクロールを始めることの方が多いかもしれませんし、ボタンのスクリプト自体はDOMの構築後発動してくれておもいっきり差し支えない訳で…
ボタンを止める位置のスクリプト部分のみ.onの引数のfunction内に書き直しました。

これでブラウザ共通のスクリプトになりました。iPhoneの分岐を書かなくてよくなったので、コードを少し減らす事ができました。
はーすっきり。

2014.07.19

jQuery retinaディスプレイの画像を差し替えて生js多めで学習してみた。

MBPを買ってからというもの自分でも見えちゃうので、Retinaディスプレイでの自分のブログの画像の見え方、なんとかしたいな〜と思っておりました。
ご存知の通り、retina用に縦横2倍サイズの画像を用意して対策するのが良いようです。
便利なJqueryプラグインには及びませんが、いつものjQuery学習という事でタイトル周りとテンプレートのイラストとiconだけでも自分でなんとかしてみることにしました。

wordpressで投稿した画像などは未対応です。これはどうしようかまだ基本方針がかたまりませんも。

iPhoneはどうでもよくてよ!

別サイトを用意してないのでこのブログは大きいディスプレイとモバイルと共用です。
iPhoneに関しては基本、横幅1000pxの土台を縮めて表示してる訳なので、おおむね奇麗!
なるべく本文はiPhoneでも(ダブルタップで拡大されるブロックの幅調整で)見やすいようにしているつもり…という逃避w
へっぽこスクリプトも相まって画像で重くなるのもなんですし、
retinaディスプレイを切り分けて、なおかつiPhoneは除外しようと思います。

retinaディスプレイか否かはwindow.devicePixelRatioで判定。retinaは1よりも大きい数字を返すだす。
そんで、ifを入れ子にしてiPhoneかどうかを判定。

.searchメソッドは引数の正規表現が見つからない場合-1を返します。

よってこの場合、-1だったらiPhoneじゃないもんね!ということになるので、ここにiPhone以外のretinaディスプレイの場合に、画像を差し替えるスクリプトを書いてゆくだす。

差し替える画像は全部じゃないのよ…

とりあえず差し替えたい画像は、このブログで言うと

  • ブログのタイトルロゴ(img)
  • タイトルバックのイラスト(background-image)
  • 記事のタイトル h1,h2(background-image)
  • 小見出し h5(background-image)
  • リンク部分の背景(background-image)
  • Twitter用のオリジナルひよこアイコン(img)

ありゃー、imgタグによる画像挿入とcssのbackground画像と2パターンあります。うっ。
一括では行かないので先ず背景画像から何とかしてみたいと思います。

画像は従来表示していた物に加え、縦横それぞれ倍の大きさにした画像をめんどくさいけど用意しました。元データを残しといて良かったです。残ってないのもありましたが…。
2倍画像の名前の末尾に_rtiとか安易な文字を足して、replaceと正規表現でurlを書き換えます。@2とかの方がかっこいいかも。ふん。

なにからとっかかったらいいのか謎です。とりあえず背景画像(background-image)のurlを書き換える関数から作ってみることに。
$().eachはなんとか出来るようになったので、今回は苦手意識があったforで繰り返してみます。こちらの方がjavascriptネィティブで早いんだとか。

.lengthをその都度取りにいかない

ハイライトの所、i=0と同時に変数に突っ込んでおくと最初の1度で済み、より早いそうです。

一見、forやeachで繰り返し処理をしなくてもいいような気がするんですが、実際ブラウザでも各要素にstyleが書き込まれるけどエラーがでまふ。
replaceのところがundefinedになっちゃう。
複数あるh5だと最初のh5に対してだけのcssの’backgroundImage’のurlが変数に入り、次ぎからのh5のurlを拾えないからだと思うんですが、さて。

最初のeq(0)だけ拾って一括でbackgroundを指定できないの?どうなの?
と思ったのですが、例えばh5が無いページとか該当する要素が無いとやっぱりundefinedになっちゃい汎用性がありませぬ。
この関数の引数には色々突っ込むので、今回はおとなしくループをしておいた方が良いようです。

本題に戻って自作関数の引数(chunBacks)に入れているのは’$(セレクタ).トラバース’の要素を選択の部分。
retina振り分けのifの中で

とかすると呼び出されるという寸法です。

なんでもかんでも変数に入れたい病

引数に入れる要素’$(セレクタ).トラバース’を変数に入れて置きたくなりました。
何度も同じ要素を探しに行くことになるし、特に’dl.ref a’なんかclassからだし、効率が悪いような気がします。

にしたい。したいよー。

そして、backgroundの数だけこのretina関数を呼び出すのも少々うざいです。

で、今回、考えた末にこれらの変数を配列に入れて$.eachで繰り返してみました。
なんで考えたかというと、変数を$(‘#hoge,#fuga’)の様にコレとコレとする書き方が分からなかったのです(´・ω・`)。

配列を扱うにはこっちの’$.each’ってことで使ってみました。コールバックの引数にindexと値が受け渡されるので、直接valで値が渡せて便利です。

でもイケますがvalの方がスッキリ。
たしかに4回書かなくても良くなったけど、タイプ数は大して変わらない気もします。
いや、きっと対象が増えたら便利に違いない。違いないったら。

悔しいので利便性を追求してみる

配列の書き方をpushで追加方式に変えてみる。

新しいbackgroundが増えたら後ろにどんどん追加していけばいいし、見やすい気がする…
しかし、これだと要素を変数に入れてから配列に入れているので
↓ここにも変数を追加しなくちゃなりません。

めんどくさい…

オブジェクト(連想配列)にしてしまえば、個々に変数に入れなくてもいいような…一度の追記で済むんじゃ?
コンストラクタとかインスタンスとかまだ手が届かないので今回は追求しない方向で…

お名前付き関数を作りましたが、オブジェクトにすると$.eachのコールバックの引数、プロパティ名(key)とプロパティ値(value)が使えそうなのでeach内に書き直してみます。

firebagで確認するとfor文ブロックの中のvalにもオブジェクトmosBacksの値である$(‘セレクタ’)がちゃんと渡されてます。
10行目、後で上書きするしかないと思っていたところもif文でkey(プロパティ名)を比較して分岐が出来るようになりましたラッキー。(?)
よしこれで行ってみよう。

imgはどうなの

background-imageの時と大体同じ、srcを操作するだけですな。

今回はオブジェクトにブラケット表記[ ]でプロパティを追加してみました。ドッド演算子と書き方が違うだけで同じ事をしているだけなんだけど、書いてみるとなんとなく連想配列で値を取り出す方法も身に付くような?気がします。
ブラケット表記では中身を文字列として扱う。
変数も入れられる。
ちなみに6行目、for の引数の中で mkeyと変数を宣言しているので””で囲って文字列にするとundefined。
そして今度は$.eachではなく、練習の為にfor in文で繰り返してみました。

for in文はオブジェクトに含まれるプロパティの数だけ繰り返し処理をする。

順不同だけど今回の場合は全然問題なし。
backgroundの時の様に繰り返し処理をしなくても大丈夫。今のところimageは親要素に対してそれぞれ一個づつしかないしー、
複数個ある場合は繰り返さなくてはならんのであとで書き直しが生じるけど、今のところ大丈夫だしー。(ちょっと頭が追いついていません、すみません)

しかし!問題発生…(追記です。)全然大丈夫じゃなかった。がっくし。

該当するimg要素がないとundefinedになっちゃうのよ…

//2015/3 追記しました。
オブジェクトに入れたimg要素が全て揃っている時は上記の方法で問題ないのですが、ハイライト部分のimgを使わないページで、エラーがでます。

タイプエラーとな。

そもそもhtmlに要素が存在しないので、srcを取得をぶっ込んだ変数がundefined。変数を利用する文字列置き換えのスクリプトの部分が評価されず、後続の存在するimgのみならず後に読み込まれるスクリプトまでも止まってしまいます。うう。

img要素の有無を判定をして、continue的な事ができればいいんだけど…
for inだとどうやるのか分からないので、またjqueryの$.eachにお世話になります。…いいんだ学習だから。ごめん。

$.eachで処理を飛ばすには、こちらを参考に。

参考サイト:
jQuery::ループ内の continue / break [Tipsというかメモ]

ifの条件にしたい要素の有無判定をこちらを参考にさせてもらいました。

参考サイト:
jQueryによる要素の存在チェックまとめ: 小粋空間

書いてみる。

6行目、val(値)にはそのままセレクターを突っ込んであり、今の所セレクターに対応するimg要素は1個しかないのでimg要素が存在したら0番目の要素となります。
ifの条件”val[0]”でセレクターの0番目がゲットできたら処理。img要素が存在しなかったらelseとなるので、 return true(continue)で処理が飛ばされます。
しかし、やっぱり2個以上セレクターに対する要素が存在したらelseになるので、その場合はまた内部でforなりしなくてはならくなるかと。

余談だけど、なんでbackgroundの方ではh5など要素が無くてもエラーにならなかったのか疑問だったのだすが、eachの中のfor文の条件式によって処理が飛ばされておったのですな。
htmlに要素がない場合eachには’head{}’と空のオブジェクトが返ってきて、それに対して第2引数のfunctionが実行されるんだけど、中のfor文は条件式によってlengthが0の場合は実行されない。functionへの返り値は恐らくundefinedになるのかな?
eachの第2引数へfalse以外のfalse的な値が返ると要素の処理がスキップされるので結果オーライだったと…そ、そうだったのか。

eachに書き換えても存在確認の条件式が無いとタイプエラーになります。
「eachに書き換えたら、もしかしてこのundefainedスキップされるんじゃないの?」というイージーな思考が沸き起こりましたが、
このタイプエラーのundefinedは中の変数に対してであって、eachの第2引数のfunctionにundefinedが返ってる訳ではないのに早く気づくべきものでありました。(やってみた)

試行錯誤の末、全体はこんな感じになりました。

// 追記終了

iPhoneにもなんかしたくなった時は、elseの中に書いてやります。
background-imageのためのオブジェクトがifの外に出てるのは、elseでiPhoneの処理をしようと思ったときにスコープってんですか?届かないんですね。関数の中だけなのかと思っておりました。
image用もiPhone用の処理をするときにはお外に出してやらないとなりませんな。

imgにはwidthいるよね…取得できないよね…(力尽きた)

画像のサイズは2倍なので、表示サイズを指定しなくてはなりません。
background-imageだとbackground-size:containなど便利なプロパティがあるのですが、imgはそうはいかんのです。
スクリプトでどうにかしようと思ったのですが、cssに指定してしまったほうが精神的に良いという結論に落ち着きました。

Firefoxではうまく行くのだけど、safariで画像サイズが読み込みのタイミングでか取得できずページ遷移では2回に1回くらいcssの指定が0pxになってしまう。
ブラウザボタンからのリロードでもサイズが0pxに。もがっ。
srcには生のパスを突っ込まないとダメなのかもしれません。new Imageの引数にサイズも指定できますが、それらをやろうとするとcssに記述するのと同じくらいの手間になり便利さは薄い訳で…やーめた!( ´・ω・)。

やってみて

実際に当wordpressで使ってまする。へんになってたらごめんなさい。指摘してやってください。safariとfirefoxでしか見てません(・ω・;)。
今回はjavascript成分が多めの勉強になりましたが、関数リテラルとかオブジェクトオブジェクトとかコンストラクタとかインスタンスとかなにそれおいしいのワカメ?的なことのほんのとっかかりが出来たのでよかったです。
javascriptは難しいなぁ。jQueryがあってよかったよぅ。

2014.01.20

jQuery 追加の置換をしたいのよ〜正規表現?(`・ω・´)キラッ

先ず何から取っ掛かっていいのかも分からないほど…jQuery学習にブランクが開いてしまいました。
少々いじる機会があったのでリハビリ備忘録を付けておきます。

階層が違うyo!相対パスが切れるno!

メインサイトさわやかまみれを更新するとき、面倒のなきようナビゲーションが置いてある各ページ共通のfooterに外部ファイルのhtmlを.loadで読み込んでます。
(以前書いた記事『備忘録 jQuery .loadでfooterを管理 & ウィンドウサイズで位置変更』)

階層が違うページに共通仕様のfooter.htmlを読み込ませるとナビゲーションや画像のリンク(相対バス)が切れてしまうため、別階層用のfooter.htmlを用意しておりました。
変更があれば当然、二つのfooter.htmlを直さなくてはなりません。
めんどくさい。
めんどくさいという理由からcssを覚えjQueryに手をだしたのに…むっきー

そこで今度は一つのfooter.htmlで済むようにロード時にリンクを書き換えるスクリプトをなんとかしようと思います。

loadで読み込むfooter.htmlのパスの分岐

footer
まず、footer.htmlへのパスを分岐させる条件を付けるべく下の階層にあるunder.htmlの<body>にidを振り、

bodyにid=under_layerがある時は上の階層へのパス、それ意外の時は同じ階層という具合に分岐をしておきました。

そしてunder.htmlに読み込んだfooter部分のリンクのパスを変えるべく上記.loadのfunction()の部分、コールバック関数で小細工をしたいと思います。

各ページへのLINKと画像のパスを書き換える

一階層上のファイルにアクセスしたいだけなので、相対バスの頭に../を付けてやればいいだけなのです。
簡単です。簡単に違いありません。しかし方法が分かりません…
aとimgの属性をそれぞれ.attrで書き換えてやればいいんです。
しかし、単純にhrefをattrで拾って、

するとツイッターやブログのアドレスのhttpから始まる部分の頭にも../がついてしましま。

そこでググったところ.replaceで正規表現とかなにそれ魔法?という方法が見つかりました。

3行目。attrで取得したurlを.replace(“置換したい文字列”,”置換後の文字列”)で置き換えるのですが、置き換えるんじゃないの、頭に追加したいのという希望をかなえるのが、最後の$1の部分。
正規表現で文字列を()でグループ化しておくとキャッシュしておいてくれて、後方参照ちうので使い回せるんです。

ところでちょっと正規表現の覚え書き。
/スラッシュ/で囲った部分が正規表現。クォートでは囲まないよ。
スラッシュ内の()は文字列をグループ化。
[a-z]+ 小文字a~zまでのいずれか一文字を一回以上繰り返し。(baa)
\.html$ バックスラッシュでドットをエスケープして文字としてあつかい、最後が.htmlと一致(.html)
| の区切りは’または、’でrssも検索(foo.rss)
最後のgで複数個文字列を検索。(この場合いらんかも?)

.replace(/置換したい文字列の正規表現/,”追加する文字列$1″)の$1にグループ化しておいた文字列baa.htmlが参照され
../baa.htmlとなります。

やった(∩・ω・)∩なりました。
画像も同じようにsrcを置換してやることにします。画像はまたフォルダに入ってるので、正規表現をちょろっと変えなくては…
.+jpg$とかでいいかなぁ。
ちょっと正規表現は難しいですが、覚えると色んな事ができそうですな。

参考サイト:
JavaScriptの正規表現で文字列を抜き出す「グループ化」: 小粋空間
jQueryで正規表現を学んでみる。【基礎編】 | webOpixel
サルにもわかる正規表現入門
くそぅ404の亡霊

リンク切れもなく、画像も無事に表示されておりますが、SafariのWEBインスペクタのコンソールに画像がノットファウンドだとエラーがでちゃいます。
Firefoxコンソール、FirBugではエラーありません。
404だという画像のパスはunder.htmlと同じ階層になってまふので、読み込みのタイミングだとは思いますがちょっと悲すぃですね。

2013.03.21

WordPress キノコは最初から隠すべき キリッ!(コメント件数の表示)

kinoko_wo先日からごにょごにょと何やらしている当ブログ。
jQuery 重いらしいcontainsフィルターを書き換えてみる
でコメントの有る無しでコメントの件数の表示をon/offするjQueryをふんだららーと記述しておりますのをまた変えてみました。

ループで記事のタイトル周りに件数を表示させています。 comment_numberの引数にそれぞれn=なし 1=1件 %=それ以上の数字を渡してます。
んで、前回はnのコメントが無い時を条件にjQueryでスクリプトを書いたのですが、今回はコメントがある時を条件に書き直してみました。

なぜかと言うと、やっぱりキノコがちら見えしちゃうからですw
あった物が消えてしまうのはコンマ何秒とはいえ、とっても不自然です。
逆に遅れて表示されるぶんには違和感がありません。コメントも滅多にないしねw

そこで、始めからcssでcomments-linkのdivをdisplay:none;で非表示にすることにしました〜。
よけいなリンクができちゃうなというのは、今回は無視。うっ。

ハイライトした三行目、以前正規表現で文字列 n を探していた部分を\dと書き換えただけー。
\dは正規表現で数字を示してます。
aのテキストに数字があった時、親要素にclass on_comments-linkを追加。
よけいな処理をするのかなーと思って前回検証した.matchはやっぱり.testに書き換えました。

cssでは、.on_comments-linkにdisplay:blockを指定して上書き。
そんなけ。そんなけにたどり着くまでずいぶん時間を要したなぁ。

…勉強になった!

2013.03.16

jQuery 調子に乗って正規表現でfilter(function(){~しまくってみる

前回と同じ.filter(function(){})で要素を選択しようというネタなんですが、調子に乗って今度はidをふるい分けてみました。
なんでidをふるい分けるんじゃ!id最強だろう!!なのですが…。
今回はWordpressのプラグインWP SyntaxHighlighter の吐き出す idを練習を兼ねてごにょごにょしてみたいと思います。

Wordpressが書き出してくれるhtmlはこんな構成になっております。
’p’のmarginを広くとっているためsyntaxhighlighterが文章から浮いた感じになってしまっておりました。
syntaxhighlighterの前後にある’p’のみ、marginを調整して、文章とのつながりを持たせたい。

よく見るとsyntaxhighlighterは名無しdivの子要素のdivに個別のidを割り振ってます。

id="highlighter _364948"

こっからなんとかたどれそうだけど、一つずつに’highlighter_連番’が振られた膨大な数のidをセレクタにするのは無理です。
でも、’highlighter’部分は共通だよね!
そこで、さっき覚えた正規表現とやらを試してみることに。

^ という記号で先頭からの位置指定ができるようです。
「もしかしてセレクタに使えるんじゃ!」と思いつきましたが、セレクターに正規表現は使えないようです。
やっぱり、覚えたての.filter(function(){})をまたしても使うことにします。

思いっきり同じです。$mainという変数は単純にメインカラムのwrapのdivです。
メインカラムからfindしたdivのうち、idの先頭の文字列がhighlighterのdivをfilterしています。ルー大柴みたい。

しかし、最終的に操作したいのは’p’なので、いったんhighlighterの親要素の名無しdivにさかのぼり、変数にぶっこみました。
ここまで前回と全く同じです。

変数 synFTpでは最終的にsyntaxhighlighterをラップしている名無しdivを選択しています。前後のpはこのdivの兄弟要素ということになります。
そこでjQueryの強力なAPIを使います。Traversingというらしい。findもfilterもそうなんだけど、横断するという意味らしい。
おなじみヌーさんの所から引用させていただきますと

prev([expr]) – jQuery 日本語リファレンス

要素集合の各要素の「前」にあたる兄弟要素を、全て抽出する。

このprev関数はあくまで各要素のすぐ隣の要素のみを抽出し、前以前を全て選択するわけではない。その場合はprevAll()を用いること。
引数には条件式を指定し、結果セットから更に絞込みを行うことも可能。

next([expr]) – jQuery 日本語リファレンス

要素集合の各要素の「次」にあたる兄弟要素を、全て抽出する。

このnext関数はあくまで各要素のすぐ隣の要素のみを抽出し、次以降を選択するのではない。その場合はnextAllを用いること。
引数には条件式を指定し、結果セットから更に絞込みを行うことも可能。

このprevとnextを使い前後の兄弟要素’p’へクラスを加えcssでmarginを設定しました。

だがしかし…動かないよー

動かないんです。WP SyntaxHighlighterはfooterにscriptを書き出しているので、別の外部ファイルにしてwp_enqueue_scriptでfooterに書き出してやればいいかなと思ってました。
実際、WP SyntaxHighlighterのscriptの後に書き出されるのですが、動きません。うっ。
間に合わせの手段ですが、

function(){・・・・・・}の中に書いてやるとページが読み込まれてから中に書いたscriptが実行されます。
だがしかし…これを足したせいか、せっかく速くなったキノコ表示が遅くなったような気がします…

PageTop