iOS13にしたら、同期処理のAjax後のwindow.openができなくなった

Facebook にシェア
Pocket

今まで、Ajax後にwindow.openで新規ページを開きたい場合、同期処理でAjaxを呼ぶようにすると(それをAjaxといっていいか微妙ですが…)、ポップアップブロックをオンにしていてもページを開くことができました(参考:Ajaxでポップアップブロックを回避する方法 – LAZE SOFTWARE)。例えば下記のような処理です。

Ajaxの書き方が古いとか言われそうですが、xhr.openの第3引数でfalseを指定すると、非同期ではなく、同期処理になります。こうすることで、ポップアップブロックしていても今までなら

ですが、iOS端末でiOS13(もしくはiPadOS13)にアップデートすると、同期処理のAjaxでもwindow.openが機能しなくなってしまいました(泣)。

ちなみに、window.openの返り値はwindowオブジェクトではなく、nullになります。nullならポップアップを許可してくださいとメッセージをだすことができそうです。

なお、もう一つの対策として、Ajaxを呼ぶ前に空のページでwindow.openを呼んでおくという方法があるようです。
参考:クリックイベントの中で非同期処理したあとに別ウィンドウで開くときにポップアップブロックにひっかからない方法 – Webtech Walker

これでうまくいけそうですね。一つ欠点としては、Ajaxで判断してエラーなどがあった場合も新しいウィンドウが開いてしまいますが、その場合は、「w.close()」で閉じればいいだけです。

imgタグのsrc属性を書き換える時の注意点

Facebook にシェア
Pocket

imgタグのsrc属性を書き換えて画像を置き換えたい時ってありますよね。

例えば、下記は青単色の画像と海の画像をラジオボタンで切り替えるサンプルコードです。

HTML

JavaScript

サンプル:imgタグのsrc属性置き換え(その1)

このサンプル、青単色の画像は1.52KBなのにたいし、海の画像は3.91MBです。ただ、回線が遅いインターネットを使ってる方は分かると思うのですが、「海」のラジオボタンを選択してすぐは青の画像が表示されたままです(速い回線のインターネットを使ってる人はGoogle ChromeのNetworkタブから、「No throtting」と書いてあるセレクトボックスを「Slow 3G」に変えて試してみてください)。

見てのとおり、ラジオボタンとimgタグのsrc属性は海の画像のURLになっているのに、画像自体は青単色のままです。海の画像自体は読み込まれてから海の画像に切り替わります。

大抵はこれでも問題ないかもしれませんが、中には選択している画像(表記の画像)の種類と表示している画像が釣り合っていない状態があると問題があることもあるでしょう。少なくとも、現在自分が関わってるプロジェクトではそうです。

じゃあ、読み込んでいる間はどうすればいいかというと、一つの策として、何も表示しないとすることが考えられると思います。そのように対応したのが下記です。

JavaScript

サンプル:imgタグのsrc属性置き換え(その2)

ようは、ラジオボタンを選択したら、imgタグのsrc属性自体は空にし、JavaScriptで作成したImageオブジェクトにラジオボタンで選択した画像のURLを指定します。で、そのImageオブジェクトに、loadイベント、つまり画像が読み込めた時のイベントを指定して、読み込めたらimgタグのsrc属性を置き換えるというような感じです。

実際はもう少し、キャッシュなども考慮した処理をいれているのですが、選択した画像の種類と実際に表示している画像が異なってはいけないことがあれば、参考にしてみてください。

JavaScriptの配列の反復処理にfor..in文を使うとインデックスが文字列型になる

Facebook にシェア
Pocket

気づいたら元号が変わってました。アウトプットが大事と書かれている本を読んでインプットしながら、アウトプットしない日々を送っています。

先日、仕事で配列の探索をしようと、下記のような処理をしました(実際にはもう少し複雑です)。

やっていることは単純に、配列からある’バナナ’という文字列が入っているインデックスを取得し、インデックスが1だった場合に、コンソールに’バナナは2つ目です’と出力しているだけです(これぐらいならArray.prototype.indexOf() – JavaScript | MDNを使えよと思われそうですが、実際にはもう少しループの中で複雑なことをしていました)。

一見、普通に’バナナは2つ目です’と出力されるような気がしますが、何も出力されません。見つからなかったら、’バナナはみつかりませんでした’と出力されるはずですが、それすらでてきません。

おかしいなぁ。と思って試しに、「i === 1」を「i == 1」としてみると、なんと’バナナは2つ目です’と出力されました。もしかしてと思って、最後に「console.log(typeof pos)」といれると、stringと出力されました。

