Xác định một mẫu HTML để thêm vào bằng JQuery


125

Tôi có một mảng mà tôi đang lặp lại. Mỗi khi một điều kiện là đúng, tôi muốn nối bản sao HTMLmã bên dưới vào phần tử vùng chứa với một số giá trị.

Tôi có thể đặt HTML này ở đâu để sử dụng lại một cách thông minh?

<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
Nếu bạn đang tìm kiếm một cách thông minh, hãy đặt tất cả thông tin của bạn vào một DIV duy nhất và tạo kiểu cho nó. Không tạo nhiều bảng chỉ có hai ô, không quấn chúng thành các neo.
Sergey Snegirev

3
OP rõ ràng là quan tâm đến các thực hành mã hóa thích hợp (kudos!), Vì vậy tôi muốn giúp đỡ. Nếu tôi muốn đóng góp vào vấn đề thực tế, tôi sẽ đăng một câu trả lời. Tôi chắc rằng bất kỳ ai cũng đồng ý rằng việc sử dụng bảng hai ô đầy đủ để định vị hình ảnh và một số văn bản hầu như không hợp lý ngoại trừ một số yêu cầu thực sự kỳ lạ (IE4?)
Sergey Snegirev

1
@BrianG. Đăng bình luận không thực sự ngụ ý rằng bạn đang đi theo hướng tiếp tuyến. Mặc dù tôi đồng ý rằng các nhận xét là nơi thích hợp cho những người đó (miễn là chúng vẫn có liên quan), chúng cũng thích hợp cho các gợi ý lái xe của những người chưa có thời gian mở rộng chúng thành câu trả lời. Sẽ rất hữu ích cho OP khi nói rõ bạn đang làm gì.
milimoose

Không ai trả lời câu hỏi của bạn, Patrick?
Sebastian Neira

Câu trả lời:


164

Bạn có thể quyết định sử dụng công cụ tạo khuôn mẫu trong dự án của mình, chẳng hạn như:

Nếu bạn không muốn bao gồm một thư viện khác, John Resig cung cấp giải pháp jQuery , tương tự như bên dưới.


Trình duyệt và trình đọc màn hình bỏ qua các loại tập lệnh không được công nhận:

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

Sử dụng jQuery, thêm các hàng dựa trên mẫu sẽ giống như sau:

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

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

@MaksimLuzik nói đúng. Mustache (lưu ý chính tả nhãn hiệu) có trọng lượng nhẹ hơn và sẽ phù hợp với mã của OP, nhưng Handlebars có nhiều tính năng hơn để xử lý mảng và cuối cùng có thể cung cấp một giải pháp đầy đủ hơn. Dưới đây là một bài báo so sánh đẹp: blog.cubettech.com/...
Michael Scheper

13
Ví dụ về cách chỉnh sửa mẫu tại đây: jsfiddle.net/meehanman/7vw8bc84
Dean Meehan

175

Câu hỏi cũ, nhưng vì câu hỏi yêu cầu "sử dụng jQuery", tôi nghĩ tôi sẽ cung cấp một tùy chọn cho phép bạn thực hiện việc này mà không cần giới thiệu bất kỳ sự phụ thuộc vào nhà cung cấp nào.

Mặc dù có rất nhiều công cụ tạo khuôn mẫu trên mạng, nhưng nhiều tính năng của chúng đã bị đánh giá thấp gần đây, với phép lặp ( <% for), điều kiện ( <% if) và biến đổi ( <%= myString | uppercase %>) được coi là microlanguage tốt nhất và tệ nhất là anti-pattern. Các phương pháp tạo khuôn mẫu hiện đại khuyến khích chỉ cần ánh xạ một đối tượng tới biểu diễn DOM (hoặc khác) của nó, ví dụ như những gì chúng ta thấy với các thuộc tính được ánh xạ tới các thành phần trong ReactJS (đặc biệt là các thành phần không trạng thái).

Mẫu bên trong HTML

Một tài sản mà bạn có thể dựa vào đó để giữ HTML cho mẫu của bạn bên cạnh còn lại của HTML của bạn, là bằng cách sử dụng một tổ chức phi thực hiện <script> type, ví dụ <script type="text/template">. Đối với trường hợp của bạn:

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

