LoginSignup
8
1

More than 3 years have passed since last update.

jQueryに頼らない! DOM操作を伴うブックマークレットの作り方

Last updated at Posted at 2019-06-07

概要

  • jQuery使わないよ
  • 基本的なDOM情報の取得・操作はJavaScriptのquerySelector querySelectorAllを使うよ
  • ネイティブのメソッド(querySelectorなど)を別の変数に入れて使おうとしたら怒られたよ
  • querySelectorで取得できるNodeListは配列ではないので、配列のメソッドで処理する時は配列化しておくと便利だよ

ブックマークレットとは

  1. ブックマークに追加
  2. 適当な名前をつけ、URLとして「javascript:」から始まるコードを保存。
  3. 任意のページで実行する(そのブックマークをクリックする)と、そのスクリプトが実行できる。

ES2015

自分が使えればいいので、ブラウザ対応は考えなくて良い。
思う存分最新のJS文法で書きましょう。

即時実行関数(一番外側のfunction)の内側に処理を書いていきます。

(function() {
  "use strict";
  r();
  // 実行本体
  function r() {
    // ここに色々書いていく
  }
})();

取得→配列化

配列のメソッドを使って抽出・操作したいので、任意のDOMを取得したら即配列化します。
domArrは配列なので、.map().filter().reduce() など自由に使えます。
※callメソッドを使えばNodeListのまま関数適用は可能ですが、繰り返しメソッドを適用する場合には面倒です。

// 取得
const $dom = document.querySelectorAll('.className');

// 配列化
const domArr = [].slice.call($dom);

// スプレッド演算子を使っても良い
const domArr = [...$dom];

抽出

クラスで大まかに絞った後、「要素内のタイトルが「にゃーん」の要素だけに絞りたい」なんていうことをしないといけなかったりします。
配列のfilter、findメソッドの出番です。メソッド内で、任意の要素を取得し、そのtextContentを文字列比較して true を返すようにすれば抽出できます。
そもそも要素自体が取得できないケースもあるため、その場合はfalseを返すようにします。

filter

複数の要素を抽出する場合に使います。

const $target = domArr.filter(el => {
  const $title = el.querySelector('.title');
  if(!$title) { // そもそも要素が取得できないケースもあるので falseを返すようにする
    return false;
  }
  return $title.textContent === 'にゃーん';
});

// $targetは配列なので、抽出した1つの要素を操作する場合は $target[0] でアクセスする 

find

最初に見つかった1つの要素のみで良い場合は、filterよりもfindの方が向いています。
挙動・返り値が変わるだけで、条件の書き方はfilterと同じです。
つまりリファクタリングしやすい、ということ。

const $target = domArr.find(el => {
  const $title = el.querySelector('.title');
  if(!$title) { // そもそも要素が取得できないケースもあるので falseを返すようにする
    return false;
  }
  return $title.textContent === 'にゃーん';
});

// $targetはDOM要素

合計する

今回はターゲットとなるカラムのアイテム1つ1つに含まれるポイント数を合計したかったので、
さくっとポイントの文字列を抽出して合計します。

// ポイントが含まれている要素を抽出
const $pointDom = $target.querySelectorAll('.point');

// 配列化
const pointDomArr = [...$pointDom];

// ポイント文字列を数値に変換しつつ抽出 → さらにundefinedなど、合計すると NaN になる要素を除外
// [1, 3, 5...] のような配列が生成される
const pointArr = pointDomArr.map(v => v.textContent * 1).filter(v => v);

// 合計
const points = pointArr.reduce((a, b) => a + b, 0);

セミコロンを忘れないこと

minifyして1行にするため、各処理の最後にセミコロンがないと意味が変わってエラーが生じてしまいます。省略しないこと。

minify

素晴らしいWebサービスが存在するので使わせていただきましょう。
エディタ上で出来るけど? という方はそれで構いません。
下記のサービスの場合、ブックマークレット化に必要な「javascript:」も補ってくれます。

備考

怒られました。


// TypeError: Illegal invocation
const qAll = document.querySelectorAll;

// これならOK
const qAll = function(selector){
  return document.querySelectorAll(selector);
};

作ったもの

今回はAsanaの「DONE」とタイトルの付いたリストのポイント(スクリーンショット「2」の部分)を合計するためのブックマークレットを作りました。
日頃のタスクをちょっと便利にするブクマ、気軽に作っていきましょう〜。

スクリーンショット 2019-06-07 午後3.19.44.png

8
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1