[Javascript] selector値からエレメントを作成する処理を自動化するライブラリ「setSelector」

2019年11月4日

Javascript テクノロジー プログラミング

プログラミングが面白いか面白くないかで、ITの好き嫌いが分かれる人をよく見かけるけど、断然好きになった方が得であるといい切れるのだが、どうやら、プログラムを覚えたいと考えている人で、論理思考でない人は、どうあがいてもプログラミング言語を習得できないという事実を目の当たりにしてしまいました。 やる気だけではどうしようも無く、好き嫌いはどうコーチングしても、本人次第なので、なんとか自分でモチベーションをアップしてもらいたいですね。 そんな日々プログラムを趣味として仕事でやっていて楽しんでいる下駄です。 最近は、ほぼjavascriptを使うことが多く、HTML5の仕様と格闘することがほとんどです。 そんなjavascriptのquerySelectorは、それまでのgetElements系のエレメント取得を考えると、遥かに便利で使いやすく、管理しやすい関数で、日々、仕事中にヘビーローテーションで使用していますね。

selectorは取得するだけで、設置することは苦手らしい

querySelectorは、任意の要素(エレメント)をDOM構造内から検索する機能ですが、システムを管理する際において、selector値を元に、エレメントを作成して設置する事で、色々と助かることがあるという風に考えてみました。 例えば、何かライブラリを作る時に、DOM構造のインターフェイスが任意設置できるような場合、selector値を元にエレメントが存在しない場合は自動で作成できるといいという場面って、僕の場合、結構あります。 今回のケースで言えば、動画プレイヤーを作っていた時に、再生ボタンや停止ボタン、音量ボタン、タイムスライダーなど・・・ お決まりの要素は、動画プレイヤーライブラリ内で用意するのですが、色々なサイトに適用できるような汎用性をもたせたくて、構造体をoption値によってselectorの値まで変更できるようにしようと考えた時に、イベント設置するボタンのselector情報と別に、エレメント作成用の情報を持たなければいけません。 これってほぼ同じ内容になるのに、別々に管理するのって馬鹿らしくないですか? しかも、selector値って、"div.hoge"というように書くけど、属性値やid値など書き方も様々で、createElementでsetAttributeする際にいちいち分解するのって、結構な手間だし、classNameなどルール化を厳密に行わないといけないことから汎用性レベルが低くなってしまいます。 ある程度のルールは持たせてもいいのですが、もう少し簡易にselector情報を分解できて、その情報を元に、エレメントを自動作成できると便利だという風に思いませんか?

selector情報を取得してみるスニペット

そこで今回情報取得する関数を作ってみました。 以下お試しください。 var LIB = function(){}; // selectorから各種情報を取得 LIB.prototype.selectorInfo = function(selector){ selector = selector.replace(/>/g," "); selector = selector.replace(/\s+/g," "); selectors = selector.split(" "); var return_array = []; for(var i=0; i<selectors.length; i++){ selectors[i].match(/^(.*?)([\.\#\:])(.*?)(\[(.+?)=['"](.+?)['"]\])*?$/); var tag = ((RegExp.$1) ? RegExp.$1 : "span").toLowerCase(); var type = (function(str){ switch(str){ case ".":return "class"; case "#":return "id"; case ":": default:return ""; } })(RegExp.$2); var attrs = []; var attr = ((RegExp.$3) ? RegExp.$3 : "").toLowerCase(); if(attr && type){ attrs.push({ key : type, val : attr }); } var attr2 = (RegExp.$5 && RegExp.$6) ? {key:RegExp.$5 , val:RegExp.$6} : null; if(attr2){ attrs.push(attr2); } return_array.push({ input : selectors[i], tag : tag, attrs : attrs }); } return return_array; }; new LIB().selectorInfo("div.test[data-value='aaa']"); > [ > { > "input": "div.test[data-value='aaa']", > "tag": "div", > "attrs": [ > { > "key": "class", > "val": "test" > }, > { > "key": "data-value", > "val": "aaa" > } > ] > } > ] どうですか?意味わかります?ついてきています? selector値を送ってあげると、タグと属性値を分解して取得することができます。

自動エレメント作成する

そして、上記に加えて、下記の関数を同じインスタンスに加えてみてください。 // selectorからエレメントを追加作成する(改装対応) LIB.prototype.addSelector = function(parent , selector){ if(!selector){return false} // タグの取得 var selectorInfo = this.selectorInfo(selector); if(!selectorInfo || !selectorInfo.length){return false} // 階層構造でエレメントを作成 for(var i=0; i<selectorInfo.length; i++){ var check = parent.querySelector(selectorInfo[i].input); if(check){ parent = check; continue; } // タグの作成 var tag = document.createElement(selectorInfo[i].tag); // 属性の登録 if(selectorInfo[i].attrs){ for(var j=0; j<selectorInfo[i].attrs.length; j++){ if(!selectorInfo[i].attrs[j].key || !selectorInfo[i].attrs[j].val){continue} tag.setAttribute(selectorInfo[i].attrs[j].key , selectorInfo[i].attrs[j].val); } } parent.appendChild(tag); parent = tag; } return true; } この関数を下記のように実行することで、要素が自動で追加されます。 //sample-1 : new LIB().addSelector(document.body."div.test[data-value='aaa']"); > <div class="test" data-value="aaa"></div> //sample-2 : new LIB().addSelector(document.body,"h1.title div.test[data-value='aaa']"); > <h1 class="title"> > <div class="test" data-value="aaa"></div> > </h1> pararent値には、エレメントを作成する親要素になるエレメントを送ってあげてください。 ※この値が無いと自動作成することはできません。 階層のselector値であれば、その階層構造を自動作成するようにしていますが、途中階層ですでに作成している値がある場合であれば、そのエレメントをきちんと適用するようにもしています。 ※以下のような感じです。 // 同じ要素が含まれる場合 new LIB().addSelector(document.body,"h1.title div.test[data-value='aaa']"); new LIB().addSelector(document.body,"h1.title div.test[data-value='bbb']"); > <h1 class="title"> > <div class="test" data-value="aaa"></div> > <div class="test" data-value="bbb"></div> > </h1> エレメント構造を管理してあげるだけで、その値をエレメント検索にも使えるので、非常に無駄がないデータ管理ができるという事です。 このスニペットを使いこなせるあなた・・・結構レベル高いんじゃないですか?

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。