JQuery를 사용하여 추가 할 HTML 템플릿 정의


125

반복되는 배열이 있습니다. 조건이 참일 때마다 HTML일부 값이있는 컨테이너 요소에 아래 코드 사본을 추가하고 싶습니다 .

이 HTML을 현명하게 재사용 할 수있는 위치는 어디입니까?

<a href="#" class="list-group-item">
    <div class="image">
         <img src="" />
    </div>
    <p class="list-group-item-text"></p>
</a>

JQuery

$('.search').keyup(function() {
    $('.list-items').html(null);

    $.each(items, function(index) {
        // APPENDING CODE HERE
    });
});

2
현명한 방법을 찾고 있다면 모든 정보를 단일 DIV에 넣고 스타일을 지정하십시오. 셀이 두 개 뿐인 표를 여러 개 만들지 말고 앵커로 감싸지 마세요.
Sergey Snegirev 2013 년

3
OP는 적절한 코딩 관행 (kudos!)에 분명히 관심이 있으므로 도와 드리고 싶었습니다. 실제 문제에 기여하고 싶다면 답변을 게시하겠습니다. 나는 누군가가 본격적인 2 셀 테이블을 사용하여 이미지를 배치하는 것에 동의 확신과 일부 텍스트 (IE4?) 정말 이국적인 요구 사항을 제외하고 거의 정당화
세르게이 Snegirev

1
@BrianG. 댓글을 게시하는 것이 실제로 당신이 탄젠트에 빠지는 것을 의미하지는 않습니다. 댓글이 (아직 관련성이있는 한) 적절한 장소라는 데 동의하지만 아직 답변으로 확장 할 시간이없는 사람들의 드라이브 바이 힌트에도 적합합니다. 당신이하고있는 일을 명확히하는 것은 OP에 도움이됩니다.
millimoose 2013 년

질문에 아무도 대답하지 않았나요, 패트릭?
Sebastian Neira 2013 년

답변:


164

프로젝트에서 다음과 같은 템플릿 엔진을 사용하도록 결정할 수 있습니다.

다른 라이브러리를 포함하지 않으려는 경우 John Resig는 아래와 유사한 jQuery 솔루션을 제공 합니다.


브라우저와 화면 판독기는 인식 할 수없는 스크립트 유형을 무시합니다.

<script id="hidden-template" type="text/x-custom-template">
    <tr>
        <td>Foo</td>
        <td>Bar</td>
    <tr>
</script>

jQuery를 사용하여 템플릿을 기반으로 행을 추가하는 것은 다음과 같습니다.

var template = $('#hidden-template').html();

$('button.addRow').click(function() {
    $('#targetTable').append(template);
});

@MaksimLuzik이 맞습니다. Mustache (상표 철자 참고)는 더 가볍고 OP의 코드에 연결되지만 Handlebars에는 배열 처리를위한 더 많은 기능이 있으며 결국 더 충분한 솔루션을 제공 할 수 있습니다. 다음은 멋진 비교 기사입니다. blog.cubettech.com/…
Michael Scheper

13
: 여기에 템플릿을 편집하는 방법의 예 jsfiddle.net/meehanman/7vw8bc84
딘 미헨

175

오래된 질문이지만 "jQuery 사용"이라는 질문이 있기 때문에 공급 업체 종속성을 도입하지 않고도이 작업을 수행 할 수있는 옵션을 제공 할 것이라고 생각했습니다.

많은 템플릿 엔진이 있지만 최근에는 반복 ( <% for), 조건부 ( <% if) 및 변환 ( <%= myString | uppercase %>)이 기껏해야 마이크로 언어로 간주되고, 최악의 경우 안티 패턴으로 간주되는 등 여러 기능이 최근에 불리 해졌습니다. 현대의 템플릿 관행은 단순히 객체를 DOM (또는 기타) 표현에 매핑하도록 장려합니다. 예를 들어 ReactJS의 구성 요소 (특히 상태 비 저장 구성 요소)에 매핑 된 속성으로 보는 것.

HTML 내부 템플릿

당신이 당신의 HTML의 나머지 옆에 템플릿의 HTML을 유지하기 위해 의존 수있는 한 속성은 비 실행 사용하는 것 <script> type, 예 <script type="text/template">. 귀하의 경우 :

<script type="text/template" data-template="listitem">
    <a href="${url}" class="list-group-item">
        <table>
            <tr>
                <td><img src="${img}"></td>
                <td><p class="list-group-item-text">${title}</p></td>
            </tr>
        </table>
    </a>
</script>

