Как работает часть knockout-js


Я все еще не понял, как Magento 2 структурирует нокаутирующую часть js.

Например, как работает процесс (шаг за шагом) получения сводного номера корзины. Вы можете найти это в app/code/Magento/Checkout/view/frontend/templates/cart/minicart.phtml:

<span class="counter qty empty"
          data-bind="css: { empty: !!getCartParam('summary_count') == false }, blockLoader: isLoading">
        <span class="counter-number"><!-- ko text: getCartParam('summary_count') --><!-- /ko --></span>
        <span class="counter-label">
        <!-- ko if: getCartParam('summary_count') -->
            <!-- ko text: getCartParam('summary_count') --><!-- /ko -->
            <!-- ko i18n: 'items' --><!-- /ko -->
        <!-- /ko -->
        </span>
    </span>

Вопрос в том, как бы я нашел весь код js, php (,html), который используется для получения номера summary_count.

Я нашел minicart.js, но summary_count там нигде не видно. Я подозреваю, что это какой-то идентификатор, который присваивается функции getCartParam. Но я тоже не могу найти getCartParam.

Другим примером может быть, например, проверка на странице: Я могу найти все шаблоны для соответствующих шагов, таких как shipping.html или payment.html. Но как они объединяются? Где они загружены и что определяет ie. приказ?

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

Некоторые просветление было бы здесь здорово!

Author: steros, 2017-03-28

2 answers

К сожалению, я не могу вставить содержимое (оно все равно слишком обширное), поэтому я могу просто дать ссылку.

Я обнаружил, что Алан Шторм написал серию статей, в которых он объясняет концепции Javascript в Magento 2. Если вы прочтете этот ответ, вы, надеюсь, все еще найдете его здесь:

Http://alanstorm.com/category/magento-2/#magento2-advanced-javascript

С информацией сверху я пытаюсь проанализировать, что происходит (не стесняйтесь добавлять любую информацию для уточнения вещи или поправьте меня):

На самом деле кода в вопросе недостаточно для его анализа. Давайте посмотрим на весь код целиком.

<?php
/**
 * Copyright © 2013-2017 Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

/** @var $block \Magento\Checkout\Block\Cart\Sidebar */
?>

<div data-block="minicart" class="minicart-wrapper">
    <a class="action showcart" href="<?php /* @escapeNotVerified */ echo $block->getShoppingCartUrl(); ?>"
       data-bind="scope: 'minicart_content'">
        <span class="text"><?php /* @escapeNotVerified */ echo __('My Cart'); ?></span>
        <span class="counter qty empty"
              data-bind="css: { empty: !!getCartParam('summary_count') == false }, blockLoader: isLoading">
            <span class="counter-number"><!-- ko text: getCartParam('summary_count') --><!-- /ko --></span>
            <span class="counter-label">
            <!-- ko if: getCartParam('summary_count') -->
                <!-- ko text: getCartParam('summary_count') --><!-- /ko -->
                <!-- ko i18n: 'items' --><!-- /ko -->
            <!-- /ko -->
            </span>
        </span>
    </a>
    <?php if ($block->getIsNeedToDisplaySideBar()): ?>
        <div class="block block-minicart empty"
             data-role="dropdownDialog"
             data-mage-init='{"dropdownDialog":{
                "appendTo":"[data-block=minicart]",
                "triggerTarget":".showcart",
                "timeout": "2000",
                "closeOnMouseLeave": false,
                "closeOnEscape": true,
                "triggerClass":"active",
                "parentClass":"active",
                "buttons":[]}}'>
            <div id="minicart-content-wrapper" data-bind="scope: 'minicart_content'">
                <!-- ko template: getTemplate() --><!-- /ko -->
            </div>
            <?php echo $block->getChildHtml('minicart.addons'); ?>
        </div>
    <?php endif ?>
    <script>
        window.checkout = <?php /* @escapeNotVerified */ echo \Zend_Json::encode($block->getConfig()); ?>;
    </script>
    <script type="text/x-magento-init">
    {
        "[data-block='minicart']": {
            "Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
        },
        "*": {
            "Magento_Ui/js/block-loader": "<?php /* @escapeNotVerified */ echo $block->getViewFileUrl('images/loader-1.gif'); ?>"
        }
    }
    </script>
</div>

Вам нужно пройти дальше по образцу кода, чем то, что я изначально опубликовал. Первое, что нужно найти, это: <a class="action showcart" ... data-bind="scope: 'minicart_content'". Что здесь делает Magento (я процитирую серию Алана):

Magento применит модель представления [minicart_content] к этому тегу и его потомкам.

Но где же появляется модель представления minicart_content? У тебя есть чтобы посмотреть немного ниже в коде на тег скрипта x-magento-init:

<script type="text/x-magento-init">
    {
        "[data-block='minicart']": {
            "Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
        },
        "*": {
            "Magento_Ui/js/block-loader": "<?php /* @escapeNotVerified */ echo $block->getViewFileUrl('images/loader-1.gif'); ?>"
        }
    }
