先日、自身の二作目であるchrome拡張機能『YouTube Video Tag』をリリースしました。
今回の記事では、前回の記事には載っていない新たな学びを書き記していこうと思います。
※以下の本文では、私が作った拡張機能のソースコードを引用している所があります。全てを載せると長くなる部分は省いていますが、詳細を見たい方はChrome extension source viewerなどのツールを使うか、拡張機能をインストールしてローカルストレージのファイルを見るなどして下さい(GitHubのリポジトリは公開してないので)。
オブジェクトのディープコピーを作る
オブジェクトのディープコピーを作るには、文字列に変換(JSON.stringify
)してから元に戻します(JSON.parse
)。
let goods = {
"name": "pen",
"price": 150
};
let goods_copy = JSON.parse( JSON.stringify(goods) );
goods["price"] = 200;
console.log(goods_copy["price"]); // > 150
コールバック関数内からインスタンスを参照する
メソッド内でイベントリスナーを定義する際、コールバック関数内でthis
を使うと、インスタンスではなくdocument
を指すことになり、メンバーが見つかりません(undefined
になる)。
class Hoge {
name = "hoge";
piyo(){
$('#fuga-btn').on('click', function(){
console.log (this.name); // > undefined
});
}
}
コールバック関数をアロー関数で定義すれば、その中で使われたthis
は関数が定義された場所におけるthis
――つまりインスタンスを指します。
class Hoge {
name = "hoge";
piyo(){
$('#fuga-btn').on('click', () => {
console.log (this.name); // > hoge
});
}
}
onメソッドの処理は重複する
jQueryのon
メソッドを使ったイベントリスナーの追加は、重複します。
重複させたくない場合は、on
メソッドの前にoff
メソッドを呼んで、既に追加されているイベントリスナーを削除する必要があります(追加されていなくてもエラーが出ることはありません。)。
例えば、私が作った拡張機能には以下のような関数があります。
「タグ要素をページに追加し、それぞれについている『削除』ボタンにイベントリスナーを追加する」という処理を行います。
addVideoTagsElem(tags){
let tagGroupElem = $("#yvt-tag-group");
for (let tag of tags) {
let tagElem = /* 略 */;
tagGroupElem.append(tagElem);
}
$('.yvt-btn-delete').off('click');
$('.yvt-btn-delete').on('click', e => {
// 略
});
}
この関数は、タグの追加が行われる度に呼び出されます。
on
メソッドを呼び出す対象要素をクラスで指定しているので、タグの追加が複数回行われると、前に追加されていたタグ要素にもイベントリスナーが追加され、重複してしまいます。
そこで、on
メソッドを呼ぶ直前にoff
メソッドを呼び、既存のタグ要素に追加されているイベントリスナーを削除しています。
タグ入力用ライブラリについて
私が作った拡張機能では、タグを入力する場所が二箇所あり、それぞれでタグ入力用ライブラリを使い分けています。
最初はtagifyだけを使う予定でしたが、tagifyの不具合が原因で片方では使えなくなったので、別のライブラリも使うことにしました。
以下では、それぞれのライブラリを使ってみた感想などを述べていこうと思います。
tagify
tagifyはUIがキレイで、オプションなども充実していて、拡張性も高いライブラリです。
日本語の入力補完にも対応していて、delimiter
の値を変更することで、全角スペース区切りにも対応します。
しかし、chrome拡張機能で使うとなったとき、いくつか問題が発生しました。
ダークテーマのページにあるテキストフォームにtagifyを適用すると、input
フォームの背景が黒くなり、入力した文字が見えなくなる。
この問題は、tagifyによって追加されたtags
タグの背景色を明示的に変更することで解決しました。
delimiter
に全角スペースを指定していても、removeAllTags
メソッドでテキストフォーム内の全角スペースを削除できない。
確かに全角スペースを入力すると区切り文字として認識はされるのですが、半角スペースとは違い、全角スペースはテキストフォーム内にそのまま残ってしまいます。
この問題は、tagify.DOM.input.textContent = "";
を実行し、テキストフォーム内に残った文字列を削除することで解決しました。
ページにショートカットキーが設定されている場合、tagifyを適用したテキストフォーム内でのキー入力が、ショートカットキーの機能を呼び出してしまう。
具体例を挙げると、YouTube動画ページ内にtagifyを適用したテキストフォームがある場合、その中でk
、j
、l
、m
などのキーを押すと、動画の再生が止まったり、シークバーが動いたり、ミュートになったりしてしまうということです。
keydown
イベントが発生したらstopPropagation
を実行するなど、色々試してみましたが、完全な解決には至らなかったので、私は「既存のページに追加したテキストフォームにtagifyを適用する」という使い方を断念しました。
ポップアップページでは問題なく使えました。
tagsinput
tagifyの代わりに動画ページで使うことにしたのが、このライブラリです。
特にこれにこだわる理由もないのですが、日本語の入力補完ができ、ショートカットキーが暴発することもなかったので、採用しました。
難点は、tagifyと違って全角スペースを区切り文字にできないことと、input
要素のid
が変更されるので、入力された値を取得するのが少しだけ面倒なことです。