KnockoutJS foreach 绑定在所选项目周围添加轮廓

KnockoutJS foreach binding add outline around selected items

我有一个显示为按钮的淘汰可观察项目数组:

<div class="btn-group" data-bind="foreach: myList">
     <button data-bind="css: Sel == false ? 'btn btn-white' : 'btn btn-dark', click:$root.makeChange, text:$data.Id, attr:{'id':'h_'+$data.Id}"></button>
</div>

我需要为其添加轮廓 对于 Sel 设置为 true 的项目。

我试过使用 outline: 2px solid black; outline-offset: 1px; 但它会在每个按钮周围添加轮廓,而不是为组添加轮廓,并且轮廓的右线绘制在下一个按钮后面。

我也尝试过使用边框,并用 JS 添加它们,但是我没有按钮和边框之间的 space。

outline 属性 感觉是解决这个问题的正确方法,但它只允许概述单个元素,并且只允许完整的轮廓。

这意味着活动元素必须包裹在一个容器中,并且该容器必须接收轮廓。

这可以通过计算可观察值来完成,该可观察值会变成一个平面列表:

[
    {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

以下是我将如何在淘汰赛中实现它。

  1. 一个 Button 视图模型,它跟踪自己的 active 状态并允许切换它
  2. 包含按钮和动态计算的 buttonGroupsButtonList 视图模型。
  3. 基于此创建 .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>