Knockout 是 Magento 2 前端世界中引入的最大变化之一,虽然一开始它真的很难掌握,但最终它会成为一个非常有用的工具,使用起来很有趣。
在您必须根据用户的输入或其他一些操作更新某些内容的情况下,所讨论的库确实很出色。它将“可观察值”带到表中——可以自动更新的变量,并通知所有相关方它们已被修改。除此之外,我们还有一种“计算”类型的函数,它们会在更新其中任何可观察对象时自动触发。添加将 html 元素绑定到这些变量的选项,现在应该清楚容易获得的可能性的数量。
在本文中,我们将创建一个简单的模块,负责与我们的客户打乒乓球。我将向您展示如何:
– 创建一个简单的前端模块,
– 声明并为可观察变量赋值,
– 将变量从模板/块/php 传递到 JavaScript,
– 在模板中使用 knockout 可观察
对象, – 在可观察到的变化。
让我们从创建模块 Magently_TableTennis 开始,该模块将为主页提供 JavaScript、模板和布局更新。
//registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Magently_TableTennis',
__DIR__
);
//etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magently_TableTennis" setup_version="0.1.0">
<sequence>
<!-- add sequence since we will update cms_index_index layout -->
<module name="Magento_Cms"/>
</sequence>
</module>
</config>
And this is where the fun part begins:
//view/frontend/web/js/view/tableTennis.js
//first we have to define modules we want to use in our script
define([
'uiComponent',
'ko'
], function (Component, ko) {
//we'll make our game a Component to allow someone to easily modify it in the future
return Component.extend({
initialize: function () {
//next line is basically equivalent of parent::__construct() in php
this._super();
//let's divide our component to 2 separate elements
//one responsible for populating our game's interface
this.populateUi();
//and one responsible for the gameplay itself
this.gameplay();
},
populateUi: function () {
//here we are creating an observable array and set its items to ping and pong
this.userActions = ko.observableArray(['ping', 'pong']);
//this observable will be responsible for storing information about currently selected action
//initialMove will be passed from template
this.selectedAction = ko.observable(this.initialMove);
//and here we will create an observable without initial value
//that will be responsible for storing computer's action
this.aiMove = ko.observable();
},
gameplay: function () {
//assign this to self so we can use it inside a function
var self = this;
//handleMove will be fired every time an observable inside it changes
ko.computed(function handleMove()
{
if (self.selectedAction() == self.userActions()[0]) {
self.aiMove(self.userActions()[1]);
}
else {
self.aiMove(self.userActions()[0]);
}
});
}
});
});
//view/frontend/layout/cms_index_index.xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="top.container">
<block class="\Magento\Framework\View\Element\Template" name="tabletennis" template="Magently_TableTennis::tabletennis.phtml" before="-" />
</referenceContainer>
</body>
</page>
//view/frontend/templates/tabletennis.phtml
<!-- data-bind attribute lets us bind knockout entities to our elemets -->
<div data-bind="scope: 'tableTennis'">
<!-- here we create select input with options fetched from userActions observable array -->
<!-- and bind the selected option to selectedAction observable -->
<select data-bind="options: userActions, value: selectedAction"></select>
<!-- analogically we bind the text of a paragraph element to aiMove -->
<p data-bind="text: aiMove"></p>
</div>
<!-- here we initialize our script -->
<script type="text/x-magento-init">
{
<?php // we can specify site elements on which we want to trigger our script ?>
<?php // * means we launch it only once - for the whole page ?>
"*": {
<?php // this is javascript we are launching ?>
"Magento_Ui/js/core/app": {
<?php // and here we declare components of Magento_Ui/js/core/app ?>
"components": {
"tableTennis": {
"component": "Magently_TableTennis/js/view/tableTennis",
<?php // here we set the initial move of the player ?>
"initialMove": "ping"
}
}
}
}
}
</script>