내장 DOM 메소드 또는 프로토 타입을 사용하여 HTML 문자열에서 새 DOM 요소 작성


621

요소를 나타내는 HTML 문자열이 '<li>text</li>'있습니다. DOM의 요소 ( ul내 경우에는 a) 에 추가하고 싶습니다 . 프로토 타입 또는 DOM 메소드를 사용하여이를 수행하려면 어떻게해야합니까?

(jQuery 에서이 작업을 쉽게 수행 할 수 있다는 것을 알고 있지만 불행히도 우리는 jQuery를 사용하지 않습니다.)


죄송합니다. 정확히 무엇을 달성하려고하십니까? HTML 문자열-> dom 요소?
Crescent Fresh

36
불행히도 이러한 솔루션은 간접적입니다. 나는 표준위원회와 같은 비슷한 지정 텐데 :var nodes = document.fromString("<b>Hello</b> <br>");
스리 Sarnobat


1
전달해야 할 속성이 있고 구문 분석하고 싶지 않기 때문에 위의 문제가 발생했습니다. "<table id = '5ccf9305-4b10-aec6-3c55-a6d218bfb107'class = 'data-table 행 경계 표시 'cellspacing ='0 'width ='100 % '> </ table> "따라서 간단하게 사용했습니다 : $ ("<table id ='5ccf9305-4b10-aec6-3c55-a6d218bfb107 'class ='data -table row-border display 'cellspacing ='0 'width ='100 % '> </ table> ")
stevenlacerda

답변:


818

참고 : 대부분의 최신 브라우저는 HTML <template>요소를 지원 하므로 문자열에서 요소를보다 안정적으로 만들 수 있습니다. 자세한 내용은 아래 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 템플릿과 달리 s 와 같은 합법적으로 자식이 될 수없는 일부 요소 에는 작동하지 않습니다 .<div><td>

이미 라이브러리를 사용하고 있다면 HTML 문자열에서 요소를 만드는 라이브러리 승인 방법을 따르는 것이 좋습니다.


1
이 안전하지 않은 innerHTML 할당을 사용하지 않고 jQuery를 사용하여 innerHTML을 생성 된 div로 설정하는 방법 (div.innerHTML = "일부 값")
Shivanshu Goyal

12
예를 들어 cannot 이 아닌 a를 반환 createElementFromHTML 하므로 함수 이름 이 잘못되었습니다 . 대신 함수에서 수익 을 창출합니다 . div.firstChildNodeHTMLElementnode.setAttributeElementdiv.firstElementChild
Semmel

당신의 감사 <div>되는 HTML 내가 함께 추가 포장이 .innerHTML짜증나는 날이었다. 나는 사용을 생각하지 않았다 .firstChild.
Ivan

생성 된 내부에서 SVG를 구문 분석하려고하는데 콘솔 로그가 올바른 DOM 요소를 제공하는 동안 div출력이 [object SVGSVGElement]발생합니다. 내가 무엇을 잘못하고 있지?
ed1nh0

1
내가 대신 firstChild (참조의 firstElementChild을 사용 w3schools.com/jsref/prop_element_firstelementchild.asp 전면 또는 템플릿의 끝 부분에 공간이있는 경우, firstChild가 비어 textNode 반환하기 때문에)
크리스 Panayotoff

342

HTML 5는 <template>이 목적으로 사용할 수있는 요소를 도입했습니다 (현재 WhatWG 사양MDN 문서에 설명되어 있음 ).

<template>소자 스크립트에서 사용될 수 HTML 단편을 선언하기 위해 사용된다. 요소는 템플릿의 컨텐츠에 대한 액세스를 제공하기 위해 DOM 에서 유형 HTMLTemplateElement.content특성 을 갖는 것으로 표시됩니다 DocumentFragment. 당신이 설정하여 DOM 요소에 HTML 문자열을 변환 할 수있는이 수단 innerHTML(A)의 <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. innerHTMLa div를 포함 하도록 설정하면 이러한 요소가 사라집니다 . 이후 <template>의 해당 콘텐츠에 이런 제한이 없습니다 템플릿을 사용하는 경우, 이러한 단점이 적용되지 않습니다.

그러나 template일부 이전 브라우저에서는 지원되지 않습니다. 2018 년 1 월 기준으로 사용할 수 있습니까 ... 전 세계 사용자의 90 %가 templates 를 지원하는 브라우저를 사용하고 있다고 추정 합니다 . 특히 어떤 버전의 Internet Explorer도 지원하지 않습니다. Microsoft는 templateEdge가 릴리스 될 때까지 지원을 구현하지 않았습니다 .

최신 브라우저 사용자만을 대상으로하는 코드를 작성하기에 운이 좋으면 지금 바로 사용하십시오. 그렇지 않으면 사용자가 따라 잡기까지 잠시 기다려야 할 수도 있습니다.


9
좋은 하나, 현대적인 접근 방식. 오페라에서 테스트, IE를 잊어 보자
Adi Prasetyo

