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属性を置き換えるというような感じです。

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

VueCLI3でinline-blockの隙間が無くなってしまう場合の対処法

Facebook にシェア
Pocket

HTMLでinline-blockの要素を改行で連続して並べると、横並びで間に隙間ができますよね(参考:inline-blockを指定した要素に隙間が空く理由 | WEBデザインの教科書)。

今やってるプロジェクトでは、デザイン会社にHTMLを作ってもらい、それをこちらでVue.jsにあてはめて処理を追加するということをやっているのですが、デザイン会社から提供してくれたHTMLでは隙間が空いているのに、VueCLI3でビルドした結果では隙間が空いていないという現象が発生しました。

具体的にいうと、下記のようなHTMLがあるとき、

普通にHTMLで書くと下記のようにボタンとボタンの間に隙間があきます。

ですが、VueCLI3で結果を見てみると、隙間が空かなくなってしまいます。

原因を調べてみると、VueCLI3での結果ではinputタグ同士にスペースや改行がないHTMLとなってしまっていることが分かりました。

最初、iniline-blockの隙間に頼らないスタイル指定にしてほしいとお願いしようかと思ったのですが、調べてみると設定で切り替えることで解決できることが分かりました。
webpack – Spaces are gone in HTML after upgrading to vue-cli 3 – Stack Overflow

どうやら、vue.config.jsに下記のchainWebpackの記述を追加すればいいようです。

どうやらこれは、VueCLI3が利用しているVue LoaderというVue Componentをビルドするためのプラグインの設定を書き換える記述のようです。VueCLI3が隠喩しているので今まで気にしてなかったのですが、Vue Loaderも理解してないのでこういうところでハマってしまいますね。

上記のページによると、VueCLI2まではpreserveWhitespaceというHTMLタグ間にスペースをつけるかどうかの設定がtrueだったそうなのですが、VueCLI3ではfalseとなったそうです(ちなみに、Vue Loader自体はデフォルトはtrueだそうです:オプションリファレンス · vue-loader)。

というわけで上記設定をいれることにより、無事にHTMLタグ間にスペースが入り、ボタンの間にも隙間ができました。

めでたしめでたし。

かと思いきや、別の連続したボタンの箇所で、デザイン会社のHTMLでは親divタグにすっぽり収まっている箇所が、VueCLI3の生成結果ではうまく収まらず、何がおかしいんだと必死で元のHTMLとVueCLIの生成したHTMLをChromeの開発者ツールで見比べました。HTML構造は全く同じで、適用されているスタイルも全く同じ……。

しばらく悩んで理由が分かりました。デザイン会社に作成していただいたHTMLでは、スペースも改行もされずにボタンタグが横に並んであり、自分はそれじゃ見栄えが悪いからと改行してしまっていました……。その結果、VueCLI3の生成結果では隙間が空いてしまい、うまく収まらずに改行が発生してしまっていました……。

やっぱり、iniline-blockの隙間に頼らないスタイル指定にしてほしいとお願いしたほうがよかったかな……(というより、本当なんで、改行やスペースが間にある連続したinline-blockの要素は隙間ができる仕様にしたんだ……)。

:active疑似クラスは右クリックでも適用する?しない?

Facebook にシェア
Pocket

今やってるプロジェクトでは、ボタンやら画像やらがあるウェブアプリを作っているのですが、先日お客さんから右クリックしてもコンテキストメニューがでないようにしてほしいとお願いされました。

ようは、画像を簡単に保存できないようにしてほしいとのことなのですが、そんなの簡単に解除できるのだけどと思いながら、下記のスクリプトを追加して右クリックしてもコンテキストメニューがでないように修正しました(参考:JavaScriptによる右クリックの禁止・禁止を解除する方法 – Qiita)。

簡単な変更ですが、設定したからには簡単な動作確認はしないといけません。ブラウザを開いて画像の他、適当な箇所を右クリックしてコンテキストメニューがでないかどうかChromeで確認しました。その時に、「あれ?」と思った箇所が一つ。

上記のアプリは、「+1」というボタンをクリックすると丈夫の数字をカウントアップするようにしてあるのですが、この「+1」のボタンにはactive疑似クラスを付けてクリック時にスタイルを変えるようにしています。そうすると、カウントアップは左クリックでしか行わないのに、スタイル自体は右クリックをしたときもactive疑似クラスのスタイルが適用されてしまいました。IEでもEdgeでも試したのですが、同じように右クリックでも適用されました。

今まで長いことCSSを書いてきて、もちろんactive疑似クラスも何回も使ってきたのですが、右クリックでも適用されるということを今になって初めて気づきました……。

そんな仕様だったのかと思い、試しにMDNを見ると下記のような記述が。

複数ボタンのマウスを使うシステムでは、 CSS 3 は :active 擬似クラスは第1ボタン、つまり右手用のマウスではふつう一番左のボタンにのみ適用しなければならないと定義しています。

あれ? MDNには「一番左のボタンにのみ適用しなければならないと定義」と書いてあります(いやいや、そんなはずはない。右クリックしても適用されたぞ)。

いろいろ調べてみると、stackoverflowに下記の投稿が。
css “:active” with right click, inconsistencies with browser implementation – Stack Overflow

英語は苦手なのでGoogle翻訳して読んだのですが、やっぱりChromeやIEはCSS3の仕様に則っていないそうです。Firefoxは仕様にのっとっているらしく、確かにFirefoxで右クリックしてもactive疑似クラスのスタイルは適用されませんでした。ただし、CSS2.1の仕様では、左のボタンのみとは書かれてなかったので、右クリックでも適用されるのは間違ってなかったそうです。

ちなみに、今やってるプロジェクトでは、右クリックしてもスタイルが変更してしまうのはダメだろうということで、JavaScriptでクリックした時にクラスを追加してスタイルを変更するという処理を入れることになりました……(泣)。

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()ってあまり使う機会ないと思って使ったことなかったんですけど、こういう使い方もあるなら結構いろいろ使いどころありそうです。

vue-cliでビルドした本番環境を、ルート以外で動かす

Facebook にシェア
Pocket

先日の記事、Vue.jsでmousedownとtouchstartのイベントを扱う | while(isプログラマ)で作成したプログラムなんですが、ビルドしたうえでvuejsフォルダをサーバに作ってアップして公開しようと思ったらうまく動きませんでした。

原因は単純に外部ファイルの指定が、「」とルートからの指定となっているため。開発環境はともかく、本番環境はこれだと困るということもあります。

そういう場合、プロジェクトのルートフォルダに、「vue.config.js」というファイルを作成して、下記のように設定。

これは、本番環境では/vuejs/を基点としたファイル構成にし、開発環境ではルートを基点とするファイル構成ととらえるという指定です(参考:Configuration Reference | Vue CLI)。こういうことでビルド時に外部ファイルの参照が、「」となり、うまく動かすことができました。

前回作成したプログラム:MousedownとTouchstart