Magento 2: `getTemplate` Nakavt Fonksiyonu Nasıl / Nerede Bağlanır?


19

Birçok Magento arka uç sayfası kaynak kodlarında aşağıdakileri içerir

<!-- ko template: getTemplate() --><!-- /ko -->

<!-- ko templateBir KnockoutJS kapsayıcı şablon bağlama olduğunu anlıyorum (ya da sanırım öyle mi?) .

Benim için net olmayan şey nedir - getTemplate()fonksiyon hangi bağlamda çağrılır? Çevrimiçi gördüğüm örneklerde, genellikle bir javascript nesnesi vardır template:. Ben getTemplatebir nesne döndüren bir javascript işlevi olduğunu varsayalım - ama adlı genel javascript işlevi yoktur getTemplate.

Nereye getTemplatebağlı? Veya, muhtemelen daha iyi bir soru, KnockoutJS uygulama bağlama Magento arka uç sayfasında nerede olur?

Ben saf bir HTML / CSS / Javascript bakış açısıyla ilgileniyorum. Magento 2'nin birçok yapılandırma soyutlaması olduğunu biliyorum, bu nedenle (teoride) geliştiricilerin uygulama ayrıntıları hakkında endişelenmesine gerek yok. Uygulama ayrıntılarıyla ilgileniyorum.

Yanıtlar:


38

Bir UI bileşeninin PHP kodu şuna benzeyen bir javascript başlatması oluşturur

<script type="text/x-magento-init">
    {
        "*": {
            "Magento_Ui/js/core/app":{
                "types":{...},
                "components":{...},
            }
        }
    }
</script>       

Sayfadaki bu kod biti, Magento'nun Magento_Ui/js/core/appbir geri çağrı almak için RequireJS modülünü çağıracağı ve sonra {types:..., components:...}JSON nesnesine argüman olarak geçen bu geri çağrıyı çağıracağı anlamına gelir ( dataaşağıda)

#File: vendor/magento/module-ui/view/base/web/js/core/app.js
define([
    './renderer/types',
    './renderer/layout',
    'Magento_Ui/js/lib/ko/initialize'
], function (types, layout) {
    'use strict';

    return function (data) {
        types.set(data.types);
        layout(data.components);
    };
});

Veri nesnesi , UI bileşenini oluşturmak için gereken tüm verilerin yanı sıra belirli dizeleri belirli Magento RequireJS modüllerine bağlayan bir yapılandırma içerir. Bu eşleme typesve layoutRequireJS modüllerinde gerçekleşir. Uygulama ayrıca Magento_Ui/js/lib/ko/initializeRequireJS kitaplığını yükler . initializeMagento'nın KnockoutJS entegrasyonu kapalı modül devreye giriyor.

/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
/** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */

#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js
define([
    'ko',
    './template/engine',
    'knockoutjs/knockout-repeat',
    'knockoutjs/knockout-fast-foreach',
    'knockoutjs/knockout-es5',
    './bind/scope',
    './bind/staticChecked',
    './bind/datepicker',
    './bind/outer_click',
    './bind/keyboard',
    './bind/optgroup',
    './bind/fadeVisible',
    './bind/mage-init',
    './bind/after-render',
    './bind/i18n',
    './bind/collapsible',
    './bind/autoselect',
    './extender/observable_array',
    './extender/bound-nodes'
], function (ko, templateEngine) {
    'use strict';

    ko.setTemplateEngine(templateEngine);
    ko.applyBindings();
});

Her bir bind/...RequireJS modülü , Nakavt için tek bir özel ciltleme kurar .

extender/...RequireJS modülleri yerli KnockoutJS nesnelere bazı yardımcı yöntemler ekleyin.

Magento, Knockout'un javascript şablon motorunun ./template/engineRequireJS modülündeki işlevselliğini de genişletir .

Sonunda Magento applyBindings(), KnockoutJS nesnesini çağırır . Bu genellikle bir Nakavt programının bir görünüm modelini HTML sayfasına bağlayacağı yerdir; ancak Magento, görünüm modeli applyBindings olmadan çağrı yapar . Bu, Nakavt'ın bir görünüm olarak sayfayı işlemeye başlayacağı, ancak veri bağlı olmadığı anlamına gelir.

Bir nakavt kurulumunda, bu biraz aptalca olurdu. Bununla birlikte, daha önce bahsedilen özel Nakavt ciltleri nedeniyle, Nakavt'ın bir şeyler yapması için birçok fırsat var.

Kapsam bağlayıcılığıyla ilgileniyoruz . Bunu, PHP UI Bileşen sistemi tarafından da oluşturulan bu HTML'de görebilirsiniz.

<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
    <div data-role="spinner" data-component="customer_listing.customer_listing.customer_columns" class="admin__data-grid-loading-mask">
        <div class="spinner">
            <span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
        </div>
    </div>
    <!-- ko template: getTemplate() --><!-- /ko -->
    <script type="text/x-magento-init">
    </script>