Khi tải tài liệu, hãy đọc mẫu của bạn và mã hóa nó bằng cách sử dụng String#split

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

Lưu ý rằng với mã thông báo của chúng tôi, bạn nhận được nó ở [text, property, text, property]định dạng thay thế . Điều này cho phép chúng tôi lập bản đồ độc đáo bằng cách sử dụng một Array#mapchức năng ánh xạ:

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

Nơi propscó thể trông giống như { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' }.

Tập hợp tất cả lại với nhau giả sử bạn đã phân tích cú pháp và tải của mình itemTplnhư trên và bạn có một itemsmảng trong phạm vi:

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

Cách tiếp cận này cũng chỉ là jQuery - bạn sẽ có thể thực hiện cách tiếp cận tương tự bằng cách sử dụng vanilla javascript với document.querySelector.innerHTML.

jsfiddle

Các mẫu bên trong JS

Một câu hỏi tự hỏi bản thân là: bạn có thực sự muốn / cần xác định các mẫu dưới dạng tệp HTML không? Bạn luôn có thể cấu phần hóa + sử dụng lại một mẫu giống như cách bạn sử dụng lại hầu hết những thứ bạn muốn lặp lại: với một hàm.

Trong es7-land, bằng cách sử dụng hàm hủy, chuỗi mẫu và hàm mũi tên, bạn có thể viết các hàm thành phần trông rất đẹp và có thể dễ dàng tải bằng $.fn.htmlphương pháp trên.

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

Sau đó, bạn có thể dễ dàng kết xuất nó, thậm chí được ánh xạ từ một mảng, như vậy:

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

Và lưu ý cuối cùng: đừng quên làm sạch các thuộc tính của bạn được chuyển đến một mẫu, nếu chúng được đọc từ DB hoặc ai đó có thể chuyển vào HTML (và sau đó chạy các tập lệnh, v.v.) từ trang của bạn.


1
Công cụ mẫu đẹp.
Arthur Castro

41
Mẫu của bạn bên trong phần JS là quả bom
BigRon

2
Bạn có thể vui lòng thêm một bản demo / fiddle cho cách tiếp cận "Mẫu bên trong HTML" không?
LCJ

1
Chà! Mẫu bên trong JS ... Chưa bao giờ nghĩ đến điều đó! Kinh ngạc!
Roman Lopez

2
Wow, điều này thực sự rất tuyệt. Tôi đang thêm thuộc tính data-url vào mỗi mẫu. Và tìm nạp dữ liệu ajax cho từng cái. Điều này thật tuyệt và tiết kiệm cho tôi rất nhiều thời gian! Cảm ơn bạn.
Davey

42

Sử dụng mẫu HTML để thay thế!

Vì câu trả lời được chấp nhận sẽ đại diện cho phương thức tập lệnh quá tải, tôi muốn đề xuất một phương thức khác, theo ý kiến ​​của tôi, sạch hơn và an toàn hơn nhiều do rủi ro XSS đi kèm với quá tải tập lệnh.

Tôi đã tạo một bản trình diễn để chỉ cho bạn cách sử dụng nó trong một hành động và cách đưa một mẫu này vào một mẫu khác, chỉnh sửa và sau đó thêm vào DOM tài liệu.

html ví dụ

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

ví dụ 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>

  • + Nội dung của nó có hiệu quả trơ cho đến khi được kích hoạt. Về cơ bản, đánh dấu của bạn là DOM ẩn và không hiển thị.

  • + Bất kỳ nội dung nào trong một mẫu sẽ không có tác dụng phụ. Tập lệnh không chạy, hình ảnh không tải, âm thanh không phát ... cho đến khi mẫu được sử dụng.

  • + Nội dung được coi là không có trong tài liệu. Việc sử dụng document.getElementById()hoặc querySelector()trong trang chính sẽ không trả về các nút con của một mẫu.

  • + Mẫu có thể được đặt bất cứ nơi nào bên trong <head>, <body>hay <frameset>và có thể chứa bất kỳ loại nội dung mà được cho phép trong những yếu tố. Lưu ý rằng "mọi nơi" có nghĩa là <template>có thể được sử dụng an toàn ở những nơi mà trình phân tích cú pháp HTML không cho phép.

Lùi lại

Hỗ trợ trình duyệt không phải là một vấn đề nhưng nếu bạn muốn bao gồm tất cả các khả năng, bạn có thể kiểm tra dễ dàng:

Để phát hiện tính năng <template>, hãy tạo phần tử DOM và kiểm tra xem thuộc tính .content có tồn tại không:

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

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

Một số thông tin chi tiết về phương pháp Overloading script

  • + Không có gì được hiển thị - trình duyệt không hiển thị khối này vì <script>thẻ có display:nonetheo mặc định.
  • + Inert - trình duyệt không phân tích cú pháp nội dung tập lệnh dưới dạng JS vì kiểu của nó được đặt thành thứ khác "text/javascript".
  • -Các vấn đề bảo mật - khuyến khích sử dụng .innerHTML. Việc phân tích chuỗi thời gian chạy của dữ liệu do người dùng cung cấp có thể dễ dàng dẫn đến các lỗ hổng XSS.

Toàn bộ bài viết: https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old

Tham khảo hữu ích: https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector

TẠO THÀNH PHẦN WEB Hướng dẫn tạo các thành phần web tùy chỉnh bằng cách sử dụng các mẫu HTML của Trawersy Media: https://youtu.be/PCWaFLy3VUo


4
Phần templatetử này không được Internet Explorer hỗ trợ (kể từ năm 2018, IE11). Đã kiểm tra với ví dụ 580 của w3c.github.io/html/single-page.html .
Roland

Tôi thích <template>, mặc dù tôi khuyên bạn nên sử dụng các lớp một cách tự do, vì vậy rõ ràng những gì đạo cụ đang được đặt thành cái gì. Vẫn cần một số kỹ năng js để ánh xạ dữ liệu của bạn vào mẫu đúng cách, đặc biệt là sử dụng phương pháp tiếp cận kiểu thành phần để ánh xạ trong tập hợp dữ liệu lớn. Cá nhân tôi vẫn thích chỉ xây dựng HTML trong các chức năng, hoặc lý tưởng nhất là xây dựng DOM trực tiếp với chính JS và bỏ HTML hoàn toàn (ví dụ: cách React thực hiện).
Josh từ Qaribou

Phương pháp tiếp cận mẫu hoạt động tốt đối với tôi. Một khuyến nghị tôi có là sao chép mẫu trước (thay vì ở cuối) và làm việc với đối tượng được nhân bản. Nếu không, những thay đổi bạn đang thực hiện đang xảy ra với chính mẫu. Nếu bạn có logic có điều kiện trong đó bạn chỉ đặt một số thuộc tính / nội dung trong một thời gian nào đó, thì những thuộc tính đó sẽ hiện diện trong lần sử dụng mẫu tiếp theo của bạn. Bằng cách sao chép trước mỗi lần sử dụng, bạn đảm bảo rằng bạn luôn có cơ sở nhất quán để làm việc.
jt.

13

Thêm một nơi nào đó trong cơ thể

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

sau đó tạo css

.hide { display: none; }

và thêm vào js của bạn

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

1
OP có JSON và muốn hiển thị một số html bằng cách sử dụng mảng đó làm nguồn dữ liệu. Câu trả lời này giải quyết vấn đề như thế nào? Câu trả lời của bạn có một nút html và sao chép / nhân bản nó và không có gì liên quan đến ràng buộc dữ liệu.
Adrian Iftode

Vì vậy, tôi là người đang tán thành.
Adrian Iftode

Tôi thực sự nghĩ rằng bạn không giúp gì để có được câu trả lời tốt hơn, vì bạn có thể đã bắt đầu bằng việc nhắc nhở chúng tôi rằng vấn đề rộng hơn là những gì được giải quyết bởi các câu trả lời của chúng tôi.
Sebastian Neira

1
Điều này thực sự hiệu quả, nhưng nó hiệu quả hơn để làm .children().clone(), hơn là .html(). Tốc độ khoảng 3: 1 cho một trang ngẫu nhiên <tr/>mà tôi có trên một trang sử dụng mã này i=10000; time=performance.now(); while (--i) {$a.clone().append(0 ? $b.html() : $b.children().clone())} performance.now()-time. Tỷ lệ này thực sự phóng đại hơn một chút vì tôi đang sử dụng $ a.clone (), nhưng việc cố gắng làm trống nó mỗi lần lặp lại mang tính hiệu suất cao hơn là sao chép, vì vậy tôi không chắc làm thế nào để làm cho nó chính xác hơn vì các chức năng thời gian có chi phí riêng.
Chinoto Vokro

1
Aproach này là xấu. chủ yếu là vì bạn tải xuống nội dung mẫu và được phân tích cú pháp ngay cả khi bạn không sử dụng nó. Đây là một vấn đề quá lớn để coi đây là một câu trả lời xác đáng. Cũng như người khác Menthon trên, nếu bạn phải đến ít nhất là bản sao sử dụng thay vì .html ()
DevWL

3

Thay thế khác: Pure

Tôi sử dụng nó và nó đã giúp tôi rất nhiều. Một ví dụ được hiển thị trên trang web của họ:

HTML

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

JSON

{
  "who": "Hello Wrrrld"
}

Kết quả

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

2

Để giải quyết vấn đề này, tôi nhận ra hai giải pháp:

  • Cái đầu tiên đi với AJAX, với đó bạn sẽ phải tải mẫu từ một tệp khác và chỉ cần thêm bất cứ lúc nào bạn muốn .clone().

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

    Hãy lưu ý rằng sự kiện nên được thêm vào khi ajax đã hoàn tất để đảm bảo dữ liệu có sẵn!

  • Cách thứ hai là thêm trực tiếp nó vào bất kỳ đâu trong html gốc, chọn nó và ẩn nó trong jQuery:

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

    Bạn có thể sau khi thêm một phiên bản mới của mẫu với

    $('.search').keyup(function() {
        $('.list-items').html(null);
    
        $.each(items, function(index) {
            $(this).append(temp.clone())
        });
    });
  • Tương tự như phần trước, nhưng nếu bạn không muốn mẫu vẫn ở đó mà chỉ là trong javascript, tôi nghĩ bạn có thể sử dụng (chưa thử nghiệm nó!) .detach()Thay vì ẩn.

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

    .detach() loại bỏ các phần tử khỏi DOM trong khi vẫn giữ cho dữ liệu và sự kiện tồn tại (.remove () thì không!).


- Không có vấn đề! -
iConnor

Op có JSON và muốn hiển thị một số html bằng cách sử dụng mảng đó làm nguồn dữ liệu. Câu trả lời này giải quyết vấn đề như thế nào? Câu trả lời của bạn có một nút html và sao chép / nhân bản nó và không có gì liên quan đến ràng buộc dữ liệu.
Adrian Iftode

1
Tôi trích dẫn từ op: Tôi muốn nối bản sao của mã HTML bên dưới vào phần tử vùng chứa với một số giá trị. Tôi tin rằng điều này giải quyết vấn đề của anh ấy.
Sebastian Neira

Và phần "một số giá trị" được xử lý như thế nào?
Adrian Iftode

Chà, điều đó không có nghĩa là nó không giải quyết được vấn đề. Tôi đánh giá cao việc bạn đã nói với tôi rằng tôi đã thiếu một trong những điểm :) Dù sao, làm thế nào để tôi biết cách chèn những giá trị đó nếu tôi thậm chí không biết chúng ta đang nói về những giá trị nào? Chỉ cần xem phần này Tôi có thể đặt HTML này ở đâu để sử dụng lại một cách thông minh? . Điều gì đang thực sự được hỏi? Giới thiệu về JSON hoặc bao gồm HTML?
Sebastian Neira

1

Câu trả lời rất hay từ DevWL về việc sử dụng phần tử mẫu HTML5 gốc . Để đóng góp cho câu hỏi hay này từ OP, tôi muốn bổ sung thêm về cách sử dụng templatephần tử này bằng jQuery, ví dụ:

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

Nội dung của templatekhông phải là html mà chỉ được coi là dữ liệu, vì vậy bạn cần phải bọc nội dung vào một đối tượng jQuery để sau đó truy cập các phương thức của jQuery.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.