Magento 2: Apa itu Tag `<setiap />`?

13

Sejauh yang saya tahu, ketika Anda melihat Grid di backend Magento, berikut "dimuat lebih dari XHR" template KnockoutJS adalah apa yang mulai membuat hal-hal

File: vendor/magento//module-ui/view/base/web/templates/collection.html
URL:  http://magento.example.xom/pub/static/adminhtml/Magento/backend/en_US/Magento_Ui/templates/collection.html
<each args="data: elems, as: 'element'">
    <render if="hasTemplate()"/>
</each>

Namun - saya sedikit bingung tentang apa <each/>tag dan <render/>tag itu. Mereka bukan (atau tampaknya bukan?) Bagian dari KnockoutJS saham.

Saya tahu ini mungkin untuk menambahkan tag khusus ke KnockoutJS melalui komponen , tapi saya tidak melihat tempat yang jelas di mana komponen bernama eachatau renderditambahkan ke KnockoutJS.

Jadi, saya tidak yakin apakah ini adalah komponen yang terdaftar di suatu tempat yang tidak saya sadari, atau kustomisasi lain yang telah dilakukan Magento untuk KnockoutJS yang memungkinkan tag khusus, atau sesuatu yang lain sama sekali.

Catatan: Saya tidak sepenuhnya dalam kegelapan di sini - saya mengerti bahwa <each/>itu mungkin berulang atas setiap komponen ui anak yang dirender dalam JSON, dan merender templatnya (jika templat itu ada).

Yang saya tidak jelas sama sekali adalah bagaimana tag ini diterapkan. Saya ingin melihat di mana mereka diterapkan sehingga saya bisa men-debug bagaimana data terikat, dan juga memahami mekanisme yang digunakan Magento untuk membuat tag ini jika ada yang lain.

Alan Storm
sumber

Jawaban:

10

Seperti yang ditunjukkan oleh Raphael , ternyata ketika Magento mengunduh templat KnockoutJS-nya melalui permintaan XHR (yaitu ajax), ia juga melewati mereka melalui beberapa rutin penguraian khusus yang mencari sejumlah tag dan atribut khusus.

Penguraian khusus ini dilakukan oleh Magento_Ui/js/lib/knockout/template/renderermodul RequireJS. Kode sumber modul ini mengatur sejumlah tag dan atribut default untuk dicari. Ada juga modul lain yang dapat menambahkan tag dan atribut tambahan ke renderer ini. Misalnya berikut ini

#File: vendor/magento/module-ui/view/base/web/js/lib/knockout/bindings/scope.js
renderer
    .addNode('scope')
    .addAttribute('scope', {
        name: 'ko-scope'
    });

akan menambahkan <scope/>tag dan scopeatribut ( <div scope="...">) ke daftar atribut yang dapat diuraikan.

Apakah tampaknya seperti ide dasarnya adalah untuk menerjemahkan tag dan atribut ke Knockout "tagless" blok Template asli. Misalnya, templat Magento KnockoutJS berikut

<each args="data: elems, as: 'element'">
    <render if="hasTemplate()"/>
</each>

Diterjemahkan ke dalam kode KnockoutJS asli berikut

<!-- ko foreach: {data: elems, as: 'element'} -->
    <!-- ko if: hasTemplate() --><!-- ko template: getTemplate() --><!-- /ko --><!-- /ko -->
<!-- /ko -->

Aturan pasti dari terjemahan ini masih belum jelas bagi saya - kode dalam Magento_Ui/js/lib/knockout/template/renderersedikit tidak langsung, dan sepertinya mereka dapat berubah dari tag ke tag, atribut ke atribut.

Saya telah membuat potongan kode berikut yang dapat mengunduh template Magento KnockoutJS, dan menerjemahkannya ke dalam kode KnockoutJS asli.

jQuery.get('http://magento-2-1-0.dev/static/adminhtml/Magento/backend/en_US/Magento_Ui/templates/collection.html', function(result){
    var renderer = requirejs('Magento_Ui/js/lib/knockout/template/renderer')
    var fragment = document.createDocumentFragment();
    $(fragment).append(result);

    //fragment is passed by reference, modified
    renderer.normalize(fragment);
    var string = new XMLSerializer().serializeToString(fragment);
    console.log(string);    
})

Mengenai mengapa Magento mungkin melakukan ini - tebakan saya menginginkan semacam penyorotan sintaksis dan keterbacaan untuk template komentar KnockoutJS, tetapi jangan pernah mengesampingkan alasan Mallory-ish lainnya .

Alan Storm
sumber
2

Kedua tag diimplementasikan di bawah app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js, saya tidak terlalu yakin untuk memahami persis bagaimana penerapannya:

_.extend(preset.nodes, {
    foreach: {
        name: 'each'
    },

    /**
     * Custom 'render' node handler function.
     * Replaces node with knockout's 'ko template:' comment tag.
     *
     * @param {HTMLElement} node - Element to be processed.
     * @param {String} data - Data specified in 'args' attribute of a node.
     */
    render: function (node, data) {
        data = data || 'getTemplate()';
        data = renderer.wrapArgs(data);

        renderer.wrapNode(node, 'template', data);
        $(node).replaceWith(node.childNodes);
    }
});
Raphael di Digital Pianism
sumber