</div>

Özellikle, data-bind="scope: 'customer_listing.customer_listing'">öznitelik. Magento başladığında applyBindings, Nakavt bu özel scopebağlayıcıyı ./bind/scopegörür ve RequireJS modülünü çağırır . Özel bir bağlayıcı uygulama yeteneği saf KnockoutJS'dir. Uygulama bağlayıcı kapsamı şey Magento Inc. yapmış olduğunu.

Kapsam bağlayıcısının uygulanması

#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js

Bu dosyadaki önemli kısım burada

var component = valueAccessor(),
    apply = applyComponents.bind(this, el, bindingContext);

if (typeof component === 'string') {
    registry.get(component, apply);
} else if (typeof component === 'function') {
    component(apply);
}

Ayrıntılara fazla girilmeden, registry.getyöntem, componentdeğişken içindeki dizeyi tanımlayıcı olarak kullanarak önceden oluşturulmuş bir nesneyi çıkarır applyComponentsve üçüncü parametre olarak yönteme iletir. Dize tanımlayıcı değeri scope:( customer_listing.customer_listingyukarıda)

İçinde applyComponents

function applyComponents(el, bindingContext, component) {
    component = bindingContext.createChildContext(component);

    ko.utils.extend(component, {
        $t: i18n
    });

    ko.utils.arrayForEach(el.childNodes, ko.cleanNode);

    ko.applyBindingsToDescendants(component, el);
}

çağrısı createChildContext, esasen, halihazırda başlatılmış bileşen nesnesine dayanan yeni bir viewModel nesnesinin ne olduğunu oluşturur ve bunu divkullanılan orijinalin tüm alt öğelerine uygular data-bind=scope:.

Peki, zaten somutlaştırılmış bileşen nesnesi nedir? layoutGeri çağrıyı hatırlıyor app.jsmusunuz?

#File: vendor/magento/module-ui/view/base/web/js/core/app.js

layout(data.components);

layoutİşlev / modül içinde geçirilen içine inecek data.components(yine, bu veriler ile geçirilen nesneden gelir text/x-magento-init). Bulduğu her nesne için bir confignesne arayacak ve bu yapılandırma nesnesinde bir componentanahtar arayacaktır . Bir bileşen anahtarı bulursa,

  1. RequireJSBir modül örneğini döndürmek için kullanın - modül bir requirejs/ definebağımlılıkta çağrılmış gibi .

  2. Bu modül örneğini javascript yapıcısı olarak adlandırın

  3. Ortaya çıkan nesneyi registrynesne / modülde saklayın

Bu, alınması gereken çok şey. İşte hızlı bir inceleme, kullanarak

<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
    <div data-role="spinner" data-component="customer_listing.customer_listing.customer_columns" class="admin__data-grid-loading-mask">
        <div class="spinner">
            <span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
        </div>
    </div>
    <!-- ko template: getTemplate() --><!-- /ko -->
    <script type="text/x-magento-init">
    </script>
</div>

başlangıç ​​noktası olarak. scopeDeğerdir customer_listing.customer_listing.

text/x-magento-initBaşlatmadan JSON nesnesine bakarsak

{
    "*": {
        "Magento_Ui/js/core/app": {
            /* snip */
            "components": {
                "customer_listing": {
                    "children": {
                        "customer_listing": {
                            "type": "customer_listing",
                            "name": "customer_listing",
                            "children": /* snip */
                            "config": {
                                "component": "uiComponent"
                            }
                        },
                        /* snip */
                    }
                }
            }
        }
    }
}

components.customer_listing.customer_listingNesnenin bir confignesnesi olduğunu ve bu yapılandırma nesnesinin olarak componentayarlanmış bir nesnesi olduğunu görüyoruz uiComponent. uiComponentDize RequireJS modülüdür. Aslında, Magento_Ui/js/lib/core/collectionmodüle karşılık gelen bir RequireJS diğer adı .

vendor/magento/module-ui/view/base/requirejs-config.js
14:            uiComponent:    'Magento_Ui/js/lib/core/collection',

İçinde layout.js, Magento aşağıdakine eşdeğer bir çalışma kodu var.

//The actual code is a bit more complicated because it
//involves jQuery's promises. This is already a complicated 
//enough explanation without heading down that path

