Объединить динамические и статические классы через css binding, knockout.js
В knockout.js мы можем использовать привязку css для статических классов
<div data-bind="css: {'translucent ': number() < 10}">static dynamic css classes</div>
и динамический
<div data-bind="css: color">static dynamic css classes</div>
Я попытался http://jsfiddle.net/tT9PK/1/ объединить его в нечто вроде
css: {color, translucent: number() < 10}
чтобы получить динамический класс color
и статический translucent
в то же время, но я получаю сообщение об ошибке. Есть ли способ сделать это?
Ответы
Ответ 1
Вы можете добавить динамический класс по свойству css
, а затем добавить статический класс с помощью свойства attr
<div data-bind="attr: { 'class': color }, css: { 'translucent': number() < 10 }">
static dynamic css classes
</div>
Обязательно добавьте все предопределенные классы к этой привязке
attr: { 'class': color }
Ответ 2
Я решил эту проблему некоторое время назад, просто клонируя привязку css
как css2
.
ko.bindingHandlers['css2'] = ko.bindingHandlers.css;
Обычно вы не можете использовать один и тот же обработчик привязки дважды в атрибуте привязки данных, поэтому это позволило мне сделать следующее:
<div data-bind="css: color, css2: { 'translucent': number() < 10 }">static dynamic css classes</div>
Я не могу решить, предпочитаю ли я это, или ответ @Aleksey, но это может быть единственным выбором, если у вас есть несколько динамических классов для добавления.
Ответ 3
Правильно... и еще больше запустите вас, проверьте эту модификацию.
http://jsfiddle.net/Fv27b/2/
Здесь вы увидите, что мы не только объединяем параметры, но и полностью создаем нашу привязку... что приводит к гораздо более переносимому расширению не только этой модели представлений, но и любой модели просмотра может быть в вашем проекте... так что вам нужно будет только один раз написать это!
ko.bindingHandlers.colorAndTrans = {
update: function(element, valAccessor) {
var valdata = valAccessor();
var cssString = valdata.color();
if (valdata.transValue() < 10) cssString += " translucent";
element.className = cssString;
}
}
Чтобы вызвать это, вы просто используете его как новое свойство привязки данных и можете включать как можно больше (или несколько) параметров. В этом конкретном случае я мог бы просто предоставить $data, однако, если вы хотите использовать параметр многократного использования, вам нужно быть более конкретным относительно того, какие типы данных вам нужны в качестве параметров, а не все модели просмотра могут иметь одинаковые свойства.
data-bind="colorAndTrans: { color: color, transValue: number }"
Надеюсь, что это больше, чем ответ на ваш вопрос!
Ответ 4
Лучше всего, наверное, не комбинировать их. Вместо этого используйте вычисленное свойство вашей модели представления, чтобы объединить их в одно свойство, которое можно связать динамически. Таким образом, вы также можете не вводить логику в свое представление с помощью номера() < 10, что в любом случае является более чистым.
Подобно этому, например:
viewModel.colorAndTrans = ko.computed(function () {
var cssString = viewModel.color();
if (viewModel.number() < 10) {
cssString += " translucent"
}
return cssString;
});
См. этот рабочий пример: http://jsfiddle.net/tT9PK/4/
Ответ 5
Если вы действительно попадаете в сложный стиль, просто накапливайте все в вычисленном свойстве. Вы можете сделать это, как сказал Алекс, или немного более читаемым:
vm.divStyle = ko.computed(function() {
var styles = [];
if (vm.isNested()) styles.push('nested');
if (vm.isTabular()) styles.push('tabular');
else styles.push('non-tabular');
if (vm.color()) styles.push(vm.color());
return styles.join(' ');
});
Основной недостаток заключается в том, что вы перемещаете часть определения вида в модель представления, которая должна быть более независимой. Альтернативой является предоставление всей логики выше как простой вызов функции js, и пусть нокаут оценит ее.
Ответ 6
Еще пара опций:
Подобно предложениям по использованию вычисленных, вы можете вставить выражение:
<div data-bind="css: [color(), (number() < 10 ? 'translucent' : 'notTranslucent')].join(' ')">static dynamic css classes</div>
В качестве альтернативы настраиваемому обработчику привязки, специфичному для этого случая, вы можете создать тот, который принимает массив смешанных спецификаций css и передает их в исходный обработчик css:
<div data-bind="cssArray: [color, {translucent: number() < 10}]">static dynamic css classes</div>
Обработчик:
ko.bindingHandlers.cssArray = {
update: function (element, valueAccessor, allBindingsAccessor, data, context) {
var arr = ko.unwrap(valueAccessor());
for (var i=0; i<arr.length; ++i) {
var wrapped = function () { return ko.unwrap(arr[i]) };
ko.bindingHandlers.css.update(element, wrapped, allBindingsAccessor, data, context);
}
}
}
Скриншот демо
Ответ 7
Существует более элегантное решение этой проблемы с помощью вычисленных имен свойств (для FF > 34, Chrome, Safari > 7.1):
<div data-bind="css: { [color]: true,'translucent': number() < 10 }">
static dynamic css classes
</div>
В то время как color
- это свойство со строковым значением.
Если значение color
является наблюдаемым, нам нужно очистить имя класса до этого наблюдаемого обновления. Если мы этого не сделаем, каждое изменение добавит еще один класс и не удалит предыдущий. Это можно легко выполнить вручную, но я написал расширитель для тех, кто заинтересован.
ko.extenders.css = function(target, value) {
var beforeChange;
var onChange;
//add sub-observables to our observable
target.show = ko.observable(true);
beforeChange = function(oldValue){
target.show(false);
}
onChange = function(newValue){
target.show(true);
}
target.subscribe(beforeChange, null, "beforeChange");
target.subscribe(onChange);
return target;
};
С помощью этого расширителя ваш код JavaScript будет выглядеть следующим образом:
function MyViewModel() {
this.color = ko.observable("red").extend({ css: true });
this.number = ko.observable(9)
};
И ваша разметка будет такой простой:
<div data-bind="css: { [color()]: color.show(),'translucent': number() < 10 }">
static dynamic css classes
</div>
У меня есть кодовое перо, демонстрирующее эту технику:
http://codepen.io/USIUX/pen/WryGZQ
Я также представил вопрос с нокаутом в надежде, что однажды пользовательский расширитель не понадобится: https://github.com/knockout/knockout/issues/1990
Ответ 8
Хороший вопрос, проблема, похоже, связана с привязкой css
, которая не смешивает два типа, color(): color() != ''
не работает (было бы хорошо).
Мне нравится подход @Simon_waver, простой и практичный.
Возможно, на момент ответа вопрос не поддерживался (Idk), но с текущим нокаутом, также объединяющим классы: data-bind="css: computed"
viewModel.computed = ko.pureComputed(function() {
return viewModel.color() + (viewModel.number() < 10 ? ' translucent' : '');
});