การกำหนดเทมเพลต HTML เพื่อต่อท้ายโดยใช้ JQuery


126

ฉันมีอาร์เรย์ที่ฉันกำลังวนลูป ทุกครั้งที่เงื่อนไขเป็นจริงฉันต้องการต่อท้ายสำเนาของ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

3
เห็นได้ชัดว่า OP สนใจแนวทางการเขียนโค้ดที่เหมาะสม (ความรุ่งโรจน์!) ดังนั้นฉันจึงอยากช่วย หากฉันต้องการมีส่วนร่วมในปัญหาที่แท้จริงฉันจะโพสต์คำตอบ ฉันแน่ใจว่าทุกคนเห็นด้วยว่าการใช้ตารางสองเซลล์เต็มรูปแบบเพื่อวางตำแหน่งรูปภาพและข้อความบางส่วนแทบจะไม่เป็นธรรมยกเว้นข้อกำหนดที่แปลกใหม่จริงๆ (IE4?)
Sergey Snegirev

1
@BrianG การโพสต์ความคิดเห็นไม่ได้หมายความว่าคุณกำลังจะสัมผัสกัน แม้ว่าฉันยอมรับว่าความคิดเห็นเป็นสถานที่ที่เหมาะสมสำหรับผู้นั้น (ตราบใดที่ยังมีความเกี่ยวข้อง) แต่ก็เหมาะสำหรับคำแนะนำในการขับรถโดยผู้ที่ยังไม่มีเวลาขยายความเป็นคำตอบ OP เพื่อให้ชัดเจนว่าคุณกำลังทำอะไรอยู่
มิลลิโมส

ไม่มีใครตอบคำถามของคุณแพทริค?
Sebastian Neira

คำตอบ:


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 ใช่เลย หนวด (สังเกตการสะกดเครื่องหมายการค้า) มีน้ำหนักเบากว่าและจะเสียบเข้ากับรหัสของ OP แต่ Handlebars มีคุณสมบัติมากกว่าสำหรับการจัดการอาร์เรย์และอาจให้วิธีแก้ปัญหาที่เพียงพอมากขึ้นในตอนท้าย นี่คือบทความเปรียบเทียบที่ดี: blog.cubettech.com/…
Michael Scheper

13
ตัวอย่างวิธีแก้ไขเทมเพลตที่นี่: jsfiddle.net/meehanman/7vw8bc84
Dean Meehan

176

คำถามเก่า แต่เนื่องจากคำถามถามว่า "ใช้ 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 - คุณควรจะสามารถที่จะใช้วิธีการเดียวกันโดยใช้ javascript วานิลลากับและdocument.querySelector.innerHTML

jsfiddle

เทมเพลตภายใน JS

คำถามที่ต้องถามตัวเองคือคุณต้องการ / จำเป็นต้องกำหนดเทมเพลตเป็นไฟล์ HTML หรือไม่? คุณสามารถคอมโพเนนต์ + ใช้เทมเพลตซ้ำได้ตลอดเวลาในลักษณะเดียวกับที่คุณใช้ซ้ำสิ่งต่างๆส่วนใหญ่ที่คุณต้องการทำซ้ำ: ด้วยฟังก์ชัน

ใน es7-land โดยใช้การทำลายโครงสร้างสตริงเทมเพลตและฟังก์ชันลูกศรคุณสามารถเขียนฟังก์ชั่นส่วนประกอบที่ดูสวยสดใสซึ่งสามารถโหลดได้ง่ายโดยใช้$.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(''));

ข้อควรทราบสุดท้าย: อย่าลืมทำความสะอาดคุณสมบัติของคุณที่ส่งผ่านไปยังเทมเพลตหากอ่านจากฐานข้อมูลหรือมีคนส่งผ่าน HTML (แล้วเรียกใช้สคริปต์ ฯลฯ ) จากหน้าของคุณ


1
เครื่องมือแม่แบบที่ดี
Arthur Castro

41
เทมเพลตของคุณในส่วนJSคือระเบิด
BigRon

2
คุณช่วยเพิ่มการสาธิต / ซอสำหรับแนวทาง "Templates Inside 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 <template>

  • + เนื้อหาจะเฉื่อยอย่างมีประสิทธิภาพจนกว่าจะเปิดใช้งาน โดยพื้นฐานแล้วมาร์กอัปของคุณจะซ่อน DOM ไว้และไม่แสดงผล

  • + เนื้อหาใด ๆ ภายในเทมเพลตจะไม่มีผลข้างเคียง สคริปต์ไม่ทำงานรูปภาพไม่โหลดเสียงไม่เล่น ... จนกว่าจะใช้เทมเพลต

  • + ถือว่าเนื้อหาไม่มีอยู่ในเอกสาร การใช้document.getElementById()หรือquerySelector()ในหน้าหลักจะไม่ส่งคืนโหนดลูกของเทมเพลต

  • + แม่สามารถวางไว้ที่ใดก็ได้ภายในของ<head>, <body>หรือ<frameset>และสามารถมีประเภทของเนื้อหาใด ๆ ที่ได้รับอนุญาตในองค์ประกอบเหล่านั้น โปรดทราบว่า "ทุกที่" หมายความว่า<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โดยค่าเริ่มต้น
  • + เฉื่อย - เบราว์เซอร์ไม่ได้แยกเนื้อหาสคริปต์ที่เป็น 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

