Magento 2: Thẻ `<mỗi />` là gì?


13

Gần như tôi có thể nói, khi bạn xem Lưới trong phần phụ trợ của Magento, mẫu KnockoutJS "được tải qua XHR" sau đây là thứ bắt đầu hiển thị mọi thứ

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>

Tuy nhiên - tôi hơi mất công về việc <each/>thẻ và <render/>thẻ là gì. Họ không (hoặc dường như không phải là?) Một phần của cổ phiếu KnockoutJS.

Tôi biết có thể thêm các thẻ tùy chỉnh vào KnockoutJS thông qua các thành phần , nhưng tôi không thấy bất kỳ vị trí rõ ràng nào có thành phần được đặt tên eachhoặc renderđược thêm vào KnockoutJS.

Vì vậy, tôi không chắc đây là những thành phần được đăng ký ở đâu đó mà tôi không biết hoặc một số tùy chỉnh khác mà Magento đã thực hiện cho KnockoutJS cho phép các thẻ tùy chỉnh hoặc hoàn toàn khác.

Lưu ý: Tôi không hoàn toàn chìm trong bóng tối ở đây - Tôi hiểu rằng <each/>có lẽ nó đang lặp lại trên mọi thành phần ui con được hiển thị trong JSON và hiển thị mẫu của nó (nếu mẫu đó tồn tại).

Điều tôi không rõ ràng ở tất cả là cách các thẻ này được thực hiện. Tôi muốn xem nơi chúng được triển khai để tôi có thể gỡ lỗi cách dữ liệu bị ràng buộc và cũng hiểu cơ chế mà Magento đang sử dụng để tạo các thẻ này trong trường hợp có các thẻ khác.

Câu trả lời:


10

Như Raphael đã gợi ý, hóa ra khi Magento tải xuống các mẫu KnockoutJS của mình thông qua yêu cầu XHR (tức là ajax), nó cũng chuyển chúng qua một số thói quen phân tích tùy chỉnh tìm kiếm một số thẻ và thuộc tính tùy chỉnh

Phân tích cú pháp tùy chỉnh này được thực hiện bởi Magento_Ui/js/lib/knockout/template/renderermô-đun RequireJS. Mã nguồn của mô-đun này thiết lập một số thẻ và thuộc tính mặc định để tìm kiếm. Ngoài ra còn có các mô-đun khác có thể thêm các thẻ và thuộc tính bổ sung cho trình kết xuất này. Ví dụ như sau

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

sẽ thêm <scope/>thẻ và scopethuộc tính ( <div scope="...">) vào danh sách các thuộc tính có thể phân tích cú pháp.

vẻ như ý tưởng cơ bản là dịch các thẻ và thuộc tính này thành các khối mẫu "không có thẻ" Knockout. Ví dụ: mẫu Magento KnockoutJS sau đây

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

Dịch sang mã KnockoutJS riêng sau đây

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

Các quy tắc chính xác của bản dịch này vẫn chưa rõ ràng đối với tôi - mã trong Magento_Ui/js/lib/knockout/template/renderercó một chút gián tiếp và có vẻ như chúng có thể thay đổi từ thẻ này sang thẻ, thuộc tính sang thuộc tính.

Tôi đã tìm ra đoạn mã sau có thể tải xuống mẫu Magento KnockoutJS và dịch nó sang mã KnockoutJS bản địa.

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

Về lý do Magento có thể làm điều này - tôi đoán là muốn một số loại cú pháp tô sáng và dễ đọc cho mẫu nhận xét của KnockoutJS, nhưng không bao giờ loại trừ thêm lý do Mallory-ish .


2

Cả hai thẻ đều được triển khai bên dưới app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js, tôi không chắc chắn hiểu chính xác cách chúng được triển khai:

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