要素を表すHTML文字列があります:'<li>text</li>'
。それをDOMの要素(ul
私の場合はa )に追加したいと思います。プロトタイプまたはDOMメソッドでこれを行うにはどうすればよいですか?
(私はこれをjQueryで簡単に実行できることを知っていますが、残念ながら私たちはjQueryを使用していません。)
var nodes = document.fromString("<b>Hello</b> <br>");
要素を表すHTML文字列があります:'<li>text</li>'
。それをDOMの要素(ul
私の場合はa )に追加したいと思います。プロトタイプまたはDOMメソッドでこれを行うにはどうすればよいですか?
(私はこれをjQueryで簡単に実行できることを知っていますが、残念ながら私たちはjQueryを使用していません。)
var nodes = document.fromString("<b>Hello</b> <br>");
回答:
注:現在のほとんどのブラウザはHTML <template>
要素をサポートしています。HTML 要素は、文字列から要素を作成するための信頼性の高い方法を提供します。詳細については、以下のMark Ameryの回答を参照してください。
古いブラウザ、およびnode / jsdom:(<template>
執筆時点ではまだ要素をサポートしていません)には、次のメソッドを使用します。これは、ライブラリがHTML文字列からDOM要素を取得するために使用するものと同じです(IEがの実装でバグを回避するための追加作業が必要ですinnerHTML
)。
function createElementFromHTML(htmlString) {
var div = document.createElement('div');
div.innerHTML = htmlString.trim();
// Change this to div.childNodes to support multiple top-level nodes
return div.firstChild;
}
HTMLテンプレートとは異なり、このことに注意してくださいません合法的に子供たちにはできませんいくつかの要素のために働く<div>
ような、<td>
S。
すでにライブラリを使用している場合は、ライブラリで承認されているHTML文字列から要素を作成する方法を使用することをお勧めします。
update()
メソッドに組み込まれています。jQuery(html)
and jQuery.parseHTML
メソッドに実装されています。createElementFromHTML
は、eg でないaをdiv.firstChild
返すので誤解を招く可能性があります。代わりに関数からの戻りを作成します。Node
HTMLElement
node.setAttribute
Element
div.firstElementChild
<div>
私が追加したHTML のラッピングは.innerHTML
私を困らせました。を使用することを考えたことはありません.firstChild
。
div
としていますが[object SVGSVGElement]
、コンソールログから正しいDOM要素が出力されます。何が悪いのですか?
HTML 5は、<template>
この目的に使用できる要素を導入しました(現在、WhatWG仕様とMDNドキュメントで説明されています))。
<template>
要素は、スクリプトで利用できるHTMLの断片を宣言するために使用されます。要素は、型のプロパティHTMLTemplateElement
を持つとしてDOMで表され、テンプレートのコンテンツへのアクセスを提供します。あなたが設定することにより、DOM要素にHTML文字列を変換することができることをこれは意味の、その後に到達し、要素をさん.content
DocumentFragment
innerHTML
<template>
template
.content
プロパティ。
例:
/**
* @param {String} HTML representing a single element
* @return {Element}
*/
function htmlToElement(html) {
var template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content.firstChild;
}
var td = htmlToElement('<td>foo</td>'),
div = htmlToElement('<div><span>nested</span> <span>stuff</span></div>');
/**
* @param {String} HTML representing any number of sibling elements
* @return {NodeList}
*/
function htmlToElements(html) {
var template = document.createElement('template');
template.innerHTML = html;
return template.content.childNodes;
}
var rows = htmlToElements('<tr><td>foo</td></tr><tr><td>bar</td></tr>');
のような別のコンテナー要素div
を使用する同様のアプローチはうまく機能しないことに注意してください。HTMLには、他のどの要素タイプ内に存在できる要素タイプに制限があります。たとえば、をtd
の直接の子として配置することはできませんdiv
。これは、あなたが設定しようとすると消えるために、これらの要素の原因となるinnerHTML
のがdiv
、それらを含むように。<template>
にはコンテンツに対するそのような制限がないため、この欠点はテンプレートを使用する場合には当てはまりません。
ただし、template
一部の古いブラウザではサポートされていません。2018年1月、のようすることができます私の使用...推定したユーザーの90%がグローバルにサポートしているブラウザを使用しているtemplate
の。特に、それらをサポートするInternet Explorerのバージョンはありません。Microsoftはtemplate
Edgeのリリースまでサポートを実装しませんでした。
運が良ければ、最新のブラウザーのユーザーのみを対象とするコードを作成できるのであれば、今すぐ使用してください。そうしないと、ユーザーが追いつくのにしばらく待たなければならない場合があります。
html.trim
、innerHTML設定の内部解析によって削除されたスペースに関するものではありません。私の場合、textNodeの一部である重要なスペースを削除します。:-(
insertAdjacentHTML()を使用します。IE11でも、現在のすべてのブラウザーで動作します。
var mylist = document.getElementById('mylist');
mylist.insertAdjacentHTML('beforeend', '<li>third</li>');
<ul id="mylist">
<li>first</li>
<li>second</li>
</ul>
insertAdjacentHTML
IE 4.0以降のすべてのブラウザーで動作します。
innerHTML += ...
は、以前の要素への参照がこのメソッドを使用してもまだ影響を受けないことです。
beforebegin
、afterbegin
、beforeend
、afterend
。MDNの記事を参照してください。
新しいDOM実装にはrange.createContextualFragment
があり、フレームワークに依存しない方法で必要な処理を実行します。
広くサポートされています。ただし、変更されるので、同じMDNリンクで互換性を確認してください。2017年5月現在、これは次のとおりです。
Feature Chrome Edge Firefox(Gecko) Internet Explorer Opera Safari
Basic support (Yes) (Yes) (Yes) 11 15.0 9.1.2
innerHTML
divの設定と同様の欠点があることに注意してください。td
s などの特定の要素は無視され、結果のフラグメントには表示されません。
微調整の必要はありません、あなたはネイティブAPIを手に入れました:
const toNodes = html =>
new DOMParser().parseFromString(html, 'text/html').body.childNodes[0]
<td>text</td>
。これは、DOMParser
がHTMLドキュメント全体を解析しようとしているためであり、すべての要素がドキュメントのルート要素として有効であるとは限りません。
<td>test</td>
div.innerHTML、DOMParser.parseFromStringおよびrange.createContextualFragment(正しいコンテキストなし)のような特定のhtmlフラグメントの場合、ここで他の回答で言及されているソリューションでは、<td>
要素は作成されません。
jQuery.parseHTML()はそれらを適切に処理します(私はjQuery 2のparseHTML関数を独立した関数に抽出しました非jqueryコードベースで使用できる)。
Edge 13+のみをサポートしている場合は、HTML5テンプレートタグを使用する方が簡単です。
function parseHTML(html) {
var t = document.createElement('template');
t.innerHTML = html;
return t.content.cloneNode(true);
}
var documentFragment = parseHTML('<td>Test</td>');
これを行う簡単な方法を次に示します。
String.prototype.toDOM=function(){
var d=document
,i
,a=d.createElement("div")
,b=d.createDocumentFragment();
a.innerHTML=this;
while(i=a.firstChild)b.appendChild(i);
return b;
};
var foo="<img src='//placekitten.com/100/100'>foo<i>bar</i>".toDOM();
document.body.appendChild(foo);
以下を使用して、文字列から有効なDOMノードを作成できます。
document.createRange().createContextualFragment()
次の例では、文字列からマークアップを取得するボタン要素をページに追加します。
let html = '<button type="button">Click Me!</button>';
let fragmentFromString = function (strHTML) {
return document.createRange().createContextualFragment(strHTML);
}
let fragment = fragmentFromString(html);
document.body.appendChild(fragment);
DocumentFragment
オブジェクトを作成しますが、それでも -驚いたことに-受け入れられた回答と同じ欠陥に悩まさdocument.createRange().createContextualFragment('<td>bla</td>')
れています。そうすると、<td>
要素のない「bla」というテキストのみを含むフラグメントが得られます。あるいは、少なくとも、私がChrome 63でそれを観察しています。私はそれが正しい動作であるかどうかを理解するために仕様を掘り下げていません。
プロトタイプでは、次のことも実行できます。
HTML:
<ul id="mylist"></ul>
JS:
$('mylist').insert('<li>text</li>');
私はこの方法を使用しています(IE9 +で機能します)が、解析されない<td>
か、または他のいくつかの無効な直接の子の本体がありません。
function stringToEl(string) {
var parser = new DOMParser(),
content = 'text/html',
DOM = parser.parseFromString(string, content);
// return element
return DOM.body.childNodes[0];
}
stringToEl('<li>text</li>'); //OUTPUT: <li>text</li>
さらに便利強化するために()が.toDOM私たちは別の場所で見つけることができるというスニペットを、私たちは今、することができ、安全に使うバッククォート(テンプレートリテラル)。
したがって、foo html宣言で一重引用符と二重引用符を使用できます。
これは、用語に精通している人にとってはヒアドキュメントのように動作します。
これは、変数でさらに拡張して、複雑なテンプレートを作成できます。
テンプレートリテラルは
、二重引用符または単一引用符ではなく、バックティック()(グレーブアクセント)文字で囲まれています。テンプレートリテラルにはプレースホルダーを含めることができます。これらは、ドル記号と中括弧($ {expression})で示されます。プレースホルダー内の式とそれらの間のテキストは関数に渡されます。デフォルトの関数は、パーツを1つの文字列に連結するだけです。テンプレートリテラル(ここでタグ)の前に式がある場合、これは「タグ付きテンプレート」と呼ばれます。その場合、タグ式(通常は関数)は処理されたテンプレートリテラルを使用して呼び出され、出力する前に操作できます。テンプレートリテラルでバックティックをエスケープするには、バックティックの前にバックスラッシュ\を置きます。
String.prototype.toDOM=function(){
var d=document,i
,a=d.createElement("div")
,b=d.createDocumentFragment()
a.innerHTML = this
while(i=a.firstChild)b.appendChild(i)
return b
}
// Using template litterals
var a = 10, b = 5
var foo=`
<img
onclick="alert('The future start today!')"
src='//placekitten.com/100/100'>
foo${a + b}
<i>bar</i>
<hr>`.toDOM();
document.body.appendChild(foo);
img {cursor: crosshair}
では、なぜ直接使用しないの.innerHTML +=
ですか?そうすることで、DOM全体がブラウザによって再計算され、速度が大幅に低下します。
Document
文字列から要素を作成するプロトタイプを追加しました。
Document.prototype.createElementFromString = function (str) {
const element = new DOMParser().parseFromString(str, 'text/html');
const child = element.documentElement.querySelector('body').firstChild;
return child;
};
<template>
デモ
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
* @description HTML5 Template
* @augments
* @example
*
*/
/*
<template>
<h2>Flower</h2>
<img src="https://www.w3schools.com/tags/img_white_flower.jpg">
</template>
<template>
<div class="myClass">I like: </div>
</template>
*/
const showContent = () => {
// let temp = document.getElementsByTagName("template")[0],
let temp = document.querySelector(`[data-tempalte="tempalte-img"]`),
clone = temp.content.cloneNode(true);
document.body.appendChild(clone);
};
const templateGenerator = (datas = [], debug = false) => {
let result = ``;
// let temp = document.getElementsByTagName("template")[1],
let temp = document.querySelector(`[data-tempalte="tempalte-links"]`),
item = temp.content.querySelector("div");
for (let i = 0; i < datas.length; i++) {
let a = document.importNode(item, true);
a.textContent += datas[i];
document.body.appendChild(a);
}
return result;
};
const arr = ["Audi", "BMW", "Ford", "Honda", "Jaguar", "Nissan"];
if (document.createElement("template").content) {
console.log("YES! The browser supports the template element");
templateGenerator(arr);
setTimeout(() => {
showContent();
}, 0);
} else {
console.error("No! The browser does not support the template element");
}
@charset "UTf-8";
/* test.css */
:root {
--cololr: #000;
--default-cololr: #fff;
--new-cololr: #0f0;
}
[data-class="links"] {
color: white;
background-color: DodgerBlue;
padding: 20px;
text-align: center;
margin: 10px;
}
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Template Test</title>
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<section>
<h1>Template Test</h1>
</section>
<template data-tempalte="tempalte-img">
<h3>Flower Image</h3>
<img src="https://www.w3schools.com/tags/img_white_flower.jpg">
</template>
<template data-tempalte="tempalte-links">
<h3>links</h3>
<div data-class="links">I like: </div>
</template>
<!-- js -->
</body>
</html>
遅いですが、メモとして。
簡単な要素をコンテナーとしてターゲット要素に追加し、使用後に削除することができます。
// chrome 23.0、firefox 18.0、つまり7-8-9とOpera 12.11でテスト済み。
<div id="div"></div>
<script>
window.onload = function() {
var foo, targetElement = document.getElementById('div')
foo = document.createElement('foo')
foo.innerHTML = '<a href="#" target="_self">Text of A 1.</a> '+
'<a href="#" onclick="return !!alert(this.innerHTML)">Text of <b>A 2</b>.</a> '+
'<hr size="1" />'
// Append 'foo' element to target element
targetElement.appendChild(foo)
// Add event
foo.firstChild.onclick = function() { return !!alert(this.target) }
while (foo.firstChild) {
// Also removes child nodes from 'foo'
targetElement.insertBefore(foo.firstChild, foo)
}
// Remove 'foo' element from target element
targetElement.removeChild(foo)
}
</script>
文字列からDOMをレンダリングする最速のソリューション:
let render = (relEl, tpl, parse = true) => {
if (!relEl) return;
const range = document.createRange();
range.selectNode(relEl);
const child = range.createContextualFragment(tpl);
return parse ? relEl.appendChild(child) : {relEl, el};
};
そしてここ uはDOM操作のパフォーマンスをチェックすることができ、ネイティブJS対リアクト
今、あなたは単に使うことができます:
let element = render(document.body, `
<div style="font-size:120%;line-height:140%">
<p class="bold">New DOM</p>
</div>
`);
そしてもちろん、近い将来、メモリからの参照を使用します。var "element"は、ドキュメント内に新しく作成されたDOMです。
そして「innerHTML =」は非常に遅いことを覚えておいてください:/
これが私のコードです、そしてそれは機能します:
function parseTableHtml(s) { // s is string
var div = document.createElement('table');
div.innerHTML = s;
var tr = div.getElementsByTagName('tr');
// ...
}
全体として、私が思いついたのは、複雑ではあるが単純なアプローチでこれを共有することだと思いました...多分誰かが何か便利なものを見つけるでしょう。
/*Creates a new element - By Jamin Szczesny*/
function _new(args){
ele = document.createElement(args.node);
delete args.node;
for(x in args){
if(typeof ele[x]==='string'){
ele[x] = args[x];
}else{
ele.setAttribute(x, args[x]);
}
}
return ele;
}
/*You would 'simply' use it like this*/
$('body')[0].appendChild(_new({
node:'div',
id:'my-div',
style:'position:absolute; left:100px; top:100px;'+
'width:100px; height:100px; border:2px solid red;'+
'cursor:pointer; background-color:HoneyDew',
innerHTML:'My newly created div element!',
value:'for example only',
onclick:"alert('yay')"
}));
なぜネイティブjsを使わないのですか?
var s="<span class='text-muted' style='font-size:.75em; position:absolute; bottom:3px; left:30px'>From <strong>Dan's Tools</strong></span>"
var e=document.createElement('div')
var r=document.createRange();
r.selectNodeContents(e)
var f=range.createContextualFragment(s);
e.appendChild(f);
e = e.firstElementChild;
次の関数を使用して、テキスト「HTML」を要素に変換できます
function htmlToElement(html)
{
var element = document.createElement('div');
element.innerHTML = html;
return(element);
}
var html="<li>text and html</li>";
var e=htmlToElement(html);
td
ます。特に、s では機能しません。
これも機能します:
$('<li>').text('hello').appendTo('#mylist');
これは、チェーンされた関数呼び出しを使用したjqueryの方法に似ています。