javascript 通过 css 绑定,knockout.js 结合动态和静态类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19256093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
combine dynamic and static classes through css binding, knockout.js
提问by Artem Svirskyi
In knockout.js we can use css binding for static classes
在knockout.js 中,我们可以对静态类使用css 绑定
<div data-bind="css: {'translucent ': number() < 10}">static dynamic css classes</div>
and dynamic
和动态
<div data-bind="css: color">static dynamic css classes</div>
I've tried http://jsfiddle.net/tT9PK/1/to combine it in something like
我试过http://jsfiddle.net/tT9PK/1/将它组合成类似的东西
css: {color, translucent: number() < 10}
to get dynamic class color
and static translucent
at the same time, but I get an error. Is there a way to do that?
同时获取动态类color
和静态类translucent
,但出现错误。有没有办法做到这一点?
回答by Aleksey
You can add dynamic class by css
property and then add static class by attr
property
您可以通过添加动态类css
属性,然后通过添加静态类attr
属性
<div data-bind="attr: { 'class': color }, css: { 'translucent': number() < 10 }">
static dynamic css classes
</div>
Be sure to add any predefined classes to this binding
attr: { 'class': color }
确保将任何预定义的类添加到此绑定
attr: { 'class': color }
回答by Simon_Weaver
I solved this problem a while back by just cloning the css
binding as css2
.
不久前,我通过将css
绑定克隆为css2
.
ko.bindingHandlers['css2'] = ko.bindingHandlers.css;
Normally you can't use the same binding handler twice in a data-bind attribute, so this allowed me to do the following:
通常,您不能在数据绑定属性中两次使用相同的绑定处理程序,因此这允许我执行以下操作:
<div data-bind="css: color, css2: { 'translucent': number() < 10 }">static dynamic css classes</div>
I can't quite decide whether I still prefer this, or @Aleksey's answer, but this may be the only choice if you have multiple dynamic classes to add.
我不能完全确定我是否仍然更喜欢这个,或者@Aleksey 的答案,但是如果您要添加多个动态类,这可能是唯一的选择。
回答by beauXjames
Correct...and to launch you even further, check out this modification.
正确......为了进一步启动您,请查看此修改。
Here, you'll see that not only are we combining the options, but we're creating our own binding entirely...which results in a much more portable extension of not just this view model, but any view model you may have in your project...so you'll only need to write this one once!
在这里,你会看到我们不仅组合了选项,而且我们完全创建了我们自己的绑定......这不仅会导致这个视图模型的更便携的扩展,而且你可能拥有的任何视图模型你的项目……所以你只需要写一次这个!
ko.bindingHandlers.colorAndTrans = {
update: function(element, valAccessor) {
var valdata = valAccessor();
var cssString = valdata.color();
if (valdata.transValue() < 10) cssString += " translucent";
element.className = cssString;
}
}
To invoke this, you just use it as a new data-bind property and can include as many (or as few) options as possible. Under this specific condition, I might have just provided $data, however if you're wanting a reusable option you need to be more specific as to what data types you need as parameters and not all view models may have the same properties.
要调用它,您只需将它用作新的数据绑定属性,并且可以包含尽可能多(或尽可能少)的选项。在这种特定条件下,我可能刚刚提供了 $data,但是如果您想要一个可重用的选项,您需要更具体地说明您需要作为参数的数据类型,并且并非所有视图模型都可能具有相同的属性。
data-bind="colorAndTrans: { color: color, transValue: number }"
Hope this does more than answer your question!
希望这不仅仅是回答您的问题!
回答by Matt Burland
Your best bet is probably not to combine them. Instead use a computed property of your view model to combine them into a single property that you can bind dynamically. That way you can also avoid putting logic in your view with the number() < 10 binding, which is cleaner anyway.
您最好的选择可能是不要将它们结合起来。而是使用视图模型的计算属性将它们组合成一个可以动态绑定的属性。这样,您还可以避免使用 number() < 10 绑定在视图中放置逻辑,这无论如何都更清晰。
Like this, for example:
像这样,例如:
viewModel.colorAndTrans = ko.computed(function () {
var cssString = viewModel.color();
if (viewModel.number() < 10) {
cssString += " translucent"
}
return cssString;
});
See this working example: http://jsfiddle.net/tT9PK/4/
请参阅此工作示例:http: //jsfiddle.net/tT9PK/4/
回答by mikus
If you really get into complicated styling case, just accumulate all in the computed property. You can do it as Alex mentioned or a bit more readable:
如果您真的遇到复杂的样式案例,只需在计算属性中累积所有内容即可。你可以像亚历克斯提到的那样做,或者更具可读性:
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(' ');
});
the main drawback is that you're moving a part of view definition into the viewmodel, that should be more independent. The alternative is to provide all the logic above as a plain js function call, and let knockout evaluate it.
主要缺点是您将视图定义的一部分移动到视图模型中,这应该更加独立。另一种方法是将上述所有逻辑作为一个普通的 js 函数调用提供,并让 Knockout 对其进行评估。
回答by Roy J
A couple more options:
还有几个选择:
Similar to the suggestions to use a computed, you can inline the expression:
类似于使用计算的建议,您可以内联表达式:
<div data-bind="css: [color(), (number() < 10 ? 'translucent' : 'notTranslucent')].join(' ')">static dynamic css classes</div>
As an alternative to a custom binding handler that is specific to this case, you can make one that takes an array of mixed css specs and passes them to the original css handler:
作为特定于这种情况的自定义绑定处理程序的替代方案,您可以制作一个接受一组混合 css 规范并将它们传递给原始 css 处理程序的方法:
<div data-bind="cssArray: [color, {translucent: number() < 10}]">static dynamic css classes</div>
The handler:
处理程序:
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);
}
}
}
回答by Kenneth Moore
There is a more elegant solution to this problem via computed property names (for FF>34, Chrome, Safari>7.1):
通过计算属性名称(对于FF>34、Chrome、Safari>7.1),有一个更优雅的解决方案:
<div data-bind="css: { [color]: true,'translucent': number() < 10 }">
static dynamic css classes
</div>
Whereas color
is a property with a string value.
而color
是具有字符串值的属性。
If the value of color
is an observable then we need to clear the classname before that observable updates. If we do not do this then each change will add another class and not remove the previous one. This can easily be accomplished manually but I wrote an extender for those who are interested.
如果 的值color
是一个 observable,那么我们需要在该 observable 更新之前清除类名。如果我们不这样做,那么每次更改都会添加另一个类,而不是删除前一个。这可以很容易地手动完成,但我为那些有兴趣的人写了一个扩展程序。
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;
};
With this extender, your JavaScript code would look like this:
使用此扩展程序,您的 JavaScript 代码将如下所示:
function MyViewModel() {
this.color = ko.observable("red").extend({ css: true });
this.number = ko.observable(9)
};
And your markup would be this simple:
你的标记会很简单:
<div data-bind="css: { [color()]: color.show(),'translucent': number() < 10 }">
static dynamic css classes
</div>
I have a code pen demonstrating this technique: http://codepen.io/USIUX/pen/WryGZQ
我有一个代码笔演示这种技术:http: //codepen.io/USIUX/pen/WryGZQ
I have also submitted an issue with knockout in hopes that one day the custom extender will not be necessary: https://github.com/knockout/knockout/issues/1990
我还提交了一个关于淘汰赛的问题,希望有一天不需要自定义扩展程序:https: //github.com/knockout/knockout/issues/1990
回答by Alex
Nice question, the problem seems to be the binding css
isn't thought to mix the two kinds, color(): color() != ''
doesn't work (would be nice).
好问题,问题似乎是绑定css
不被认为是混合这两种,color(): color() != ''
不起作用(会很好)。
I like @Simon_waver's answer approach, simple and practical.
我喜欢@Simon_waver 的回答方式,简单实用。
Maybe at the time of the question wasn't supported (Idk) but with current knockoutalso combining the classes works: data-bind="css: computed"
也许在提出问题的时候不支持(Idk),但目前的淘汰赛也结合了这些课程:data-bind="css: computed"
viewModel.computed = ko.pureComputed(function() {
return viewModel.color() + (viewModel.number() < 10 ? ' translucent' : '');
});
回答by user3297291
I'd create the css
binding value in your viewmodel. You can define a computed
that returns either an object or string.
我会css
在您的视图模型中创建绑定值。您可以定义computed
返回对象或字符串的 。
Some examples, using ES2015:
一些示例,使用 ES2015:
const App = function() {
this.number = ko.observable(12);
this.color = ko.observable("red");
this.cssConfigObj = ko.pureComputed(() => ({
"italic": this.number() > 10,
[this.color()]: true
}));
this.cssConfigStr = ko.pureComputed(() =>
`${this.color()} ${this.number() > 10 ? "italic" : ""}`
);
};
ko.applyBindings(new App());
.monospaced {
font-family: monospace;
}
.italic {
font-style: italic;
}
.red {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div
class="monospaced"
data-bind="css: cssConfigObj"
>Hello world</div>
<div
class="monospaced"
data-bind="css: cssConfigStr"
>Hello world</div>