言語のデフォルトに無い機能を作るのが大好きな、ユゲタです。
個人的にユゲタは、Javascript埋め込み型SaaSアプリケーションの開発を得意とするというか、これまで、たくさんの製品を作って、
会社で販売したり、人にレクチャーしたりしてきましたが、Javascriptタグを貼り付けるタイプのソフトウェアの場合、
比較的、使うことが多かったと言うか、これまでは、力技でやっていたのを、今回かなり汎用的に使えるプログラムを作ったので、
紹介しておきます。
対象エレメントのSelectorを作り出す機能
WEBページ(HTML)内で、特定の要素(エレメント)を選択する時に、querySelectorで、かなり便利に対象要素の選択ができますが、
逆にその対象要素のselector値を取得したいと思ったら、次のような方法を通常は行うはずです。
・ユニーク(唯一の)要素であれば、対象要素にID値を付ける。
・複数ある要素であれば、class値を付けて、ページ内での順番を管理する。
・タグ属性などで管理する。
・ページ内のタグや各種要素の順番で管理する。
どれも、HTML作成時であれば、対応可能ですが、すでに出来上がっている場合に、ID値が付けられなかったり、classを増やせなかったりする事も多々あります。
でも、chromeブラウザのデバッグコンソール内で、HTMLタグの部分を右クリックして、「Copy / Copy Selector」を選択すると、
body > div.contents > div > form > div > div.column-1 > div:nth-child(4)
こんな感じで、ページ内で、その対象の要素が選択できるSelectorが取得できます。
単純なselectorもあれば、属性値が一切ついていないタグの場合は、上記のように、bodyタグからの階層をたどるような形になってしまいますが、
確実にそのselectorがユニークで要素を選択できるものになっています。
今回は、要するにコレをjavascriptで出力できるようにしたいんですね。
ソースコード
// エレメントからセレクタ情報を取得(ユニーク値対応)
function getElement2Selector(elm){
if(!elm){return;}
let selectors = [];
for(var cur=elm; cur; cur=cur.parentElement){
if(!cur){break;}
let data = getElementName_data(cur);
selectors.unshift(data);
if(cur.id){break;}
if(cur.tagName.toLowerCase() === "body"){break;}
}
selectors = getElement2Selector_check_duplicate(selectors);
return getElement2Selector_format(selectors);
};
// 表示用エレメント名を取得 (タグ + #ID + .class)
function getElementName_data(elm){
if(!elm){return "";}
let tag = elm.tagName.toLowerCase();
let data = {
elm : elm,
tag : tag,
name : tag
};
if(elm.id){
// IDで使えない文字判定
if(elm.id.match(/[^0-9a-zA-Z_\-]/g)){}
else{
data.id = elm.id;
data.name = "#"+elm.id;
}
}
if(elm.className){
for(let cls of elm.classList){
// class名で使えない文字判定
if(cls.match(/[^0-9a-zA-Z_\-]/g)){continue;}
data.className = cls;
data.name += "."+ cls;
}
}
return data;
};
// 任意エレメントのselectorを取得(nth-of-childを付与する)
function getElement2Selector_check_duplicate(selectors){
for(let i=0; i<selectors.length; i++){
let selector = getElement2Selector_format(selectors.slice(0,(i+1)));
let elms = document.querySelectorAll(selector);
if(elms.length >= 2){
let selector_lasttag = getElement2Selector_format_lastTag(selectors.slice(0,(i+1)));
let elms_tag = document.querySelectorAll(selector_lasttag);
for(let j=0; j<elms_tag.length; j++){
if(elms_tag[j] === selectors[i].elm){
selectors[i].name = selectors[i].tag + ":nth-of-type("+ (j+1) +")";
break;
}
}
}
}
return selectors;
};
// selectorデータからselector値を取得
function getElement2Selector_format(selectors){
let names = [];
for(let selector of selectors){
names.push(selector.name);
}
return names.join(">");
};
// selectorデータからselector値を取得
function getElement2Selector_format_lastTag(selectors){
let names = [];
for(let i=0; i<selectors.length; i++){
let selector = selectors[i];
if(i < selectors.length - 1){
names.push(selector.name);
}
else{
names.push(selector.tag);
}
}
return names.join(">");
};
実行すると
getElement2Selector(element)
Responce :
body > div.contents > div > form > div > div.column-1 > div.row.tag-control-area > ul > li:nth-child(7) > button
どういう時に使うの?
実際に、elementを指定するので、そのelementをどうやって取得しているんだ?というようなニワトリとタマゴ問題のような禅問答が始まるかもしれませんが、
これはl,clickイベントやmousedownイベントなどで、どのelementをクリック(タッチ)したのかを判別するときに、それを視覚的に表示するために、selectorという形で表現してみました。
ボクのよく作る、webサイトの改善ツールなどでは、この機能が何故デフォルトでないのかが不明なぐらい必要な機能なので、利用頻度はかなり高いですね。
まあ、通常のwebサイトでは使わないほうが多いんですけどね、実際・・・
でも、限りなくchromeブラウザのcopy selector機能と同じになるように、調整してあるので、もし、誤差が生まれるような事があれば、
こっそりご連絡ください。
0 件のコメント:
コメントを投稿