마 젠토 2 : ‘getTemplate’녹아웃 함수 바운드는 어떻게 / 어디에 있습니까? getTemplate() –><!– /ko

많은 Magento 백엔드 페이지는 소스 코드에 다음을 포함합니다.

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

<!-- ko templateKnockoutJS 컨테이너리스 템플릿 바인딩 인 것을 이해합니다 (또는 생각합니까?) .

나에게 분명하지 않은 것은- getTemplate()함수 가 어떤 맥락 에서 호출됩니까? 온라인에서 본 예제에는 일반적으로. 다음에 자바 스크립트 객체가 template:있습니다. getTemplate객체를 반환하는 자바 스크립트 함수 라고 가정 하지만 전역 자바 스크립트 함수는 없습니다 getTemplate.

getTemplate묶인 곳은 어디 입니까? 아니면 Magento 백엔드 페이지에서 KnockoutJS 응용 프로그램 바인딩이 어디서 발생합니까?

순수한 HTML / CSS / Javascript 관점에서 이것에 관심이 있습니다. Magento 2에는 많은 구성 추상화가 있으므로 이론적으로 개발자는 구현 세부 정보에 대해 걱정할 필요가 없습니다. 구현 세부 사항에 관심이 있습니다.



답변

UI 구성 요소의 PHP 코드는 다음과 같은 자바 스크립트 초기화를 렌더링합니다.

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

이 페이지의이 코드는 Magento가 Magento_Ui/js/core/appRequireJS 모듈을 호출하여 콜백을 가져온 다음 {types:..., components:...}JSON 객체를 전달하는 콜백을 인수로 호출합니다 ( data아래).

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

데이터 개체에는 UI 구성 요소를 렌더링하는 데 필요한 모든 데이터 와 특정 문자열을 특정 Magento RequireJS 모듈과 연결하는 구성이 포함됩니다. 즉, 매핑은에서 발생 types하고 layoutRequireJS 모듈. 응용 프로그램은 Magento_Ui/js/lib/ko/initializeRequireJS 라이브러리 도로드합니다 . 이 initialize모듈은 Magento의 KnockoutJS 통합을 시작합니다.

/**
 * 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();
});

각 개별 bind/...RequireJS 모듈은 녹아웃에 대한 단일 사용자 정의 바인딩 을 설정합니다 .

extender/...RequireJS 모듈은 기본 KnockoutJS 객체에 몇 가지 도우미 메서드를 추가합니다.

Magento는 또한 ./template/engineRequireJS 모듈 에서 Knockout의 자바 스크립트 템플릿 엔진 기능을 확장합니다 .

마지막으로 Magento applyBindings()는 KnockoutJS 객체를 호출 합니다. 일반적으로 Knockout 프로그램은 뷰 모델을 HTML 페이지에 바인딩하지만 Magento 는 뷰 모델 applyBindings 없이 호출합니다 . 즉, 녹아웃은 페이지를보기로 처리하기 시작하지만 데이터가 바인딩되지 않습니다.

스톡 녹아웃 설정에서는 약간 어리 석습니다. 그러나 앞에서 언급 한 사용자 정의 녹아웃 바인딩으로 인해 녹아웃이 작업을 수행 할 수있는 많은 기회가 있습니다.

범위 바인딩에 관심이 있습니다. 이 HTML에서 PHP UI 구성 요소 시스템으로 렌더링 된 것을 볼 수 있습니다.

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

특히 data-bind="scope: 'customer_listing.customer_listing'">속성입니다. Magento가 시작 applyBindings되면 Knockout은이 사용자 정의 scope바인딩 을보고 ./bind/scopeRequireJS 모듈을 호출합니다 . 사용자 정의 바인딩을 적용하는 기능은 순수 KnockoutJS입니다. 범위 바인딩 의 구현 은 Magento Inc.가 수행 한 것입니다.

범위 바인딩의 구현은

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

이 파일의 중요한 부분은 여기

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

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

세부 정보에 너무 많이 들어 가지 않으면 registry.get메서드는 component변수 의 문자열을 식별자로 사용하여 이미 생성 된 개체를 가져 와서 applyComponents세 번째 매개 변수로 메서드에 전달합니다 . 문자열 식별자는 scope:( customer_listing.customer_listing위) 의 값입니다.

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

를 호출 createChildContext하면 이미 인스턴스화 된 컴포넌트 객체를 기반으로 본질적으로 새로운 viewModel 객체를 생성 한 다음 div사용 된 원본의 모든 하위 요소에 적용합니다 data-bind=scope:.

그렇다면 이미 인스턴스화 된 구성 요소 객체는 무엇입니까? layout다시 전화를 기억 app.js하십니까?

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

layout(data.components);

layout기능 / 모듈로 하강 전달한다 data.components(또,이 데이터를 통해 전달 된 객체로부터 온다 text/x-magento-init). 찾은 각 객체에 대해 객체를 찾고 config해당 구성 객체에서 component키를 찾습니다 . 구성 요소 키를 찾으면

  1. RequireJS모듈이 requirejs/ define종속성 에서 호출 된 것처럼 모듈 인스턴스를 반환하는 데 사용하십시오 .

  2. 해당 모듈 인스턴스 를 자바 스크립트 생성자로 호출

  3. 결과 객체를 registry객체 / 모듈에 저장

그래서, 그것은 많이 받아 들일 것입니다. 다음은

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

출발점으로. scope값입니다 customer_listing.customer_listing.

text/x-magento-init초기화 에서 JSON 객체를 보면

{
    "*": {
        "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_listing객체가이 config객체를, 그 구성 객체는이 component에 설정되어 개체를 uiComponent. uiComponent문자열은 RequireJS 모듈입니다. 실제로 Magento_Ui/js/lib/core/collection모듈에 해당하는 RequireJS 별명입니다 .

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

에서가 layout.js, 마 젠토는 다음에 해당되는 코드를 실행하고있다.

//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*/})
}

