요소를 나타내는 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>
요소를 지원 하므로 문자열에서 요소를보다 안정적으로 만들 수 있습니다. 자세한 내용은 아래 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 문자열에서 요소를 만드는 라이브러리 승인 방법을 따르는 것이 좋습니다.
update()
방법을 .jQuery(html)
및 jQuery.parseHTML
메소드 에서 구현했습니다 .createElementFromHTML
하므로 함수 이름 이 잘못되었습니다 . 대신 함수에서 수익 을 창출합니다 . div.firstChild
Node
HTMLElement
node.setAttribute
Element
div.firstElementChild
<div>
되는 HTML 내가 함께 추가 포장이 .innerHTML
짜증나는 날이었다. 나는 사용을 생각하지 않았다 .firstChild
.
div
출력이 [object SVGSVGElement]
발생합니다. 내가 무엇을 잘못하고 있지?
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
. innerHTML
a div
를 포함 하도록 설정하면 이러한 요소가 사라집니다 . 이후 <template>
의 해당 콘텐츠에 이런 제한이 없습니다 템플릿을 사용하는 경우, 이러한 단점이 적용되지 않습니다.
그러나 template
일부 이전 브라우저에서는 지원되지 않습니다. 2018 년 1 월 기준으로 사용할 수 있습니까 ... 전 세계 사용자의 90 %가 template
s 를 지원하는 브라우저를 사용하고 있다고 추정 합니다 . 특히 어떤 버전의 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>')
없는 텍스트 'bla'만 포함하는 조각을 얻습니다 <td>
. 또는 적어도 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 선언 에 작은 따옴표와 큰 따옴표를 사용할 수 있습니다 .
이것은 용어에 익숙한 사람들을 위해 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을 다시 계산하므로 속도가 훨씬 느려집니다.
Document
문자열에서 요소를 만드는 프로토 타입을 추가했습니다 .
Document.prototype.createElementFromString = function (str) {
const element = new DOMParser().parseFromString(str, 'text/html');
const child = element.documentElement.querySelector('body').firstChild;
return child;
};
td
s 에서는 작동하지 않습니다 .
<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>
늦었지만 참고로;
대상 요소에 간단한 요소를 컨테이너로 추가하고 사용 후 제거 할 수 있습니다.
// 크롬 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>
문자열에서 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 ="은 매우 느립니다 : /
내 코드는 다음과 같습니다.
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 방식과 비슷합니다.