require(['Magento_Ui/js/lib/core/collection'], function (collection) {    
    object = new collection({/*data from x-magento-init*/})
}

Gerçekten merak uyandırmak için, toplama modeline bakarsanız ve yürütme yolunu izlerseniz collection, bunun hem lib/core/element/elementmodül hem de modül tarafından geliştirilmiş bir javascript nesnesi olduğunu keşfedeceksiniz lib/core/class. Bu özelleştirmeleri araştırmak bu cevabın kapsamı dışındadır.

Bir kez başlatıldığında, layout.jsbunu objectkayıt defterinde saklar . Bu, Nakavt ciltleri işlemeye başladığında ve özel scopeciltleme ile karşılaştığında

<div class="admin__data-grid-outer-wrap" data-bind="scope: 'customer_listing.customer_listing'">
    <!-- snip -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- snip -->
</div>

Magento bu nesneyi kayıt defterinden geri getirecek ve içindeki şeyler için görünüm modeli olarak bağlayacaktır div. Başka bir deyişle, getTemplateNakavt etiketsiz bağlayıcıyı ( <!-- ko template: getTemplate() --><!-- /ko -->) çağırdığında çağrılan getTemplateyöntem new collectionnesnedeki yöntemdir .


1
Sadece cevabınıza 'neden' sorusunu sormaktan nefret ediyorum, bu yüzden daha odaklanmış bir soru olurdu, M2 bu (görünüşte kıvrık) sistemi kullanarak KO şablonlarını çağırmak için ne kazanır?
circlesix

1
@circlesix <uiComponents/>Düzen XML sisteminden oluşturma için daha büyük bir sistemin parçası . Aldıkları faydalar, farklı bir etiket kümesi için aynı sayfada görünüm modellerini değiştirme yeteneğidir.
Alan Storm

16
Ağlamak mı ağlamak mı bilmiyorum! Ne dağınıklık.
koosa

8
Bence kendi mezarlarını kazıyorlar. Böyle şeyleri karmaşık hale
getirmeye

2
Ben sadece özel bir davranış tüm bu "büyü" tarafından oluşturulan bir forma bağlamak için nasıl anlamaya çalışırken yaklaşık 5 saat harcamak. Sorunun bir kısmı, bu son derece genel çerçevenin, bir şeyleri nasıl yapacağınızı anlama şansınız olana kadar bir ton katmandan geçmenizi gerektirmesidir. Ayrıca belirli bir yapılandırmanın nereden geldiğini izlemek inanılmaz derecede yorucu hale gelir.
greenone83

12

Nakavt JS şablonlarından herhangi birinin bağlanması, modülün .xml dosyalarında gerçekleşir. Checkout modülünü örnek olarak kullanarak contentşablonun yapılandırmasını şurada bulabilirsiniz :vendor/magento/module-checkout/view/frontend/layout/default.xml

<block class="Magento\Checkout\Block\Cart\Sidebar" name="minicart" as="minicart" after="logo" template="cart/minicart.phtml">
    <arguments>
        <argument name="jsLayout" xsi:type="array">
            <item name="types" xsi:type="array"/>
                <item name="components" xsi:type="array">
                    <item name="minicart_content" xsi:type="array">
                        <item name="component" xsi:type="string">Magento_Checkout/js/view/minicart</item>
                            <item name="config" xsi:type="array">
                                <item name="template" xsi:type="string">Magento_Checkout/minicart/content</item>
                            </item>

Bu dosyada blok sınıfının "jsLayout" u tanımlayan ve çağıran düğümleri olduğunu görebilirsiniz <item name="minicart_content" xsi:type="array">. Biraz yuvarlak bir mantık robinidir, ama içerideyseniz vendor/magento/module-checkout/view/frontend/templates/cart/minicart.phtmlbu satırı göreceksiniz:

<div id="minicart-content-wrapper" data-bind="scope: 'minicart_content'">
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

Yani veri bağlamak nerede var bu durumda, herhangi bir iç içe şablona aramaya yönlendiren Magento_Checkout/js/view/minicartbir vendor/magento/module-checkout/view/frontend/web/js/view/minicart.jsmantık için (veya OG knock-out Model-View-View Modeli sistem içinde) ve sahip Magento_Checkout/minicart/content(veya knock-out Model-View-View Modeli V sistemi). Yani bu noktada çekilmekte olan şablon vendor/magento/module-checkout/view/frontend/web/template/minicart/content.html.

Gerçekten .xml'lere bakmaya alıştıktan sonra bunu anlamak zor değil. Bunların çoğunu , kırık İngilizceyi geçebilirseniz burada öğrendim . Ama şimdiye kadar Nakavt entegrasyonu M2'nin en az belgelenmiş kısmı gibi hissediyorum.


2
Yararlı bilgi, yani +1, ama soru başına Magento'nun bununla başa çıkmak için soyutlamalar olduğunu biliyorum - ama uygulama ayrıntılarını kendileri merak ediyorum. ie - bu XML dosyasında bir şey yapılandırdığınızda, magento yapılandırılmış değerlerinizin üçüncü bir şey yaptığından emin olmak için başka bir şey yapar . Başka bir şeyle ve üçüncü şeyle ilgileniyorum.
Alan Storm

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.