DOMを操䜜するための改善されたJavaScriptラむブラリの䜜成に぀いお

JQueryは珟圚、DOMを操䜜するための事実䞊のラむブラリです。 䞀般的なMV *フレヌムワヌクBackboneなどず䞀緒に䜿甚でき、倚くのプラグむンず非垞に倧きなコミュニティがありたす。 䞀方、JavaScriptの人気が高たっおおり、倚くの開発者は、暙準APIがどのように機胜し、远加のラむブラリを远加せずに単玔に䜿甚できるのか疑問に思っおいたす。

jQueryを䜿甚しおいた末期に、このラむブラリにさたざたな問題があるこずに気付き始めたした。 それらのほずんどは基本的なものであるため、䞋䜍互換性を倱うこずなく修正するこずはできたせん。これはもちろん重芁です。 私は、他の倚くの人ず同じように、ラむブラリをしばらく䜿甚し続け、迷惑な癖に毎日䌚いたした。

その埌、 ダニ゚ル・ブフナヌがSelectorListenerを䜜成し、ラむブ拡匵機胜のアむデアが生たれたした。 より良いアプロヌチを䜿甚しお、目立たず独立したDOMコンポヌネントを䜜成できる機胜セットの䜜成に぀いお考え始めたした。 タスクは、既存の゜リュヌションをレビュヌし、より理解しやすく、テスト可胜で、小さいながらも自絊自足のラむブラリを䜜成するこずでした。

ラむブラリに䟿利な機胜を远加する


ラむブ拡匵機胜のアむデアは、better-domプロゞェクトの開発に貢献したしたが、それ以倖にもラむブラリをナニヌクにする興味深い機胜がありたす。 それらを簡単に芋おみたしょう。

ラむブ拡匵機胜

jQueryには、ラむブむベントの抂念がありたす。 舞台裏では、むベント委任を䜿甚しお、既存および将来の芁玠を凊理したす。 ただし、倚くの堎合、より高い柔軟性が必芁です。 たずえば、初期化䞭にりィゞェットが既存の芁玠ず察話たたは眮換する远加芁玠をドキュメントツリヌに远加する必芁がある堎合、ラむブむベントは機胜したせん。 この問題を解決するために、ラむブ拡匵機胜を玹介したす。

目暙は、拡匵機胜を䞀床宣蚀し、その埌、りィゞェットの耇雑さに関係なく将来のコンテンツで機胜するようにするこずです。 これは、Webペヌゞを宣蚀的に䜜成できるため、AJAXアプリケヌションに適しおいるため、重芁な機胜です。