</script>

Здесь Magento устанавливает, через KnockoutJS, loaderAnimation.gif . И до того, как мини-карта каким-то образом инициализируется data-block с именем minicart по [data-block='minicart'], который подозрительно похож на селектор стилей CSS. Для меня $block->getJsLayout() возвращает следующее:

{
   "components":{
      "minicart_content":{
         "children":{
            "subtotal.container":{
               "children":{
                  "subtotal":{
                     "children":{
                        "subtotal.totals":{
                           "config":{
                              "display_cart_subtotal_incl_tax":0,
                              "display_cart_subtotal_excl_tax":1,
                              "template":"Magento_Tax\/checkout\/minicart\/subtotal\/totals"
                           },
                           "children":{
                              "subtotal.totals.msrp":{
                                 "component":"Magento_Msrp\/js\/view\/checkout\/minicart\/subtotal\/totals",
                                 "config":{
                                    "displayArea":"minicart-subtotal-hidden",
                                    "template":"Magento_Msrp\/checkout\/minicart\/subtotal\/totals"
                                 }
                              }
                           },
                           "component":"Magento_Tax\/js\/view\/checkout\/minicart\/subtotal\/totals"
                        }
                     },
                     "component":"uiComponent",
                     "config":{
                        "template":"Magento_Checkout\/minicart\/subtotal"
                     }
                  }
               },
               "component":"uiComponent",
               "config":{
                  "displayArea":"subtotalContainer"
               }
            },
            "item.renderer":{
               "component":"uiComponent",
               "config":{
                  "displayArea":"defaultRenderer",
                  "template":"Magento_Checkout\/minicart\/item\/default"
               },
               "children":{
                  "item.image":{
                     "component":"Magento_Catalog\/js\/view\/image",
                     "config":{
                        "template":"Magento_Catalog\/product\/image",
                        "displayArea":"itemImage"
                     }
                  },
                  "checkout.cart.item.price.sidebar":{
                     "component":"uiComponent",
                     "config":{
                        "template":"Magento_Checkout\/minicart\/item\/price",
                        "displayArea":"priceSidebar"
                     }
                  }
               }
            },
            "extra_info":{
               "component":"uiComponent",
               "config":{
                  "displayArea":"extraInfo"
               }
            },
            "promotion":{
               "component":"uiComponent",
               "config":{
                  "displayArea":"promotion"
               }
            }
         },
         "config":{
            "itemRenderer":{
               "default":"defaultRenderer",
               "simple":"defaultRenderer",
               "virtual":"defaultRenderer"
            },
            "template":"Magento_Checkout\/minicart\/content"
         },
         "component":"Magento_Checkout\/js\/view\/minicart"
      }
   },
   "types":[

   ]
}

Вот это уже настоящая шумиха! Для нашей цели здесь мы найдем, откуда взялась модель представления minicart_content. Я снова процитирую Алана:

Как мы знаем [...] когда Magento встречает тег скрипта text/x-magento-init с атрибутом *, он будет

  1. Инициализировать указанный модуль RequireJS (magento_ui/js/core/app)
  2. Вызовите функцию, возвращаемую этим модулем, передав объект данных

Модуль Magento_Ui/js/core/app RequireJS - это модуль, который создает экземпляры моделей представлений KnockoutJS для использования с атрибутом scope. Его полная реализация выходит за рамки, гм, "сферы охвата" этого статья, но на высоком уровне Magento создаст экземпляр нового объекта javascript для каждого отдельного модуля RequireJS, настроенного как компонент, и этот новый объект станет моделью представления.

Теперь мы видим, что здесь инициализировано множество компонентов, как для изображений товаров в корзине. Но также и этот: "component":"Magento_Checkout\/js\/view\/minicart". Это переводится в файл module-checkout/view/frontend/web/js/view/minicart.js, на который указал @Mitch7663 в своем ответе.

Здесь вы найдете функцию getCartParam, на которую ссылается шаблон файл:

<span class="counter-number"><!-- ko text: getCartParam('summary_count') --><!-- /ko --></span>

С использованием магии KnockoutJS это помещает текстовый узел с возвращением getCartParam, вызываемый с идентификатором summary_count. Который сам по себе является ключом к полю в this.cart.

Это все, что у меня сейчас есть. Я пока не уверен, как данные из this.cart попадают во все это. Также я пропустил всю возню с наблюдаемыми и то, о чем вы не можете прочитать в Аланах series...no на самом деле вы должны это прочитать!

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

В любом случае я обновлю ответ, если получу больше информации.

 3
Author: steros, 2017-04-05 14:35:44

summary_count устанавливается в module-checkout/CustomerData/Cart.php

Функция getCartParam() находится в нижней части module-checkout/view/frontend/web/js/view/minicart.js

 0
Author: Mitch7663, 2017-03-28 11:36:59