outline 属性感觉是解决这个问题的正确方法,但它只允许勾勒单个元素,并且只允许完整的轮廓。
这意味着活动元素必须包装在一个容器中,并且该容器必须接收轮廓。
这可以通过计算出的 observable 来完成,该 observable 会变成一个平面列表:
[
{text: 'Mon', active: true},
{text: 'Tue', active: true},
{text: 'Wed', active: true},
{text: 'Tue', active: false},
{text: 'Fri', active: false},
{text: 'Sat', active: true},
{text: 'Sun', active: true}
]
变成一个嵌套的:
[
[
{text: 'Mon', active: true},
{text: 'Tue', active: true},
{text: 'Wed', active: true}
],
[
{text: 'Tue', active: false},
{text: 'Fri', active: false},
],
[
{text: 'Sat', active: true},
{text: 'Sun', active: true}
]
]
取决于哪个项目是active。
这是我在淘汰赛中的实现方式。
- 一个
Button 视图模型,它跟踪自己的 active 状态并允许切换它
- 一个
ButtonList 视图模型,其中包含按钮和动态计算的buttonGroups。
- 基于此创建
.btn-group 和 .btn-group.active div 的视图。
下面的互动示例:
function Button(params) {
this.text = params.text;
this.active = ko.observable(params.active);
this.toggle = () => this.active(!this.active());
}
function ButtonList(params) {
this.buttons = ko.observableArray(params.buttons.map(b => new Button(b)));
this.buttonGroups = ko.pureComputed(() => {
const groups = [];
let prev = null, group = null;
this.buttons().forEach(b => {
if (b.active() !== prev) {
group = [];
groups.push(group);
prev = b.active();
}
group.push(b);
});
return groups;
});
}
const vm = new ButtonList({
buttons: [
{text: 'Mon', active: true},
{text: 'Tue', active: true},
{text: 'Wed', active: true},
{text: 'Tue', active: false},
{text: 'Fri', active: false},
{text: 'Sat', active: true},
{text: 'Sun', active: true}
]
});
ko.applyBindings(vm);
.btns {
display: flex;
}
.btn-group {
display: flex;
outline-offset: 2px;
}
.btn-group.active {
outline: 2px solid black;
}
.btn-group > * {
width: 50px;
padding: 5px;
margin: 0;
text-align: center;
}
.btn-group > .active {
background-color: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="btns" data-bind="foreach: buttonGroups">
<div class="btn-group" data-bind="foreach: $data, css: {active: $data[0].active}">
<div data-bind="click: toggle, text: text, css: {active: active}"></div>
</div>
</div>