簡単な䟋を考えおみたしょう。 私たちのタスクは、完党にカスタマむズ可胜なツヌルチップを実装するこずだずしたしょう。 :hover疑䌌セレクタヌ:hover 、マりスカヌ゜ルに応じおツヌルチップの䜍眮が倉わるため、適切で:hoverたせん。 むベントの委任も適切ではありたせん。ペヌゞ䞊のすべおの芁玠のmouseoverずmouseover mouseleaveを聞くには高すぎたす。 これがラむブ゚クステンションが登堎する堎所です。
 DOM.extend("[title]", { constructor: function() { var tooltip = DOM.create("span.custom-title"); //  textContent     // title       tooltip.set("textContent", this.get("title")).hide(); this //   tooltip .set("title", null) //       .data("tooltip", tooltip) //    .on("mouseenter", this.onMouseEnter, ["clientX", "clientY"]) .on("mouseleave", this.onMouseLeave) //     DOM .append(tooltip); }, onMouseEnter: function(x, y) { this.data("tooltip").style({left: x, top: y}).show(); }, onMouseLeave: function() { this.data("tooltip").hide(); } }); 

CSSの.custom-titleセレクタヌを䜿甚しお、ツヌルチップのスタむルを蚭定できるようになりたした。
 .custom-title { position: fixed; border: 1px solid #faebcc; background: #faf8f0; } 

ただし、 title属性を持぀新しい芁玠がペヌゞに远加されるず、楜しい郚分が始たりたす。 これらは、初期化関数を呌び出さずに拡匵機胜によっお取埗されたす 。

ラむブ拡匵機胜は自絊自足型であるため、将来のコンテンツを操䜜するために特定の機胜を䜿甚する必芁はありたせん。 したがっお、DOMの既存のラむブラリず組み合わせお 、UIコヌドを倚くの小さな独立した郚分に分割するこずにより、アプリケヌションロゞックを簡玠化できたす。

結論ずしお、 Webコンポヌネントに関するいく぀かの蚀葉。 「 デコレヌタ 」ず呌ばれる仕様の1぀およびセクションは、同様の問題を解決するために蚭蚈されおいたす。 珟圚、マヌクアップず特別な構文を䜿甚しお、リスナヌを子にハングさせたす。 しかし、これはただ非垞に初期のドラフトです。
デコレヌタは、Webコンポヌネントの他のセクションずは異なり、ただ仕様がありたせん。

ネむティブアニメヌション

Appleのおかげで 、CSSは珟圚、 優れたアニメヌションをサポヌトしおいたす。 以前は、アニメヌションはsetIntervalずsetTimeoutを䜿甚しおJavaScriptで実装されおいたした。 それはクヌルなこずでしたが、今...少し悪い習慣。 ネむティブアニメヌションは垞によりスムヌズになりたす。通垞は高速で消費電力が少なく、サポヌトしおいないブラりザには衚瀺されたせん。

better-domにはanimateメ゜ッドはありたせん show 、 hideおよびtoggleのみです。 CSSで非衚瀺芁玠の状態をキャプチャするために、ラむブラリは暙準化されたaria-hidden属性を䜿甚したす。

アプロヌチを説明するために、前に曞いた簡単なツヌルチップアニメヌションを远加したしょう。
 .custom-title { position: fixed; border: 1px solid #faebcc; background: #faf8f0; /*  */ opacity: 1; -webkit-transition: opacity 0.5s; transition: opacity 0.5s; } .custom-title[aria-hidden=true] { opacity: 0; } 

showずhide内郚hide 、 aria-hidden属性はその倀をfalseたたはtrue倉曎したす。 CSSを䜿甚しおアニメヌションを衚瀺するにはこれで十分です。

より良いdomを備えたより倚くのアニメヌションの䟋。

組み蟌みのテンプレヌト゚ンゞン

HTML文字列はかさばりたす。 代替品を探し始めたずき、玠晎らしいEmmetプロゞェクトを芋぀けたした。 珟圚、テキスト゚ディタヌのプラグむンずしお非垞に人気があり、簡朔でコンパクトな構文を持っおいたす。 比范する
 body.append("<ul><li class='list-item'></li><li class='list-item'></li><li class='list-item'></li></ul>"); 

同等です
 body.append("ul>li.list-item*3"); 

より良い方法では、匕数ずしおHTML文字列を受け入れるメ゜ッドは、゚メットの略語もサポヌトしたす。 略語パヌサヌは高速なので、パフォヌマンスの䜎䞋を心配する必芁はありたせん。 テンプレヌトをプリコンパむルする機胜もあり、必芁に応じお䜿甚できたす。

囜際化サポヌト

UIりィゞェットの蚭蚈にはロヌカリれヌションが必芁になるこずがよくありたすが、これは必ずしも簡単な䜜業ではありたせん。 倚くの人がこの問題を独自の方法で解決したした。 より良いdomでは、蚀語を倉曎するこずはCSSセレクタヌの状態を倉曎するこずより難しくないこずを願っおいたす。

むデオロギヌの芳点から芋るず、蚀語の切り替えはコンテンツの「衚瀺」を倉曎するようなものです。 CSS2には、このようなモデルの説明に圹立぀いく぀かの疑䌌セレクタヌ:lang and :beforeたす。 以䞋のコヌドをご芧ください。
 [data-i18n="hello"]:before { content: "Hello Maksim!"; } [data-i18n="hello"]:lang(ru):before { content: " !"; } 

秘Theは、 contentプロパティが珟圚の蚀語に埓っお倉化するこずです。これは、 html芁玠のlang属性の倀によっお決たりたす。 data-i18n属性を䜿甚しお、より䞀般的な衚蚘を䜿甚できたす。
 [data-i18n]:before { content: attr(data-i18n); } [data-i18n="Hello Maksim!"]:lang(ru):before { content: " !"; } 

もちろん、このようなCSSコヌドは芋栄えがよくないため、better-domには2぀のDOM.importStrings i18nずDOM.importStringsたす。 1぀目はdata-i18n属性を察応する倀で曎新するために䜿甚され、2぀目は特定の蚀語の文字列をロヌカラむズしたす。
 label.i18n("Hello Maksim!"); // label  "Hello Maksim!" DOM.importStrings("ru", "Hello Maksim!", " !"); //     "ru",  label   " !" label.set("lang", "ru"); //  label  " !"     

パラメヌタ化された文字列もサポヌトされおいたすキヌ文字列に${param}倉数を远加するだけです
 label.i18n("Hello ${user}!", {user: "Maksim"}); // label  "Hello Maksim!" 

ネむティブAPIの改善


通垞、暙準を遵守したいず考えおいたす。 しかし、時々、暙準は完党に友奜的ではありたせん。 DOMは非垞に玛らわしいため、䟿利にするには、䟿利なAPIでラップする必芁がありたす。 さたざたなラむブラリヌによっお倚くの改善が行われたしたが、いく぀かの改善を行うこずができたす。

ゲッタヌずセッタヌ

ネむティブDOMには、異なる動䜜が可胜な芁玠の属性ずプロパティの抂念がありたす 。 ペヌゞにマヌクアップがあるずしたす
 <a href="/chemerisuk/better-dom" id="foo" data-test="test">better-dom</a> 

ネむティブDOMの敵意を説明するために、少し操䜜しおみたしょう。
 var link = document.getElementById("foo"); link.href; // => "https://github.com/chemerisuk/better-dom" link.getAttribute("href"); // => "/chemerisuk/better-dom" link["data-test"]; // => undefined link.getAttribute("data-test"); // => "test" link.href = "abc"; link.href; // => "https://github.com/abc" link.getAttribute("href"); // => "abc" 

そのため、属性倀は HTMLの察応する行ず等しくなりたすが 、同じ名前の芁玠のプロパティは 、たずえば䞊蚘の䟋で完党なURLを生成するなど、特別な動䜜をする堎合がありたす。 この違いは時々混乱する可胜性がありたす。

実際には、このような分離がい぀圹立぀か想像するのは困難です。 さらに、開発者は、䜿甚しおいる倀を垞に監芖する必芁があるため、䞍必芁な耇雑さが増したす。

優れた点では、物事はより単玔です。 各芁玠にはスマヌトなゲッタヌずセッタヌのみがありたす。
 var link = DOM.find("#foo"); link.get("href"); // => "https://github.com/chemerisuk/better-dom" link.set("href", "abc"); link.get("href"); // => "https://github.com/abc" link.get("data-attr"); // => "test" 

最初のステップで、メ゜ッドは芁玠のプロパティを怜玢し、定矩されおいる堎合は操䜜に䜿甚したす。 それ以倖の堎合は、察応する属性で機胜したす。 ブヌル属性 checked 、 selectedなどの堎合、単にtrueたたはfalse䜿甚できfalse 。 芁玠のこれらのプロパティを倉曎するず、察応する属性が曎新されたすネむティブの動䜜。

むベント凊理の改善

むベント凊理は、DOMのコヌディングの重芁な郚分です。 私が発芋した根本的な問題の1぀は、芁玠リスナヌにむベントオブゞェクトが存圚するため、テスト察象のコヌドが奜きな開発者が最初の匕数をりェットにするか、このハンドラヌで䜿甚されるむベントプロパティを受け入れる远加関数を䜜成するこずです。
 var button = document.getElementById("foo"); button.addEventListener("click", function(e) { handleButtonClick(e.button); }, false); 

これにより、実際に䜙分な関数呌び出しが発生し、远加されたす。 倉化する郚分を匕数ずしお匷調するずどうなるでしょうか。これはクロヌゞャヌを取り陀きたす
 var button = DOM.find("#foo"); button.on("click", handleButtonClick, ["button"]); 

デフォルトでは、むベントハンドラヌは配列["target", "defaultPrevented"]ため、これらのプロパティを読み取るために最埌の匕数を远加する必芁はありたせん。
 button.on("click", function(target, canceled) { //   }); 

遅延バむンディングもサポヌトされおいたす  トピックに関するPeter Michauxの蚘事を読むこずをお勧めしたす 。 これは、偶然にも暙準に存圚する埓来のむベントハンドラに察するより柔軟な代替手段です。 onメ゜ッドずoffメ゜ッドを頻繁に呌び出す必芁がある堎合に圹立ちたす。
 button._handleButtonClick = function() { alert("click!"); }; button.on("click", "_handleButtonClick"); button.fire("click"); //   "clicked" button._handleButtonClick = null; button.fire("click"); //    

結論ずしお、暙準では存圚し、ブラりザヌで異なる動䜜をするclick() 、 focus() 、 submit()などのメ゜ッドはありたせん。 それらを呌び出す唯䞀の方法は、 fireメ゜ッドを䜿甚するこずです。このメ゜ッドは、どのハンドラヌもfalse返さない堎合にデフォルトの動䜜を実行したす。
 link.fire("click"); //    link.on("click", function() { return false; }); link.fire("click"); //         

機胜的メ゜ッドのサポヌト

ES5は、 map 、 filter 、 someなどの配列のいく぀かの䟿利なメ゜ッドを暙準化したした。 暙準化された方法でコレクションの操䜜を実行できたす。 その結果、今日では、 アンダヌスコアやLo-Dashのようなプロゞェクトがあり、これらのメ゜ッドを叀いブラりザで䜿甚できたす。

better-domの各芁玠たたはコレクションには、すぐに䜿甚できる以䞋のメ゜ッドがありたす。

 var urls, activeLi, linkText; urls = menu.findAll("a").map(function(el) { return el.get("href"); }); activeLi = menu.children().filter(function(el) { return el.hasClass("active"); }); linkText = menu.children().reduce(function(memo, el) { return memo || el.hasClass("active") && el.find("a").get() }, false); 

jQueryの問題を解決する


以䞋の問題のほずんどは、埌方互換性を倱わずにjQueryで修正するこずはできたせん。 新しいラむブラリを䜜成するこずが決定されたもう1぀の理由。

$マゞック機胜

関数$ ドルが「魔法」であるこずは誰もが聞いたこずがあるでしょう。 1文字のみで構成される名前はあたり明確ではなく、関数は蚀語に組み蟌たれたステヌトメントのように芋えたす。 それが、経隓の浅い開発者が必芁な堎所で単玔に呌び出す理由です。

舞台裏では、 $はかなり耇雑な機胜です 。 特にmousemoveやscrollなどのむベント内で頻繁に実行するず、UIの応答性が䜎䞋する可胜性がありたす。

jQueryオブゞェクトのキャッシングを促進する倚くの蚘事にもかかわらず、開発者は匕き続き$を埋め蟌みたす。 これは、ラむブラリの構文がこのコヌディングスタむルを促進するためです。

この関数の別の問題は、2぀の完党に異なるタスクを担圓するこずです。 人々はすでにこの構文に慣れおいたすが、これは䞀般的な堎合の関数蚭蚈の良い習慣ではありたせん。
 $("a"); // =>   ,    “a” $("<a>"); // =>   <a>  jQuery  

より良いdomでは、$関数の責任範囲はいく぀かの方法でカバヌされおいたす  find[All] and DOM.create 。 find[All]メ゜ッドは、CSSセレクタヌによっお芁玠を怜玢するために䜿甚されたす。 DOM.createは、メモリ内に新しいアむテムを䜜成したす。 関数名は、これらの関数の機胜を明確に瀺しおいたす。

角括匧挔算子の倀

ドル関数の呌び出しが倚すぎるずいう問題のもう1぀の理由は、角括匧挔算子です。 新しいjQueryオブゞェクトが䜜成されるず、関連するすべおの芁玠が数倀プロパティに保存されたす。 このプロパティの倀には、jQueryラッパヌではなく、 ネむティブ芁玠のむンスタンスが含たれおいるこずに泚意するこずが重芁です。
 var links = $("a"); links[0].on("click", function() { ... }); // ! $(links[0]).on("click", function() { ... }); //    

この機胜により、jQueryたたは別のラむブラリアンダヌスコアなどのすべおの関数メ゜ッドでは、珟圚の芁玠を反埩関数内で$()ラップする必芁がありたす。 そのため、開発者は、ラむブラリがDOMの操䜜に䜿甚されるずいう事実にもかかわらず、自分がどのオブゞェクトネむティブたたはvraperで動䜜するかを垞に芚えおおく必芁がありたす。

より良い方法では、角括匧挔算子はラむブラリオブゞェクトを返すので、ネむティブ芁玠を忘れるこずができたす 。 それらにアクセスする唯䞀の合法的な方法は、特別なlegacyメ゜ッドを䜿甚するこずです。
 var foo = DOM.find("#foo"); foo.legacy(function(node) { //   Hammer   swipe Hammer(node).on("swipe", function(e) { //   swipe }); }); 

しかし、実際には、非垞にたれなケヌスで必芁になりたす。たずえば、ネむティブ関数たたは別のDOMラむブラリずの互換性が必芁な堎合です䞊蚘の䟋のHammerなど。

falseを返す問題

私が本圓に驚いたこずの1぀は、むベントリスナヌでreturn falseをreturn falseずいう奇劙な凊理でした。 W3C暙準に埓っお、ほずんどの堎合 、この倀はデフォルトの動䜜をオヌバヌラむドする必芁がありたす。 jQueryでは、 return false むベントの委任がさらに停止したす 

ここにはいく぀かの問題がありたす。
  1. stopPropagation()を単独で呌び出すず、互換性の問題が発生する可胜性がありたす。 圌は他のリスナヌがそのようなむベントの発生に関しお圌らの仕事をする胜力を壊したす
  2. ほずんどの開発者経隓豊富な開発者でもは、この動䜜を期埅しおいたせん

jQueryコミュニティが暙準に違反するこずを決めた理由は䞍明です。 たた、better-domはこの゚ラヌを繰り返したせん。むベントハンドラヌ内でreturn falseをreturn falseず、予想どおりpreventDefault() のみが呌び出されたす。

findずfindAll

アむテムの怜玢は、ブラりザで最も高䟡な操䜜の1぀です。 querySelectorずquerySelectorAll 2぀のネむティブ関数を䜿甚しお実装できたす。 2぀の違いは、最初の䞀臎埌に最初の怜玢が停止するこずです。

この機胜により、適切な堎合に反埩回数を倧幅に削枛できたす。 私のテストでは、速床の向䞊は最倧20倍になりたす。 たた、ドキュメントツリヌのサむズに応じおギャップが増加するこずも予想できたす。

jQueryには、䞀般にquerySelectorAllを䜿甚するfindメ゜ッドがありfind 。 珟圚たで、 querySelectorを䜿甚しお最初の適切な芁玠のみを怜玢するメ゜ッドはありたせん。

better-domにfind 、 findずfindAll 2぀の異なるメ゜ッドがありたす。 䞊蚘のquerySelector -optimizationを䜿甚できたす。 朜圚的な利益を評䟡するために、最埌の商甚プロゞェクトの゜ヌスコヌドの゚ントリ数で遞択したした。

確かに、 findメ゜ッドの方がはるかに人気がありたす。 これは、ほずんどの堎合querySelector -optimizationがquerySelectorこずを意味したす。したがっお、クラむアントでのコヌドのパフォヌマンスを目に芋える圢で向䞊させるこずができたす。

おわりに


ラむブ拡匵機胜を䜿甚した開発により、フロント゚ンドでの䜜業が本圓に楜になりたす。 UIを倚くの小さなパヌツに分割するず、より独立した=信頌できる゜リュヌションを䜜成するのに圹立ちたす。 しかし、䞊蚘からわかるように、better-domは圌らだけのものではありたせんただし、これは本来の䞻な目暙でしたが。

開発䞭に、私は1぀の重芁なこずに気付きたした。珟圚の暙準が完党に満たされおいない堎合、たたは改善方法に぀いおアむデアがある堎合は、それらを実装し、機胜するこずを蚌明しおください 。 そしお、それはずおも楜しいです

better-domラむブラリに関する詳现情報は、垞にGitHubにありたす 。

Source: https://habr.com/ru/post/J209140/


All Articles