Magento 2: Что такое тег <each />?

13

Насколько я могу судить, когда вы просматриваете Grid в бэкенде Magento, следующий шаблон KnockoutJS «загружен поверх XHR» - это то, что начинает рендерить вещи

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>

Однако - я немного растерялся относительно того, что такое <each/>тег и <render/>тег. Они не являются (или не являются?) Частью акции KnockoutJS.

Я знаю, что можно добавлять пользовательские теги в KnockoutJS через компоненты , но я не вижу очевидных мест, где компонент назван eachили renderдобавлен в KnockoutJS.

Итак, я не уверен, что это компоненты, зарегистрированные где-то, о которых я не знаю, или какая-то другая настройка, которую Magento сделал для KnockoutJS, которая включает пользовательские теги, или что-то еще полностью.

Примечание: я здесь не совсем в темноте - я понимаю, что <each/>, вероятно , выполняется итерация по каждому дочернему компоненту пользовательского интерфейса, отображаемому в JSON, и визуализация его шаблона (если этот шаблон существует).

Я не совсем понимаю, как реализованы эти теги. Я хочу посмотреть, где они реализованы, чтобы я мог отладить, как связаны данные, а также понять механизм, который Magento использует для создания этих тегов, если есть другие.

Алан Сторм
источник

Ответы:

10

Как намекал Рафаэль , оказывается, что когда Magento загружает свои шаблоны KnockoutJS через запрос XHR (т.е. ajax), он также пропускает их через некоторые пользовательские процедуры синтаксического анализа, которые ищут ряд пользовательских тегов и атрибутов.

Этот пользовательский анализ выполняется Magento_Ui/js/lib/knockout/template/rendererмодулем RequireJS. Исходный код этого модуля устанавливает ряд тегов и атрибутов по умолчанию для поиска. Существуют также другие модули, которые могут добавлять дополнительные теги и атрибуты для этого средства визуализации. Например, следующее

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

добавит <scope/>тег и scopeattribute ( <div scope="...">) в список разбираемых атрибутов.

Есть кажется, основная идея заключается в том, чтобы перевести эти теги и атрибуты в родные «tagless» шаблонные блоки Knockout. Например, следующий шаблон Magento KnockoutJS

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

Переводит в следующий родной код KnockoutJS

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

Точные правила этого перевода мне до сих пор неясны - код Magento_Ui/js/lib/knockout/template/rendererнемного косвенный, и кажется, что они могут меняться от тега к тегу, атрибута к атрибуту.

Я создал следующий фрагмент кода, который может загрузить шаблон Magento KnockoutJS и перевести его на собственный код KnockoutJS.

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);    
})

Что касается того, почему Magento может сделать это - я думаю, что мне нужна какая-то подсветка синтаксиса и удобочитаемость для шаблона комментариев KnockoutJS, но никогда не исключаю больше причин Мэллори .

Алан Сторм
источник
2

Оба тега реализованы в app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js, я не слишком уверен, чтобы понять, как именно они реализованы, хотя:

_.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);
    }
});
Рафаэль в цифровом пианизме
источник