2
이것은 효과적인 접근 방식이며 매우 깨끗합니다. 그러나 (최소한 Chrome 50에서는) 스크립트 태그 처리가 중단됩니다. 즉,이 방법을 사용하여 스크립트 태그를 만든 다음이를 문서 (본문 또는 헤드)에 추가해도 태그가 평가되지 않으므로 스크립트가 실행되지 않습니다. (부착시 평가가 발생하면 의도적으로 설계된 것일 수 있습니다. 확실히 말할 수는 없습니다.)
shanef22

1
아름다운! 다음과 같은 방법으로 요소를 쿼리 할 수도 있습니다. template.content.querySelector ( "img");
Roger Gajraj

1
@Crescent Fresh : 충분히 공평합니다. 지금은 관련이 없다고 말한 이후로 답변을 원치 않았습니다. 사과드립니다. 메타에 대해 논의했듯이 독자들에게 이것에 대한 설명을 추가하는 것이 좋은 타협입니다 . 편집 전쟁이 다시 시작되지 않기를 바랍니다.
BoltClock

2
한 가지 문제가 있습니다. 시작 또는 끝에 공백이있는 태그가 있으면 제거됩니다! 잘못 생각하지 마십시오. 이것은 제거 된 공간이 html.trim아니라 innerHTML 설정의 내부 파싱에 관한 것입니다. 필자의 경우 textNode의 일부인 중요한 공백을 제거합니다. :-(
e-motiv

109

insertAdjacentHTML ()을 사용하십시오 . IE11에서도 모든 최신 브라우저에서 작동합니다.

var mylist = document.getElementById('mylist');
mylist.insertAdjacentHTML('beforeend', '<li>third</li>');
<ul id="mylist">
 <li>first</li>
 <li>second</li>
</ul>


9
첫째, insertAdjacentHTMLIE 4.0부터 모든 브라우저 에서 작동합니다.
Jonas Äppelgran

6
둘째, 훌륭합니다! innerHTML += ...이 방법을 사용하면 이전 요소에 대한 참조가 그대로 유지된다는 점에 비해 큰 장점 이 있습니다.
Jonas Äppelgran

7
첫 번째 인수에 대한 셋째, 가능한 값은 : beforebegin, afterbegin, beforeend, afterend. MDN 기사를 참조하십시오.
Jonas Äppelgran

나에게 최고의 답변
Jordan

4
삽입 된 HTML을 요소로 반환하지 않습니다
Mojimi

30

최신 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

3
이것은 innerHTMLdiv 설정과 비슷한 단점이 있습니다 . tds 와 같은 특정 요소 는 무시되고 결과 조각에 나타나지 않습니다.
Mark Amery

"데스크탑 Safari가 한 시점에서 Range.createContextualFragment ()를 지원한다는보고가 있지만 적어도 Safari 9.0 및 9.1에서는 지원되지 않습니다." (답변의 MDN 링크)
akauppi

27

조정할 필요가 없으며 기본 API가 있습니다.

const toNodes = html =>
    new DOMParser().parseFromString(html, 'text/html').body.childNodes[0]

9
이것은 받아 들여진 대답과 같은 큰 단점으로 어려움을 겪고 있습니다-HTML과 유사 <td>text</td>합니다. DOMParser전체 HTML 문서 를 구문 분석하려고하기 때문에 모든 요소가 문서의 루트 요소로 유효한 것은 아닙니다.
Mark Amery

4
-1 위의 의견에서 언급 한 단점을 명시 적으로 지적한 이전 답변 의 복제본이므로 -1 입니다.
Mark Amery

20

<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>');

16

간단한 방법은 다음과 같습니다.

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);

4
@MarkAmery의 차이점은 DOM에 여러 루트 요소를 추가 할 수있는 조각을 사용한다는 것입니다. 이는 추가 이점입니다. 윌리엄 만이 그의 대답을 언급했다면 ...
Koen.

10

다음을 사용하여 문자열에서 유효한 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);


5
이것이 DocumentFragment객체를 생성하더라도 여전히 놀랍게도 받아 들여진 대답과 동일한 결함이 있습니다. 그렇다면 요소가 document.createRange().createContextualFragment('<td>bla</td>')없는 텍스트 'bla'만 포함하는 조각을 얻습니다 <td>. 또는 적어도 Chrome 63에서 관찰 한 것입니다. 나는 그것이 올바른 행동 인지 아닌지를 알아 내기 위해 사양을 탐구 하지 않았습니다.
Mark Amery

9

프로토 타입을 사용하여 다음을 수행 할 수도 있습니다.

HTML :

<ul id="mylist"></ul>

JS :

$('mylist').insert('<li>text</li>');

이 jQuery입니까? 아니면 JS?
Jeya Suriya Muthumari 5

1
이것은 언급 된 것처럼 내장 DOM 메소드가 아닌 jQuery를 사용하고 있습니다.
Juan Hurtado