문서로드시 템플릿을 읽고 간단한 방법으로 토큰 화합니다. String#split

var itemTpl = $('script[data-template="listitem"]').text().split(/\$\{(.+?)\}/g);

토큰을 사용하면 교대 [text, property, text, property]형식으로 얻을 수 있습니다 . 이렇게하면 Array#map매핑 함수와 함께를 사용하여 멋지게 매핑 할 수 있습니다 .

function render(props) {
  return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}

어디 props처럼 보일 수 { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }있습니다.

itemTpl위와 같이 구문 분석하고로드 items했으며 범위 내에 배열 이 있다고 가정하고 모두 합치면 됩니다.

$('.search').keyup(function () {
  $('.list-items').append(items.map(function (item) {
    return itemTpl.map(render(item)).join('');
  }));
});

이러한 접근 방식은 또한에만 겨우 jQuery를 - 당신은 바닐라 자바 스크립트를 사용하여 동일한 접근을 할 수 있어야 document.querySelector하고 .innerHTML.

jsfiddle

JS 내부 템플릿

스스로에게 물어볼 질문은 다음과 같습니다. 템플릿을 HTML 파일로 정의하고 싶습니까 / 필요합니까? 반복하려는 대부분의 항목을 재사용하는 것과 동일한 방식으로 템플릿을 구성 요소 화 및 재사용 할 수 있습니다. 함수를 사용하면됩니다.

es7-land에서는 destructuring, 템플릿 문자열 및 화살표 함수를 사용하여 $.fn.html위 의 방법을 사용하여 쉽게로드 할 수있는 매우보기 좋은 구성 요소 함수를 작성할 수 있습니다 .

const Item = ({ url, img, title }) => `
  <a href="${url}" class="list-group-item">
    <div class="image">
      <img src="${img}" />
    </div>
    <p class="list-group-item-text">${title}</p>
  </a>
`;

그런 다음 쉽게 렌더링 할 수 있으며 다음과 같이 배열에서 매핑 할 수도 있습니다.

$('.list-items').html([
  { url: '/foo', img: 'foo.png', title: 'Foo item' },
  { url: '/bar', img: 'bar.png', title: 'Bar item' },
].map(Item).join(''));

마지막 참고 사항 : DB에서 읽은 속성을 템플릿에 전달한 속성을 삭제하는 것을 잊지 마십시오. 그렇지 않으면 누군가 페이지에서 HTML을 전달할 수 있고 스크립트를 실행할 수 있습니다.


1
멋진 템플릿 엔진.
Arthur Castro

41
귀하의 JS의 내부 템플릿 섹션은 폭탄이다
BigRon

2
"HTML 내부 템플릿"접근 방식에 대한 데모 / 피들을 추가해 주시겠습니까?
LCJ

1
와! JS 내부의 템플릿… 놀랄 만한!
Roman Lopez

2
와, 이거 정말 좋아요. 각 템플릿에 data-url 속성을 추가하고 있습니다. 그리고 각각에 대한 ajax 데이터를 가져옵니다. 이것은 너무 멋져서 많은 시간을 절약했습니다! 감사합니다.
Davey

42

대신 HTML 템플릿을 사용하십시오!

허용되는 답변은 스크립트 오버로딩 방법을 나타내므로 오버로드 스크립트와 함께 제공되는 XSS 위험으로 인해 훨씬 ​​깨끗하고 안전한 다른 방법을 제안하고 싶습니다.

액션에서 사용하는 방법과 한 템플릿을 다른 템플릿에 삽입하고 문서 DOM에 추가하는 방법을 보여주는 데모 를 만들었습니다 .

예제 html

<template id="mytemplate">
  <style>
     .image{
        width: 100%;
        height: auto;
     }
  </style>
  <a href="#" class="list-group-item">
    <div class="image">
      <img src="" />
    </div>
    <p class="list-group-item-text"></p>
  </a>
</template>

예 js

// select
var t = document.querySelector('#mytemplate');

// set
t.content.querySelector('img').src = 'demo.png';
t.content.querySelector('p').textContent= 'demo text';

// add to document DOM
var clone = document.importNode(t.content, true); // where true means deep copy
document.body.appendChild(clone);

