knockoutjs 主页面调用组件

Calling component on main page in knockoutjs

我在使用 knockoutjs 组件时遇到了一些问题,我正在按照 official knockout component documentation 中的示例进行操作。

如何在主页上调用我的小部件组件?我想我可能把代码放在了错误的地方。

代码: index.html

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script type="text/javascript" src="js/libs/knockout/knockout-3.3.0.js" ></script>
        <script type="text/javascript" src="js/widget.js" ></script>
    </head>
    <body>
        <div>TODO write content</div>
    </body>
</html>

main.js

ko.components.register('like-or-dislike', {
    viewModel: { require: 'files/widget' },
    template: { require: 'text!files/widget.html' }
});

alert(ko.components.isRegistered('like-or-dislike'));

widget.html

<ul data-bind="foreach: products">
    <li class="product">
        <strong data-bind="text: name"></strong>
        <like-widget params="value: userRating"></like-widget>
    </li>
</ul>

widget.js

function Product(name, rating) {
    this.name = name;
    this.userRating = ko.observable(rating || null);
}

function MyViewModel() {
    this.products = [
        new Product('Garlic bread'),
        new Product('Pain au chocolat'),
        new Product('Seagull spaghetti', 'like') // This one was already 'liked'
    ];
}

ko.applyBindings(new MyViewModel());

documentation explains how to load components from external files using requirejs 的时候好像有点迷路了。

I think I may be putting the code in the wrong places

是的,您确实放错了一些代码。让我们让您重回正轨:)

首先,你的widget.js中的代码属于你的main.js 以及对 ko.components.register 的调用。

其次,您在 widget.html 中的标记,对于您的视图模型,属于 index.html

第三,您似乎缺少小部件本身的代码和标记。

看看下面的工作示例。我已经把每段代码属于哪个文件放在代码上方的注释中。

您将不需要通过将它们作为第一个参数传递给requirejsdefine来定义模块名称像我一样的功能:

define("files/widget",...
define("main",...

这只适用于 Stack Snippet. requirejs uses a convention based on file paths if the module name is not supplied, for example requirejs will look for a file called widget.js in a folder called files when given the module name files/widget. Please read the requirejs docs

// This goes in widget.html, only the html. 
// This example uses the define function only to work in this snippet.
define("text!files/widget.html", [], function() {
  return '<div class="like-or-dislike" data-bind="visible: !chosenValue()">\
            <button data-bind="click: like">Like it</button>\
            <button data-bind="click: dislike">Dislike it</button>\
        </div>\
        <div class="result" data-bind="visible: chosenValue">\
            You <strong data-bind="text: chosenValue"></strong> it\
        </div>'
});

// This goes in in widget.js, you must use the define function. 
define("files/widget", [], function() {
  return function(params) {
    // Data: value is either null, 'like', or 'dislike'
    this.chosenValue = params.value;

    // Behaviors
    this.like = function() {
      this.chosenValue('like');
    }.bind(this);
    this.dislike = function() {
      this.chosenValue('dislike');
    }.bind(this);
  }
});

// all of the below goes into main.js
require.config({
  paths: {
    "knockout": "http://knockoutjs.com/downloads/knockout-3.3.0",
    "text": "https://rawgit.com/requirejs/text/master/text"
  }
});

define("main", ["knockout"], function(ko) {
  ko.components.register('like-or-dislike', {
    viewModel: {
      require: 'files/widget'
    },
    template: {
      require: 'text!files/widget.html'
    }
  });

  function Product(name, rating) {
    this.name = name;
    this.userRating = ko.observable(rating || null);
  }

  function MyViewModel() {
    this.products = [
      new Product('Garlic bread'),
      new Product('Pain au chocolat'),
      new Product('Seagull spaghetti', 'like') // This one was already 'liked'
    ];
  }

  ko.applyBindings(new MyViewModel());
})
<!-- this goes in the body of index.html -->
<ul data-bind="foreach: products">
  <li class="product">
    <strong data-bind="text: name"></strong>
    <like-or-dislike params="value: userRating"></like-or-dislike>
  </li>
</ul>

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.19/require.min.js" data-main="main"></script>