1
@JuanHurtado 이것은 거의 11 년 전에 OP 요청에 따라 프로토 타입 J를 사용하고 있습니다.)
Pablo

8

이 방법 (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>

5

다른 장소에서 찾을 수 있는 유용한 .toDOM () 스 니펫을 더욱 향상시키기 위해 백틱 ( 템플릿 리터럴 )을 안전하게 사용할 수 있습니다 .

따라서 foo html 선언 에 작은 따옴표와 큰 따옴표를 사용할 수 있습니다 .

이것은 용어에 익숙한 사람들을 위해 heredocs 처럼 행동합니다 .

복잡한 템플릿을 만들기 위해 변수로 더욱 향상시킬 수 있습니다.

템플릿 리터럴은 큰 따옴표 나 작은 따옴표 대신 백틱 ( ) (가중 악센트) 문자로 묶습니다. 템플릿 리터럴에는 자리 표시자가 포함될 수 있습니다. 이것들은 달러 기호와 중괄호 ($ {expression})로 표시됩니다. 플레이스 홀더의 표현식과 그 사이의 텍스트는 함수로 전달됩니다. 기본 기능은 부품을 단일 문자열로 연결합니다. 템플릿 리터럴 (여기에서 태그) 앞에식이있는 경우이를 "태그 된 템플릿"이라고합니다. 이 경우 처리 된 템플릿 리터럴을 사용하여 태그 식 (보통 함수)을 호출 한 다음 출력하기 전에 조작 할 수 있습니다. 템플릿 리터럴에서 백 틱을 이스케이프하려면 백 틱 앞에 백 슬래시 (\)를 넣으십시오.

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을 다시 계산하므로 속도가 훨씬 느려집니다.

https://caniuse.com/template-literals


4

Document문자열에서 요소를 만드는 프로토 타입을 추가했습니다 .

Document.prototype.createElementFromString = function (str) {
    const element = new DOMParser().parseFromString(str, 'text/html');
    const child = element.documentElement.querySelector('body').firstChild;
    return child;
};

이 페이지의 다른 부분에서 지적했듯이 tds 에서는 작동하지 않습니다 .
Mark Amery

3

HTML5 및 ES6

<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>


2

늦었지만 참고로;

대상 요소에 간단한 요소를 컨테이너로 추가하고 사용 후 제거 할 수 있습니다.

// 크롬 23.0, 파이어 폭스 18.0, 즉 7-8-9 및 오페라 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>

2

문자열에서 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};
};

그리고 여기 에서 DOM 조작에 대한 성능을 확인할 수 있습니다 .React vs native 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 ="은 매우 느립니다 : /


1

내 코드는 다음과 같습니다.

function parseTableHtml(s) { // s is string
    var div = document.createElement('table');
    div.innerHTML = s;

    var tr = div.getElementsByTagName('tr');
    // ...
}

1
작성 될 요소 자체가 테이블 인 경우 실패합니다.
Mark Amery

0

그것을 위해 나는 내가 생각해 낸 복잡하지만 간단한 접근 방식으로 이것을 공유한다고 생각했다.

/*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')"
}));

0

왜 네이티브 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;

-1
function domify (str) {
  var el = document.createElement('div');
  el.innerHTML = str;

  var frag = document.createDocumentFragment();
  return frag.appendChild(el.removeChild(el.firstChild));
}

var str = "<div class='foo'>foo</div>";
domify(str);

-2

다음 함수를 사용하여 텍스트 "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);


-1; 이것은 허용 된 답변에서 제안 된 것과 동일한 기술이며 동일한 단점이 있습니다. 특히 tds에서 작동하지 않습니다 .
Mark Amery

-3
var jtag = $j.li({ child:'text' }); // Represents: <li>text</li>
var htmlContent = $('mylist').html();
$('mylist').html(htmlContent + jtag.html());

jnerator 사용


-3

나를 위해 작동하는 코드는 다음과 같습니다.

' Text '문자열을 HTML 요소 로 변환하고 싶었습니다.

var diva = UWA.createElement('div');
diva.innerHTML = '<a href="http://wwww.example.com">Text</a>';
var aelement = diva.firstChild;

무엇입니까 wwww?
Tintin81

-3

var msg = "test"jQuery.parseHTML (msg)


이 코드 스 니펫은 제한적이고 즉각적인 도움이 될 수 있습니다. 적절한 설명은 크게이 문제에 대한 좋은 해결책이 왜 보여 장기적인 가치를 향상 것이고, 다른 유사한 질문을 미래의 독자들에게 더 유용 할 것입니다. 제발 편집 당신이 만든 가정 등 일부 설명을 추가 할 답변을.
Dwhitz

-7

이것도 작동합니다 :

$('<li>').text('hello').appendTo('#mylist');

체인 함수 호출을 사용하는 jquery 방식과 비슷합니다.


26
jQuery이기 때문에 jQuery처럼 느껴 집니까?
Tim Ferrell

5
마지막 줄은 재밌어요!
kumarharsh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.