HTML <템플릿>

  • + 그 내용은 활성화 될 때까지 효과적으로 비활성 상태입니다. 기본적으로 마크 업은 숨겨진 DOM이며 렌더링되지 않습니다.

  • + 템플릿 내의 모든 콘텐츠에는 부작용이 없습니다. 템플릿이 사용될 때까지 스크립트가 실행되지 않고 이미지가로드되지 않으며 오디오가 재생되지 않습니다.

  • + 콘텐츠는 문서에없는 것으로 간주됩니다. 사용 document.getElementById()하거나 querySelector()메인 페이지에 템플릿의 자식 노드를 반환하지 않습니다.

  • + 템플릿 내부의 어딘가에 배치 될 수있다 <head>, <body>또는 <frameset>그러한 소자에 허용되는 모든 유형의 콘텐츠를 포함 할 수있다. "anywhere" <template>는 HTML 파서가 허용하지 않는 위치에서 안전하게 사용할 수 있음을 의미합니다 .

폴백

브라우저 지원은 문제가되지 않지만 모든 가능성을 다루고 싶다면 쉽게 확인할 수 있습니다.

감지 기능을 <template>사용하려면 DOM 요소를 만들고 .content 속성이 있는지 확인하세요.

function supportsTemplate() {
  return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
  // Good to go!
} else {
  // Use old templating techniques or libraries.
}

오버로딩 스크립트 방법에 대한 몇 가지 통찰력

  • + 아무것도 렌더링되지 않습니다- <script>태그가 display:none기본적으로 가지고 있기 때문에 브라우저는이 블록을 렌더링하지 않습니다 .
  • + Inert-브라우저가 스크립트 내용을 JS로 구문 분석하지 않습니다. 유형이 "text/javascript".
  • -보안 문제- .innerHTML. 사용자가 제공 한 데이터의 런타임 문자열 구문 분석은 쉽게 XSS 취약성을 유발할 수 있습니다.

전체 기사 : https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old

유용한 참조 : https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector

웹 구성 요소 만들기 Trawersy Media의 HTML 템플릿을 사용하여 사용자 정의 웹 구성 요소 만들기 자습서 : https://youtu.be/PCWaFLy3VUo


4
template요소는 Internet Explorer에서 지원되지 않습니다 (2018 년, IE11 기준). w3c.github.io/html/single-page.html의 예제 580으로 테스트되었습니다 .
Roland

나는를 좋아 <template>하지만 클래스를 자유롭게 사용하는 것이 좋으므로 어떤 소품이 무엇으로 설정되는지 분명합니다. 특히 대규모 데이터 집합에서 매핑에 대한 구성 요소 스타일 접근 방식을 사용하여 데이터를 템플릿에 올바르게 매핑하려면 여전히 약간의 js 기술이 필요합니다. 개인적으로 나는 여전히 HTML을 함수로 구축하는 것을 좋아하거나 이상적으로는 JS 자체로 DOM을 직접 구축하고 HTML을 완전히 포기하는 것을 좋아합니다 (예 : React가 수행하는 방식).
Qaribou에서 Josh

템플릿 접근 방식은 저에게 잘 맞았습니다. 한 가지 권장 사항은 템플릿을 끝이 아니라 먼저 복제하고 복제 된 개체로 작업하는 것입니다. 그렇지 않으면 템플릿 자체에 변경 사항이 적용됩니다. 일부 속성 / 콘텐츠를 가끔 설정하는 조건부 논리가있는 경우 해당 속성은 다음에 템플릿을 사용할 때 표시됩니다. 사용하기 전에 복제하면 항상 일관된 기반을 확보 할 수 있습니다.
jt.

13

본문에 추가

<div class="hide">
<a href="#" class="list-group-item">
    <table>
        <tr>
            <td><img src=""></td>
            <td><p class="list-group-item-text"></p></td>
        </tr>
    </table>
</a>
</div>

그런 다음 CSS를 만듭니다.

.hide { display: none; }

js에 추가하십시오.

$('#output').append( $('.hide').html() );

1
OP에는 JSON이 있으며 해당 배열을 데이터 소스로 사용하여 일부 html을 렌더링하려고합니다. 이 답변이 문제를 어떻게 해결하고 있습니까? 귀하의 답변은 html 노드를 가져 와서 복제 / 복제하고 데이터 바인딩과 관련된 것은 없습니다.
Adrian Iftode 2013 년

그래서 제가 반대하는 사람입니다.
Adrian Iftode 2013 년

나는 당신이 더 나은 대답을 얻는 데 도움이되지 않는다고 생각합니다. 우리의 대답에 의해 해결 된 것이 더 넓다는 것을 우리에게 상기시키는 것부터 시작할 수 있었기 때문입니다.
Sebastian Neira 2013 년

