如何在Magento 2中使用Knockout JS


12

我的问题:

我试图在Magento 2中编写一个小型的Knockout JS应用,但我正在努力初始化该应用,因为当我使用ko.applyBindings(AppViewModel, document.getElementById("koTest"));它破坏了Magento 使用的Knockout并引发此错误时:

Uncaught Error: You cannot apply bindings multiple times to the same element.

我怀疑是因为:

我怀疑这是因为Magento的2已经在使用ko.applyBindings()app/code/Magento/Ui/view/base/web/js/lib/knockout/bootstrap.js。而且由于未指定节点,因此无法ko.applyBindings再次使用。

如果我不在ko.applyBindings(AppViewModel, document.getElementById("koTest"))代码中使用,那么我的应用程序不会初始化。

这使我认为我需要以某种方式使用ko.applyBindings()基因敲除/bootstrap.js,但我不知道该如何使用,有人可以帮忙吗?我对淘汰赛的经验很少。

我的密码

<script type="text/javascript">
    require([
        'ko'
    ], function(ko) {
        // This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
        function AppViewModel() {

            this.firstName = ko.observable("Bert");
            this.lastName = ko.observable("Bertington");
            this.fullName = ko.computed(function() {
                return this.firstName() + " " + this.lastName();
            }, this);

            this.capitalizeLastName = function() {
                var currentVal = this.lastName();
                this.lastName(currentVal.toUpperCase());
            };
        }

        ko.applyBindings(AppViewModel, document.getElementById("koTest"));
    });
</script>

<!-- This is a *view* - HTML markup that defines the appearance of your UI -->

<div id="koTest">
    <p>First name: <strong data-bind="text: firstName"></strong></p>
    <p>Last name: <strong data-bind="text: lastName"></strong></p>
    <p>Full name: <strong data-bind="text: fullName"></strong></p>

    <p>First name: <input data-bind="value: firstName" /></p>
    <p>Last name: <input data-bind="value: lastName" /></p>
    <p>Full name: <input data-bind="value: fullName" /></p>

    <button data-bind="click: capitalizeLastName">Capitalise</button>
</div>

Answers:


23

您无需使用html模板的简单方法

多亏了Vinai Kopp,我终于得到了答案,这比我以前的hacky解决方法(我正在清理节点)要简单得多。您需要做的就是将其定义'ko'为依赖项,然后将代码添加到return函数中。

下面是一个简单的示例,该示例呈现出一些通过JSON传递的文本。

app/code/VENODR/MODULE/view/frontend/templates/knockout-example.phtml

在这里,我们告诉Magento我们组件的范围(必须匹配data-bind: "scope: 'example-scope'"并传递任何其他数据。这可能是基本URL,一条简单消息,几乎任何您想要的东西。我已经传递了一个字符串(PHP echo)作为示例

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "example-scope": {
                    "component": "VENDOR_MODULE/js/knockout-example",
                    "exampleMessage": "<?= __('Hello Magento Stack Exchange!') ?>"
                }
            }
        }
    }
}
</script>

<div data-bind="scope: 'example-scope'">
    <h2 data-bind="text: message"></h2>
</div>

在这里,我们编写了Javascript。

app/code/VENDOR/MODULE/view/frontend/web/js/knockout-example.js

define(['ko'], function(ko) {
    return function(config) {
        this.message = ko.observable(config.exampleMessage);
    }
});

 结果

在此处输入图片说明

---------------------

您需要使用HTML模板的方法

如果您想在Magento2 / Knockout中使用HTML模板系统(我想您需要做任何重要的工作),那么与我的简化答案相比(以下),您需要进行一些更改。

如果您不需要模板功能,请向下滚动到我以前的简化答案。

我在此示例中使用的文件是:

  • app/design/frontend/VENDOR/THEME/Magento_Cms/templates/knockout.phtml
  • app/design/frontend/VENDOR/THEME/Magento_Cms/web/js/knockout-example.js
  • app/design/frontend/VENDOR/THEME/Magento_Cms/web/template/test.html

PHTML模板文件

对我们的PHTML模板的唯一更改是对getTemplate()函数的调用:

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "example-scope": {
                    "component": "Magento_Cms/js/knockout-example",
                    "exampleMessage": "<?= __('Hello Magento Stack Exchange!') ?>"
                }
            }
        }
    }
}
</script>

<div data-bind="scope: 'example-scope'">
    <h2 data-bind="text: message"></h2>
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

JS(组件)文件

您需要对JS文件进行一些更改,以下将详细说明。

define(['ko', 'uiComponent'], function(ko, Component) {
    'use strict';

    return Component.extend({
        defaults: {
            exampleMessage: 'Hello?',
            template: 'Magento_Cms/test'
        },

        initialize: function() {
            this._super();
            console.log(this.exampleMessage);
            this.message = ko.observable(this.exampleMessage);
        }
    });
});

1-现在,您的return函数需要扩展uiComponent模块:

return Component.extend({
    ...
});

2-您需要添加一个initialize函数并调用this._super()this._super()将使用相同的名称调用父组件的函数。因此,在这种情况下我认为它会调用initializeuiComponent

initialize: function() {
    this._super();
    ...
}.

3- 可选 -您还可以在此处为组件设置一些默认值,我认为这是一个好的做法,因为它使您的组件易于使用。当您重用它时,您可以保留默认值,或者如果您要自定义它,则可以使用新参数调用它而无需更改组件。

例如,如果您查看JS中的默认值,则会将其设置exampleMessage为,'Hello?'而页面会将文本呈现为Hello Magento Stack Exchange!。这是因为exampleMessage调用该组件时,我已经覆盖了PHTML文件。

HTML模板

我仍在研究并了解HTML模板的功能,我认为Knockout JS文档中提到的功能可以在此处使用,从而使其变得非常灵活。

我现在刚刚添加了一些lorem ipsum文本,一旦弄清楚了HTML模板可以做什么,我可能会提供另一个问题/答案。

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores assumenda beatae blanditiis culpa cupiditate doloremque, expedita ipsum iure magni minima modi molestiae nulla optio porro ratione reiciendis repellat soluta voluptatum!

结果,并覆盖默认值

如前所述,您可以看到我已经覆盖exampleMessage了模板,可以看到它随着文本的读取而工作Hello Magento Stack Exchange

在此处输入图片说明

如果我删除了模板文件中的替代值,exampleMessage它将恢复为默认值Hello?。我确实需要删除var/view_preprocessed,但是pub/static/frontend在更改此设置之后。我认为Magento已经缓存了该值。

在此处输入图片说明


这将在Magento2.1
Venkat

@Venkat-您的意思是您现在可以轻松使用Knockout而不需要清理节点吗?还是我的修复程序在2.1中有效?
本·克鲁克

您的修复程序将在2.1中工作吗?
2016年

对我而言,绑定是可行的,但在第一次输入数据绑定时会出现参考错误
Venkat

我认为KnockoutJS自2.0.X以来似乎并没有太大变化-尽管我在2.1中还没有尝试过,所以我不确定100%。另外,请确保您进行了彻底的测试,因为我不确定这是否是最好的方法,但这是我唯一能找到的方法。
本·克鲁克

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.