找到合适的DOM元素

时间:2016-08-17 16:16:39

标签: javascript jquery dom knockout.js

以下是我的模型:

function TimeCardViewModel() {
    var self = this;
    self.teamMembers=ko.observableArray();
  }

function TeamMemberViewModel(data){
    var self=this;
    self.days=ko.observableArray();
    for (var i=0; i<7; i++)  {
      self.days.push(new DayViewModel(...);
    }
  }

function DayViewModel(shifts){
    var self=this;
    self.shifts=ko.observableArray();
    for (var i=0; i<shifts.length; i++)  {
       self.shifts.push(new ShiftElementsViewModel(...);
    } 
  }

function ShiftElementsViewModel(a,b,c,d) {
    var self=this;
    self.startTime=ko.observable(a);
    self.endTime=ko.observable(b);
  }

var timeCardViewModel=new TimeCardViewModel();
ko.applyBindings(timeCardViewModel);

和我的viewmodel:

blur

对于每个成员,我们(一周中的七天中的每一天)都有一些轮班。对于每个班次,我们都有成对的startTime-endTime输入。 就视觉结果而言,存在包括成员的每周轮班的行,并且可能是每个成员每天多次轮班的情况。如果我们查看列,这些列包括某一天所有成员的所有轮班 我的问题是,只要endTime的DOM元素上有{{1}}事件,我就要关注startTime 垂直的DOM元素。例如,如果我们在星期一并且第一个成员有两个班次我想要关注第一个成员的第二个班次的startTime,当第一个班次的结束时间发生模糊,然后是第一个班次的开始时间在第二个成员的星期一,当第一个成员的第二个班次的结束时间发生模糊时。周二等同样如何实现呢?目前,光标正在水平移动。

3 个答案:

答案 0 :(得分:2)

我在这里使用所有knockout向您展示其中一种方法。它向您展示了如何实现您的逻辑,因为我没有您的数据样本,您可能需要根据您的数据对其进行修改

工作示例https://jsfiddle.net/kyr6w2x3/48/

<强> HTML:

<table>
 <tbody>
   <!-- ko foreach: teamMembers -->
    <tr>
    <td data-bind="text:name"></td>
      <!-- ko foreach: days -->   
      <td>
      <h4 data-bind="text:name"></h4>
          <input type="text" data-bind="value: startTime ,hasFocus :getFocus">
          <input type="text" data-bind="value: endTime ,event:{blur: $root.endTimeBlur}">          

      </td>
      <!-- /ko -->       
    </tr>
<!-- /ko -->
 </tbody>
</table>

<强> JS:

var data ={
    teamMembers: [{
        Name: "Member A",
    id:1,
        days: [{startTime: '8:00',endTime: "4:00" ,name:'Monday',parentId:1},{startTime: '8:00',endTime: "4:00",name:'Tuesday',parentId:1},{startTime: '8:00',endTime: "4:00",name:'Wednesday',parentId:1},{startTime: '8:00',endTime: "4:00",name:'Thursday',parentId:1},{startTime: '8:00',endTime: "4:00",name:'Friday',parentId:1},{startTime: '8:00',endTime: "4:00",name:'Saturday',parentId:1},{startTime: '8:00',endTime: "4:00",name:'Sunday',parentId:1}]
    },
                   {
        Name: "Member B",
    id:2,
        days: [{startTime: '8:00',endTime: "4:00" ,name:'Monday' ,parentId:2},{startTime: '8:00',endTime: "4:00",name:'Tuesday' ,parentId:2},{startTime: '8:00',endTime: "4:00",name:'Wednesday',parentId:2},{startTime: '8:00',endTime: "4:00",name:'Thursday',parentId:2},{startTime: '8:00',endTime: "4:00",name:'Friday',parentId:2},{startTime: '8:00',endTime: "4:00",name:'Saturday',parentId:2},{startTime: '8:00',endTime: "4:00",name:'Sunday',parentId:2}]
    },
  {
        Name: "Member C",
    id:3,
        days: [{startTime: '8:00',endTime: "4:00" ,name:'Monday',parentId:3},{startTime: '8:00',endTime: "4:00",name:'Tuesday',parentId:3},{startTime: '8:00',endTime: "4:00",name:'Wednesday',parentId:3},{startTime: '8:00',endTime: "4:00",name:'Thursday',parentId:3},{startTime: '8:00',endTime: "4:00",name:'Friday',parentId:3},{startTime: '8:00',endTime: "4:00",name:'Saturday',parentId:3},{startTime: '8:00',endTime: "4:00",name:'Sunday',parentId:3}]
    },]

}
var memberViewModel = function(data) {
 var self = this ;
 self.days = ko.observableArray([]);
 self.name = ko.observable(data.Name);
 self.id = ko.observable(data.id); 
 self.days($.map(data.days, function (item) {
    return new daysViewModel(item);
 }));

}
var daysViewModel = function (data){
 var self = this ;
 self.getFocus = ko.observable(false);
 self.startTime = ko.observable(data.startTime);
 self.endTime = ko.observable(data.endTime);
 self.name = ko.observable(data.name)
 self.parentId = ko.observable(data.parentId);
}

function ViewModel() {
  var self = this;
  self.teamMembers = ko.observableArray([]);
  self.teamMembers($.map(data.teamMembers, function (item) {
    return new memberViewModel(item);
  }));
  self.endTimeBlur = function(data){
    ko.utils.arrayFirst(self.teamMembers(), function (item,i) {
      if (item.id() == data.parentId() && self.teamMembers()[i+1] ) {
        //here you set getFocus to true to make next member 's monday gets focus    
        self.teamMembers()[i+1].days()[0].getFocus(true);
        return;
      }
    });
  }
}  
  ko.applyBindings(new ViewModel());

答案 1 :(得分:1)

这对你有用......

jQuery(function($) {
  $('body').on("blur", "input[data-bind*='value: endTime']", function() {
    var
      $t = $(this), // Current input
      $td = $t.closest('td'), // Current input's parent td
      i = $td.find('input[data-bind*="value: endTime"]').index($t), // Index of current input = current shift index
      $target = $td.find('input[data-bind*="value: startTime"]').eq(i + 1); // Target is current shift + 1

    if ($target.length) {
      $target.focus();
    }
  });
});

我们的想法是绑定一个事件处理程序来模糊value: endTime属性中包含data-bind的每个输入的事件。
如果是这个处理程序,我们会在一天中找到endTime输入的索引,向其中添加1,并将startTime输入与该索引的焦点集中在同一个td(日)

由于元素在文档加载后不存在(但是由knockout渲染),我们将处理程序绑定到body,以便input[data-bind*='value: endTime']选择输入。

答案 2 :(得分:1)

我的建议是使用计算出的tabindex属性。

  • 在您的$root视图模型中,我们会计算一个shift.startend可观察数组的数组,就像您希望它们在焦点方面一样。
  • 我们还会创建一个工厂方法,为每个<input>绑定返回一个计算索引。
  • 每个输入都会获得attr: { 'tabindex': getTabIndex() }绑定,以确保索引保持最新状态

此方法适用于使用标签键在表单中导航的用户。最重要的是;现在您已经有了已排序的输入可观察量的计算列表,您可以轻松地绑定到事件以选择上一个/下一个。

以下是一个例子:

&#13;
&#13;
var Root = function() {
  this.members = ko.observableArray([]);

  for (var i = 0; i < 5; i += 1) {
    this.members.push(new Member());
  }

  // Note: you could do this in less lines of code, but I wanted
  // to be extra transparent to show the structure of the data
  // transform.
  var orderedShiftInputs = ko.pureComputed(function() {
    // We want the days to be leading, so we create a
    // two-dimensional array: [[meber1day1, member2day1], [member1day2], etc]
    // Note: members _cannot_ skip days
    var mergedDays = [];
    this.members().forEach(function(member) {
      member.days().forEach(function(day, index) {
        if (!mergedDays[index]) {
          mergedDays[index] = [];
        }

        mergedDays[index] = mergedDays[index].concat(day);
      });
    });

    // We flatten the 2d-array of days to a list of shifts:
    // [member1day1shift1, member1day1shift2, member2day1shift1, etc]
    var mergedShifts = mergedDays.reduce(function(shifts, days) {
      var allShifts = days.reduce(function(all, day) {
        return all.concat(day.shifts());
      }, []);
      return shifts.concat(allShifts);
    }, []);

    // We flatten the shifts into an array of start and end observables:
    // [member1day1shift1start, member1day1shift1end, etc.]
    return mergedShifts.reduce(function(inputs, shift) {
      return inputs.concat([shift.start, shift.end]);
    }, []);

  }, this);
  
  this.getTabIndex = function(data) {
    return ko.computed(function() {
      // Find the start or end data in our sorted array.
      // In this example, we can start with index 1. In your app,
      // there might be other input elements before the shifts...
      var START_TAB_INDEX = 1;
      return orderedShiftInputs().indexOf(data) + START_TAB_INDEX;
    }, this);
  }.bind(this);

}

var Member = function() {
  this.days = ko.observableArray([]);

  for (var i = 0; i < 2; i += 1) {
    this.days.push(new Day());
  }

}
var Day = function() {
  this.shifts = ko.observableArray([]);

  for (var i = 0; i < 3; i += 1) {
    this.shifts.push(new Shift());
  }
}

var Shift = function() {
  this.start = ko.observable(1);
  this.end = ko.observable(2);
}

ko.applyBindings(new Root());
&#13;
td {
  border: 1px solid black
}
input {
  display: inline;
  width: 30px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<table>
  <tbody>
    <!-- ko foreach: members -->
    <tr>
      <td data-bind="text: 'Member-' + $index()"></td>
      <!-- ko foreach: days -->
      <td>
        <span data-bind="text: 'Day ' + $index()"></span>
        <br/>
        <!-- ko foreach: shifts -->
        <input type="text" data-bind="value: start, 
                                      attr: { 'tabindex': $root.getTabIndex(start) }">
        <input type="text" data-bind="value: end, 
                                      attr: { 'tabindex': $root.getTabIndex(end) }">
        <!-- /ko -->
      </td>
      <!-- /ko -->
    </tr>
    <!-- /ko -->
  </tbody>
</table>
&#13;
&#13;
&#13;