配列のインデックスを「arr[‘0’]」というように、数値の文字列型で取得できるのは知ってたのですが、for..inを配列で使うと、インデックスは文字列型になってしまうことは知りませんでした。まあ、確かにfor..inはあくまでオブジェクトのプロパティ名が代入される処理ですしね。

MDNを見ると、「注: for…in はインデックスの順序が重要となる 配列 の繰り返しには使うぺきではありません。」と書かれてました(参考:for…in – JavaScript | MDN)。普通のforループかforEachを使うのがよさそうです。

ただ、forループだといちいちlengthの指定が必要だし、forEachだと途中で抜けれなくて無駄な処理が多くなりそうなので、for…inにしました。ですが、もう少し調べてみると、Array​.prototype​.some()を使うと自分のやりたいことはできそうだと発覚。

Array​.prototype​.some()ってあまり使う機会ないと思って使ったことなかったんですけど、こういう使い方もあるなら結構いろいろ使いどころありそうです。

jquery.ajaxに代わる、Fetch APIについて

Facebook にシェア
Pocket

最近のJavaScriptでは、jQueryに依存しない書き方が増えてきたようです。ただ、確かにセレクターなら、document.querySelectorAllメソッドを使えばいいだけなんですが、個人的にjQueryで便利なところは、ajaxだと思ってるんです。いちいち、XMLHttpRequestがどうちゃらこうちゃらとか書きたくないし、だいいち覚えられない。だから自分は、jQueryからはなかなか離れられないだろうし、離れたとしてもAjaxようの共通関数は実装することになるんだろうなぁ。と思っていたら、最近になってFetch APIなんてものを知りました。

最近のWeb技術界隈は追えていないと思ったらこんなものが。というわけで、調べて使ってみました。

HTML

PHP

サンプル:Document

やってることは、サーバーに数値と文字列をPOSTで渡すと、数値を2倍、文字列をSHA-256でハッシュ化した結果をJSON形式で返すというもの。例えば、数値を123、文字列をabcとすると下記のようになりました。

確かに数値は2倍になって、文字列はハッシュ化して返ってきました。ちょっとよく分からなかったのが、最初にResponseオブジェクトからどういう形式で値を取得するかという指定が必要なこと。これがPromiseオブジェクトで返ってくるので、いちいちthenを二回書かなきゃいけないという。response.json()で返ってくる値がPromiseオブジェクトじゃなくて、JSONオブジェクト(多重表現)になってるほうが直感的でわかりやすい気がするのだけど、多分、こうなってるメリットはあるんだろうと思う。このへんは多分、自分がPromiseについてよく分かってないから疑問に思ってるのだと思うので、もう少しこのへんも勉強していこうと思う。

ところで最初、fetchのbody部分を「body: new FormData(document.getElementById(‘frm’))」と指定しようと思ったのですが、それだといまいちメリットがないなと思ったら、JSONで渡せることを知ったのでそうしました。PHP側で『json_decode(file_get_contents(‘php://input’), true);』とすればいいそうです。初めて知りました。JSONのまま渡せるなら、便利ですね。これからはそうしようかな。

画面内に入ったり出たりした時の処理を行う「Intersection Observer」について

Facebook にシェア
Pocket

先日、超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)という本を読んで知ったのですが、最近のWebブラウザのJavaScriptには、「Intersection Observer」というAPIがあるらしく、このAPIを使うことで画面内に入ったか(もしくは画面外に出たか)どうかを判定できるそうです。

便利そうなので、試しに使ってみました。画面に四角い要素を100個並べて、画面に入ったり出たりすることで背景色が変わるサンプルです。試しに、今まで知ってはいたけど使ったことがないCSSアニメーションや、ES6から実装されたletやconstやアロー関数も使っています。

HTML

CSS

JavaScript

サンプル:Intesection Observeテスト

スクロールしたり画面サイズを変更したりすることで、四角い要素が画面内に入ると、背景色が1秒かけて青からオレンジに変わると思います(IE以外の最新ブラウザ対応)。

ただ、すばやくスクロールしているとたまにうまく動作しないことがあるみたいです。あまりアテにしすぎるのもよくないのかも(自分がよく分かってない可能性もおおいにあります)。

なお、IntersectionObserverの第2引数にはどの要素の交差を判定するか(なければブラウザのビューポート)のrootと、ルート回りの余白を指定できるrootMargin、それと可視性がどれぐらい入ってるか出ているかでコールバックを実行するthresholdというオプションがあるそうです。
参考:Intersection Observer API – Web API インターフェイス | MDN

超速!  Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)
佐藤 歩 泉水 翔吾
技術評論社
売り上げランキング: 11,340