同一视图中的多个挖空组件

时间:2015-07-24 06:08:04

标签: javascript knockout.js

我已经高低搜索了这个答案,但是对于我的生活来说,我不能弄清楚我在做什么与官方例子不同,除了我认为我的用例有点更复杂:

http://knockoutjs.com/documentation/component-binding.html

基本上,我正在尝试创建可重用的UI元素。行为将基本上通过“params”对象传递给它们。我希望多个元素能够存在于单个页面上,然而,这是我遇到困难的地方。

我正在使用browserify捆绑我的代码并拥有以下内容(为简洁起见,某些条目被截断):

的index.html

<div data-bind='component: { name: "toggle" , params: {
   enabledText: "Parental controls are enabled",
   disabledText: "Parental controls are disabled"
 }}'></div>
 <div data-bind='component: { name: "toggle" , params: {
   enabledText: "Same component, different behavior: enabled",
   disabledText: "Same component, different behavior: disabled"
 }}'></div>

main.js

var ko = window.ko = require('knockout'),
    toggle = require('./components/toggle/toggle');

ko.components.register('toggle', toggle);

function Container() {

}

var con = new Container();

ko.applyBindings(con);

组件/肘/ toggle.js

var ko = require('knockout'),
    template = require('./toggle.html');

function vm(params) {
  var self = this;
  self.enabled = ko.observable(false);
  self.label = ko.computed(function() {
    return self.enabled() ? params.enabledText : params.disabledText;
  });
}

module.exports = { viewModel: vm, template: template };

最后,在components / toggle / toggle.html中:

<input type='checkbox' data-bind='checked: enabled' id='switch-checkbox' class='switch-input' />
<label for='switch-checkbox' class='switch-input-label'>
  <span data-bind='text: label'></span>
</label>

我遇到的问题是组件都适当地出现在页面上,但点击第二个组件会激活第一个组件(并且对seconD没有任何作用)。我是Knockout的新手并且显然遗漏了一些东西,但我无法弄清楚如何解决我的问题。任何帮助都会非常感激!

奇怪的是标签是唯一的,表明为每个HTML实体实例化的组件(视图模型)实际上是唯一的...但是,看来敲门的“已检查”绑定只能绑定到第一个。

编辑:我知道习惯上包含一个例子,所以这里有一个关于codepen的例子。我为使用浏览器代码道歉,但希望它仍然可读:

http://codepen.io/sunny-mittal/pen/OVBNwp

1 个答案:

答案 0 :(得分:7)

当您加载此组件的多个实例时,id标记上的input属性和构成您组件的for标记上的label属性是不再是页面的独特之处。

您基本上有两个input标记,其中idlabel个标记位于一个id。第二个组件上的label for="switch-checkbox"从第一个组件而不是第二个组件中获取input id="switch-component"

虽然淘汰组件很棒,但遗憾的是组件实例之间没有隔离。

要解决此问题,您需要确保每个组件实例中idfor的值对整个页面都是唯一的。

我在此工作中包含了一个片段。

var uid = function(){
  var seed = 1;
  return { 
    new: function(p){
      return p + (seed++);
    }
  }
}();


    var template =
      "<input type='checkbox' data-bind='checked: enabled, attr: {id:id}' class='switch-input' />\n<label data-bind='attr: {for: id}' class='switch-input-label'>\n  <span data-bind='text: label'></span>\n</label>\n";

    var viewModel = function vm(params) {
      var self = this;
      self.id = uid.new('switch-checkbox-');
      self.enabled = ko.observable(false);
      self.label = ko.computed(function() {
        return self.enabled() ? params.enabledText : params.disabledText;
      });
    }

    var component = {
      viewModel: viewModel,
      template: template
    };

    ko.components.register('toggle', component);

    var vm = {};

    ko.applyBindings(vm);
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html {
  position: relative;
  height: 100%;
  min-height: 100%;
}
.switch-input {
  display: none;
}
.switch-input-label {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
  position: relative;
  display: inline-block;
  cursor: pointer;
  font-weight: 500;
  text-align: left;
  margin: 16px;
  padding: 16px 0 16px 44px;
}
.switch-input-label:before,
.switch-input-label:after {
  content: '';
  position: absolute;
  margin: 0;
  outline: 0;
  top: 50%;
  transform: translate(0, -50%);
  transition: all 0.3s ease;
}
.switch-input-label:before {
  left: 1px;
  width: 34px;
  height: 14px;
  background-color: #9e9e9e;
  border-radius: 8px;
}
.switch-input-label:after {
  left: 0;
  width: 20px;
  height: 20px;
  background-color: #fafafa;
  border-radius: 50%;
  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.14), 0 2px 2px 0 rgba(0, 0, 0, 0.098), 0 1px 5px 0 rgba(0, 0, 0, 0.084);
}
.switch-input:checked + .switch-input-label:before {
  background-color: #a5d6a7;
}
.switch-input:checked + .switch-input-label:after {
  background-color: #4caf50;
  transform: translate(80%, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>


<div data-bind='component: { name: "toggle" , params: {
   enabledText: "Parental controls are enabled",
   disabledText: "Parental controls are disabled"
 }}'></div>

<div data-bind='component: { name: "toggle" , params: {
   enabledText: "Same component, different behavior: enabled",
   disabledText: "Same component, different behavior: disabled"
 }}'></div>

<div data-bind='component: { name: "toggle" , params: {
   enabledText: "Same component, another instance: enabled",
   disabledText: "Same component, another instance: disabled"
 }}'></div>