2015-07-24 5 views
7

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

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

в принципе, я пытаюсь создать повторно используемые элементы пользовательского интерфейса. Поведение будет по существу передано им через объект «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/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 }; 

И, наконец, в компонентах/тумблер/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, фактически уникальны ... однако, похоже, что «проверенная» привязка нокаута является обязательной к первому.

EDIT: Я знаю, что принято включать пример, так что вот один из косеферов. Я извиняюсь за помощью browserified коды, но, надеюсь, он по-прежнему читает:

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

ответ

6

При загрузке несколько экземпляров данного компонента атрибут id на input тег и атрибут на label тега for, которые составляют ваш компонент , больше не будут уникальными для этой страницы.

У вас есть два тега input с теми же id и двумя тегами label, ориентированными на один id. Ваш label for="switch-checkbox" на втором компоненте поднимает input id="switch-component" от первого компонента, а не второго.

Несмотря на то, что компоненты нокаута великолепны, к сожалению, между экземплярами компонентов отсутствует изоляция dom.

Для решения этой проблемы вам необходимо убедиться, что значения для id и for в каждом экземпляре вашего компонента уникальны для всей страницы.

Я включил фрагмент ниже этой работы.

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>

+1

Вы спасатель! Я очень надеюсь, что этот ответ поможет кому-то другому, потому что я много часов ломал голову над этим. –

+1

Рад, что я мог бы помочь приятелю :) –

+1

Семантически говоря, HTML-идентификатор всегда должен быть уникальным в соответствии со спецификациями HTML. Есть ли какая-либо техническая причина, по которой вы не можете их дублировать? Не совсем, но это лучшая практика, которая помогает предотвратить вышеупомянутую ситуацию. Если вы видите идентификатор в документе, следует предположить, что он не существует в другом месте. – mattLummus

Смежные вопросы