정말 궁금한 점은 컬렉션 모델을 살펴보고 실행 경로 collection를 따르면 lib/core/element/element모듈과 모듈 모두에서 향상 된 자바 스크립트 객체라는 것을 알 수 lib/core/class있습니다. 이러한 사용자 정의 연구는이 답변의 범위를 벗어납니다.

인스턴스화되면 layout.jsobject를 레지스트리에 저장하십시오 . 이는 녹아웃이 바인딩 처리를 시작하고 사용자 정의 scope바인딩이 발생하는 시점을 의미합니다.

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

Magento는이 객체를 레지스트리에서 다시 가져 와서 객체 내부의 뷰 모델로 바인딩합니다 div. 즉, getTemplateKnockout이 태그없는 바인딩 ( <!-- ko template: getTemplate() --><!-- /ko -->)을 호출 할 때 호출 되는 getTemplate메소드는 new collection객체 의 메소드입니다 .


답변

녹아웃 JS 템플릿에 대한 바인딩은 모듈의 .xml 파일에서 발생합니다. Checkout 모듈을 예로 들어 content템플릿 의 구성을 찾을 수 있습니다 .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>

이 파일에서 블록 클래스에 “jsLayout”을 정의하고를 호출하는 노드가 있음을 알 수 있습니다 <item name="minicart_content" xsi:type="array">. 그것은 약간의 논리의 로빈이지만, 당신이 있다면 vendor/magento/module-checkout/view/frontend/templates/cart/minicart.phtml이 줄을 볼 수 있습니다 :

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

따라서 데이터 바인딩 곳이있어이 경우, 중첩 된 템플릿을 찾아하는 지시 Magento_Checkout/js/view/minicartvendor/magento/module-checkout/view/frontend/web/js/view/minicart.js논리에 대해 (또는 MV 녹아웃 모델 – 뷰 – 뷰 모델 시스템) 및 당신이 Magento_Checkout/minicart/content(또는 녹아웃 모델 – 뷰 – 뷰 모델에 V 템플릿 호출). 이 지점에서 가져 오는 템플릿은 vendor/magento/module-checkout/view/frontend/web/template/minicart/content.html입니다.

실제로 .xml을 살펴 보는 데 익숙해지면 어렵지 않습니다. 이 중 대부분은 깨진 영어를 지나칠 수 있다면 여기서 배웠습니다 . 그러나 지금까지 나는 녹아웃 통합이 M2에서 가장 적게 문서화 된 부분이라고 생각합니다.


답변

나는 확실히 꽤있어 글로벌 getTemplate 당신이 아래에 정의되어 찾고있는 JS 방법 app/code/Magento/Ui/view/base/web/js/lib/core/element/element.js여기를 찾을 수 있습니다 : https://github.com/magento/magento2/blob/4d71bb4780625dce23274c90e45788a72f345dd9/app/code/Magento/Ui/view/base /web/js/lib/core/element/element.js#L262

전화를 걸었을 때 바인딩이 정확히 어떻게 수행되는지 알아내는 데 어려움을 겪고 있습니다.