実用的なJS:innerHTMLの問題

注:以下はJulien Lecomte 記事「The Problem With innerHTML」の翻訳です。著者は、現代のブラウザーでinnerHTMLメソッドを使用する際の問題を検討し、それを回避するためのヒントを提供しています。 イタリック体での私のコメント



innerHTML



プロパティは、特定のタグのHTMLコンテンツを置き換えることができる完全に基本的なものであるため、そのシンプルさと便利さからWeb開発者の間で非常に人気があります。 DOM Level 2 API( removeChild



createElement



appendChild



)を使用することもできappendChild



が、 innerHTML



を使用すると、DOMツリーを変更するためのはるかに簡単で効率的な方法です。 ただし、 innerHTML



を使用する場合は、回避する必要があるいくつかの問題があります。







言及する価値があるいくつかのマイナーな欠陥があります:











個人的には、 innerHTML



プロパティの使用に関連するセキュリティおよびメモリ使用量の問題を心配しています。 しかし、説明されている問題は決して新しいものではなく、すでにいくつかの明るい頭脳がそれに注意を払い、それを解決する方法を提案しました。



Douglas CrockfordイベントハンドラーをHTML要素に追加することで発生するいくつかの循環参照を削除するpurge



関数
を作成し、 ガベージコレクターが関連するすべてのメモリ完全に解放できるようにしました。



HTML文字列から<script>



削除することは、一見したほど簡単ではありません。 この目的に使用される正規表現は非常に複雑でなければなりませんが、考えられるすべてのケースをカバーするかどうかは私にはわかりません。 以下は、仕事で個人的に使用するオプションです。



  / <script [^>] *> [\ S \ s] *?<\ / script [^>] *> / ig 




これらの両方の手法を1つのsetInnerHTML



関数に結合してみましょう( UPD:コメントを追加したすべての人に感謝します:あなたが指摘したすべてのエラー/ホールを修正しました。また、 setInnerHTML



関数をYAHOO.util.Dom



に含めることにしYAHOO.util.Dom







 YAHOO.util.Dom.setInnerHTML = function(el、html){
	 el = YAHOO.util.Dom.get(el);
	 if(!el || typeof html!== 'string'){
		 nullを返します。
	 }

	 //循環参照を削除します
	 (関数(o){

		 var a = o.attributes、i、l、n、c;
		 if(a){
			 l = a.length;
			 for(i = 0; i <l; i + = 1){
				 n = a [i] .name;
				 if(typeof o [n] === 'function'){
					 o [n] = null;
				 }
			 }
		 }

		 a = o.childNodes;

		 if(a){
			 l = a.length;
			 for(i = 0; i <l; i + = 1){
				 c = o.childNodes [i];

				 //子ノードを削除します 
				 arguments.callee(c);

				 //すべてのイベントハンドラーを削除し、
				 // YUI addListenerを介して要素に追加
				 YAHOO.util.Event.purgeElement(c);
			 }
		 }

	 })(el);

	 // HTML文字列からすべてのスクリプトを削除し、innerHTMLプロパティを設定します
	 el.innerHTML = html.replace(/ <script [^>] *> [\ S \ s] *?<\ / script [^>] *> / ig、 "");

	 //最初の子ノードへのリンクを返します
	 return el.firstChild;
 }; 




出来上がり! この関数の実装で何かを見逃した場合や、正規表現を改善する必要がある場合は教えてください。



UPD: Webページに悪意のあるコードを挿入する方法は数多くあります。 setInnerHTML



関数は、すべてのクラスAブラウザー( Aグレードブラウザー )で実行された場合にのみ<script>



の動作を正規化します 。 信頼できないHTMLコードを埋め込む場合は、サーバー側で最初にクリアします。 これには膨大な数のライブラリがあります。



メモを読んでくれたみんなに感謝します。 与えられた例を改善する方法についてのあなたのコメントを歓迎します。



All Articles