1
이것은 작동하지만 . .children().clone()보다 .html(). 속도는 <tr/>이 코드를 사용하여 페이지에 무작위로 3 : 1입니다 i=10000; time=performance.now(); while (--i) {$a.clone().append(0 ? $b.html() : $b.children().clone())} performance.now()-time. $ a.clone ()을 사용하고 있기 때문에 비율은 실제로 약간 더 과장되었지만 반복 할 때마다 비우려고하는 것이 복제보다 성능 저하에 가깝기 때문에 더 정확하게 만드는 방법을 모르겠습니다. 타이밍 기능에는 자체 비용이 있습니다.
Chinoto Vokro

1
이 앞치마는 나쁘다. 주로 사용하지 않더라도 템플릿 콘텐츠를 다운로드하고 구문 분석하기 때문입니다. 이것은 유효한 답변으로 간주하기에는 너무 큰 문제입니다. 또한 위의 다른 사람과 마찬가지로 .html () 대신 clone을 사용해야하는 경우
DevWL

3

다른 대안 : 순수

나는 그것을 사용하고 그것은 나를 많이 도왔습니다. 웹 사이트에 표시된 예 :

HTML

<div class="who">
</div>

JSON

{
  "who": "Hello Wrrrld"
}

결과

<div class="who">
  Hello Wrrrld
</div>

2

이 문제를 해결하기 위해 두 가지 해결책을 알고 있습니다.

  • 첫 번째는 AJAX와 함께 사용되며 다른 파일에서 템플릿을로드하고 .clone().

    $.get('url/to/template', function(data) {
        temp = data
        $('.search').keyup(function() {
            $('.list-items').html(null);
    
            $.each(items, function(index) {
                 $(this).append(temp.clone())
            });
    
        });
    });

    데이터를 사용할 수 있는지 확인하려면 ajax가 완료되면 이벤트를 추가해야합니다.

  • 두 번째는 원본 html의 아무 곳에 나 직접 추가하고 선택하여 jQuery에서 숨기는 것입니다.

    temp = $('.list_group_item').hide()

    다음을 사용하여 템플릿의 새 인스턴스를 추가 한 후

    $('.search').keyup(function() {
        $('.list-items').html(null);
    
        $.each(items, function(index) {
            $(this).append(temp.clone())
        });
    });
  • 이전의 것과 동일하지만 템플릿이 그대로 유지되는 것을 원하지 않지만 자바 스크립트에서만 .detach()숨기는 대신 사용할 수 있다고 생각합니다 (테스트하지 않았습니다!) .

    temp = $('.list_group_item').detach()

    .detach() 데이터와 이벤트를 유지하면서 DOM에서 요소를 제거합니다 (.remove ()는 그렇지 않습니다!).


-문제 없습니다! -
iConnor

작업에는 JSON이 있으며 해당 배열을 데이터 소스로 사용하여 HTML을 렌더링하려고합니다. 이 답변이 문제를 어떻게 해결하고 있습니까? 귀하의 답변은 html 노드를 가져 와서 복제 / 복제하고 데이터 바인딩과 관련된 것은 없습니다.
Adrian Iftode 2013 년

1
op에서 인용 합니다. 아래 HTML 코드의 복사본을 일부 값이있는 컨테이너 요소에 추가하고 싶습니다. 나는 이것이 그의 문제를 해결한다고 믿는다.
Sebastian Neira 2013 년

그리고 "일부 가치"부분은 어떻게 취급됩니까?
Adrian Iftode 2013 년

그렇다고해서 문제가 해결되지 않는다는 의미는 아닙니다. 요점 중 하나를 놓쳤다 고 말씀 해주셔서 감사합니다. :) 어쨌든, 우리가 어떤 값에 대해 이야기하고 있는지 조차 모르는 경우 어떻게 그 값을 삽입하는 방법을 알 있습니까? 이 부분을 한번 보세요.이 HTML을 스마트하게 재사용 할 수있는 위치는 어디입니까? . 정말로 무엇을 요구하고 있습니까? JSON 또는 HTML 포함에 대해?
Sebastian Neira 2013 년

1

네이티브 HTML5 템플릿 요소 사용에 대한 DevWL의 매우 좋은 답변 입니다 . OP의이 좋은 질문에 기여하기 위해 다음과 같이 jQuery 를 사용하여이 요소 를 사용하는 방법을 추가하고 싶습니다 .template

$($('template').html()).insertAfter( $('#somewhere_else') );

의 내용은 templatehtml이 아니라 데이터로 취급되므로 내용을 jQuery 객체로 래핑 한 다음 jQuery의 메서드에 액세스해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.