การสร้างส่วนประกอบเว็บการสร้างการสอนส่วนประกอบเว็บแบบกำหนดเองโดยใช้เทมเพลต HTML โดย Trawersy Media: https://youtu.be/PCWaFLy3VUo


4
templateองค์ประกอบไม่สนับสนุน Internet Explorer ( ณ 2018 IE11) ทดสอบกับตัวอย่าง 580 ของw3c.github.io/html/single-page.html
Roland

ฉันชอบ<template>แม้ว่าฉันจะแนะนำให้ใช้ชั้นเรียนอย่างเสรีดังนั้นจึงชัดเจนว่าอุปกรณ์ประกอบฉากใดบ้างที่ตั้งค่าเป็นอะไร ยังต้องใช้ทักษะ js ในการแมปข้อมูลของคุณลงในเทมเพลตอย่างถูกต้องโดยเฉพาะอย่างยิ่งการใช้วิธีการทำแผนที่ในชุดข้อมูลขนาดใหญ่ โดยส่วนตัวแล้วฉันยังคงชอบเพียงแค่สร้าง HTML ในฟังก์ชันหรือควรสร้าง DOM โดยตรงด้วย JS เองและละทิ้ง HTML ทั้งหมด (เช่น React ทำอย่างไร)
Josh จาก Qaribou

วิธีการของเทมเพลตทำงานได้ดีสำหรับฉัน คำแนะนำอย่างหนึ่งที่ฉันมีคือการโคลนเทมเพลตก่อน (แทนที่จะเป็นตอนท้าย) และทำงานกับวัตถุที่โคลน มิฉะนั้นการเปลี่ยนแปลงที่คุณกำลังทำจะเกิดขึ้นกับเทมเพลตนั้นเอง หากคุณมีตรรกะเงื่อนไขที่คุณตั้งค่าคุณสมบัติ / เนื้อหาบางส่วนเท่านั้นคุณสมบัติเหล่านั้นจะปรากฏในการใช้เทมเพลตครั้งต่อไปของคุณ โดยการโคลนก่อนการใช้งานแต่ละครั้งคุณต้องแน่ใจว่าคุณมีพื้นฐานที่สอดคล้องกันในการทำงานเสมอ
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

ดังนั้นฉันคือผู้ที่ลงคะแนน
Adrian Iftode

ฉันคิดว่าคุณไม่ได้ช่วยให้ได้รับคำตอบที่ดีขึ้นจริงๆเพราะคุณสามารถเริ่มต้นด้วยการเตือนเราว่าประเด็นนั้นกว้างขึ้นว่าคำตอบของเราตอบอะไร
Sebastian Neira

1
นี้ไม่ทำงาน แต่มันมีประสิทธิภาพมากขึ้นที่จะทำมากกว่า.children().clone() .html()ความเร็วประมาณ 3: 1 สำหรับการสุ่มที่<tr/>ฉันมีบนเพจโดยใช้รหัส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 ()
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 () ไม่ได้!)


- ไม่มี Problemo! -
iConnor

op มี JSON และต้องการแสดง html โดยใช้อาร์เรย์นั้นเป็นแหล่งข้อมูล คำตอบนี้ช่วยแก้ปัญหาได้อย่างไร? คำตอบของคุณใช้โหนด html และโคลน / ทำซ้ำโดยไม่มีอะไรเกี่ยวข้องกับการผูกข้อมูล
Adrian Iftode

1
ฉันอ้างจาก op: ฉันต้องการต่อท้ายสำเนาของโค้ด HTML ด้านล่างกับองค์ประกอบคอนเทนเนอร์ที่มีค่าบางอย่าง ฉันเชื่อว่าสิ่งนี้ช่วยแก้ปัญหาของเขาได้
Sebastian Neira

และได้รับการปฏิบัติอย่างไรในส่วน "ค่านิยม"?
Adrian Iftode

นั่นไม่ได้หมายความว่ามันไม่ได้ช่วยแก้ปัญหา ฉันขอขอบคุณที่คุณได้บอกผมว่าผมหายไปหนึ่งในจุด :) อย่างไรก็ตามวิธีที่ฉันจะทราบวิธีการใส่ค่าเหล่านั้นถ้าผมไม่ได้รู้ว่าสิ่งที่มีค่าที่เราพูดถึง? ลองดูที่ส่วนนี้ฉันจะนำ HTML นี้ไปใช้ซ้ำได้อย่างไรอย่างชาญฉลาด . สิ่งที่ถูกถามจริงๆ? เกี่ยวกับ JSON หรือการรวม HTML?
Sebastian Neira

1

คำตอบที่ดีมากจากDevWLเกี่ยวกับการใช้องค์ประกอบเทมเพลต HTML5 ดั้งเดิม ในการมีส่วนร่วมในคำถามที่ดีจาก OP ฉันต้องการเพิ่มเกี่ยวกับวิธีการใช้templateองค์ประกอบนี้โดยใช้ jQuery ตัวอย่างเช่น:

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

เนื้อหาของtemplateไม่ใช่ html แต่ถือว่าเป็นเพียงข้อมูลดังนั้นคุณต้องรวมเนื้อหาไว้ในวัตถุ jQuery เพื่อเข้าถึงวิธีการของ jQuery

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.