测量输入时间

3
我是一个有用的助手,可以为您翻译文本。
我有一个简单的测验表单,其中包含几个输入和选择项,我需要测量参赛者编写/选择答案所花费的时间。
这是我尝试的方法,但它报告了不正确的时间:

$('input, select').on('focus', function(event) {

    el = $(this);

    name = el.attr('name'); // console.log(name);
    a = performance.now();
    a_value = el.val();

    console.log(name + ' focused.');

    $(el).on('input select cut copy paste', function(event) {
        console.log('el: ' + el);
        b_value = el.val();
        if (a_value != b_value) {
            b = performance.now();
            if (name in times) {
                console.log('exists');
                times[name] = times[name] + (b - a);
            } else {
                times[name] = b - a;
            }
        }
    });

    $(el).on('blur', function(event) {
        alert(times);
    });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>

  <input type="text" name="" id="">
  <select name="" id="">
    <option value="">option1</option>
    <option value="">option2</option>
  </select>
  
</body>
</html>


我认为你可以使用这个问题 - sharp
1
如果 (name in times) 中的 times 是什么?在控制台中它显示为未定义。 - Harsh
请修复代码片段。 - Parth Trivedi
@Drakes 1) 是的,这将成为数组中的键 2) 选择也将具有“selected”选项的值 3) 不完全是这样,就像输入一样,选择也应根据我与其交互的时间(聚焦,更改选择等)而增加时间。对于“聚焦”状态,我考虑添加一个计时器,在用户将字段聚焦但离开电脑后x秒钟停止。 - eozzy
4个回答

2

在与您(OP)交谈后,我对您的基础代码进行了几个调整。

首先,.on('input ...') 每次表单元素聚焦时都会被调用,因此事件处理程序会堆叠。 在失去焦点的处理程序中调用相应的 .off('input ...') 以处理这个问题。

其次,在 JavaScript 中创建关联数组通常使用对象,所以我创建了 times = {}

接下来,times[name] = times[name] + (b - a); 持续使用了当元素首次聚焦时的初始时间值 a,因此汇总时间快速增加。 我们可以通过设置 a = b; 来弥补这一点。

最后,为了跟踪选择器何时发生更改,就像输入更改时一样,我们可以在选择已更改时更新内部选定的值,例如 a_value = b_value;

希望这是您要寻找的内容。

var times = {};
$('input, select').on('focus', function(event) {
  var el = $(this);

  // This will get the name of the input or select. Is that right?
  // OP: yes, this becomes the key in the array
  var name = el.attr('name');
  var a = performance.now();
  var a_value = el.val();

  // This will attach an event handler over and over unless we 
  // unattach it. Please see "blur" below
  el.on('input select cut copy paste', function(event) {
    var b_value = el.val();

    // Initial values are updated as inputs change
    // so the times don't stack up
    if (a_value !== b_value) {
      b = performance.now();
      if (times.hasOwnProperty(name)) {
        console.log('exists');
        times[name] = times[name] + (b - a);
        a = b;
      } else {
        console.log('adding ' + name);
        times[name] = b - a;
      }
      a_value = b_value;
    }
  });

  el.one('blur', function(event) {
    console.dir(times);

    // Update the times display
    displayTimes();

    // Unattach the event handler added in on("focus")
    el.off('input select cut copy paste');
  });

  // For the demo
  function displayTimes() {
    // Output results
    var str = "";
    $.each(times, function(key, value) {
      str += key + " total time: " + value + "<br>";
    });
    $("#results").html(str);
  }

  // Periodically update the times just for the demo
  setInterval(displayTimes, 200);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="input" id="">
<select name="select" id="">
  <option value="option1">option1</option>
  <option value="option2">option2</option>
</select>
<div id="results"></div>


1
太棒了!虽然它的功能很好,但考虑到我需要处理太多的计时器,我想我会使用tock.js来启动、暂停、分段和停止计时器。不过还是谢谢你! - eozzy

1
请尝试这个..

<script>
  var Stopwatch = (function() {
            var s;
            return {
                settings: {
                    stop: 0,
                    sw: document.querySelectorAll(".stopwatch")[0],
                    results: document.querySelectorAll(".results")[0],
                    mills: 0,
                    secs: 0,
                    mins: 0,
                    i: 1,
                    times: ["00:00:00"],
                    clearButton: "<a href=\"#\" class=\"button\" onClick=\"Stopwatch.clear();\">Clear</a>"
                },
                init: function() {
                    s = this.settings;
                    setInterval(this.timer, 1);
                },
                clear: function() {
                    s.i = 1,
                    s.times = ["00:00:00"],
                    s.results.innerHTML = s.clearButton;
                },
                lap: function() {
                    if (s.i === 1) {
                        s.results.innerHTML = s.clearButton;
                    }
                    s.times.push(("0" + s.mins).slice(-2) + ":"
                                         + ("0" + s.secs).slice(-2) + ":"
                                         + ("0" + s.mills).slice(-2));
                    var diffTime = ("0" + Math.floor(s.times[s.i].split(":")[0]
                                             - s.times[s.i-1].split(":")[0])).slice(-2)
                                             + ":"
                                             + ("0" + Math.floor(s.times[s.i].split(":")[1]
                                             - s.times[s.i-1].split(":")[1])).slice(-2)
                                             + ":"
                                             + ("0" + (s.times[s.i].split(":")[2]
                                             - s.times[s.i-1].split(":")[2])).slice(-2);
                    s.results.innerHTML = s.results.innerHTML + "<tr><td>"
                                                            + s.times[s.i] + "</td><td>"
                                                            + diffTime + "</td></tr>";
                    s.i++;
                },
                restart: function() {
                    s.mills = 0,
                    s.secs = 0,
                    s.mins = 0;
                    this.start();
                },
                start: function() {
                    s.stop = 0;
                },
                stop: function() {
                    s.stop = 1;
                },
                timer: function() {
                    if (s.stop === 0) {
                        if (s.mills === 100) {
                            s.secs++;
                            s.mills = 0;
                        }
                        if (s.secs === 60) {
                            s.mins++;
                            s.secs = 0;
                        }
                        s.sw.innerHTML = ("0" + s.mins).slice(-2) + ":"
                                                     + ("0" + s.secs).slice(-2) + ":"
                                                     + ("0" + s.mills).slice(-2);
                        s.mills++;
                    }
                }
            };
        })();
$('.textbox,.selectbox').focusin(function(event) {
 Stopwatch.init();
Stopwatch.restart();    
});
$('.textbox,.selectbox').on('blur', function(event) {
    Stopwatch.stop();
});

这里有一个可工作的Fiddle示例

参考资料


不完全是我想要的,但秒表参考很有帮助,谢谢! - eozzy

1
我已经制作了一个简单的jquery插件。它可以告诉你任何输入元素的编辑总时间(仅在实际使用时进行编辑),第一次编辑时间和最后一次编辑时间。您还可以获取所有编辑时间。
(function () {
    var getTime = function () { return performance.now(); };
    function MeasureTime () {
        this.editTimes = [];
        this.currentEdit = null;
        this.lastEdit = {start:0, last: 0};
        this.firstEdit = 0;
    }
    MeasureTime.prototype = {
        setFirst: function () {
            this.firstEdit = getTime();
            this.setFirst = new Function();
        },
        startEdit: function (val) {
            this.setFirst();
            if(this.currentEdit == null) {
                this.currentEdit = {start: getTime(), last: getTime(), value: val};
                this.editTimes.push(0);
            } else {
                this.edit(val);
            }
        },
        edit: function (val) {
            if(this.currentEdit == null)
                  this.startEdit(val);
            else {
                var current = this.currentEdit;
                if(current.value == val)
                    return;
                current.last = getTime();
                this.editTimes.pop();
                this.editTimes.push(current.last - current.start);
            }
        },
        stopEdit: function () {
            if(this.currentEdit != null) {
                this.lastEdit = this.currentEdit;
                this.currentEdit = null;
            }
        },
        getEvent: function () {
            return new TimeMeasuredEvent(this.editTimes, this.currentEdit || this.lastEdit, this.firstEdit);
        }
    };
    function TimeMeasuredEvent (all, current, first) {
        this.all = all.slice(0);
        this.start = current.start;
        this.last = current.last;
        this.first = first;
    }
    TimeMeasuredEvent.prototype = {
        current: function () {
            return this.all[this.all.length-1];
        },
        total: function () {
            var sum = 0, a = this.all, l = a.length, i = -1;
            while(++i<l)
                sum+=a[i];
            return sum;
        }
    };
    function EnsureMeasureTime () {
        if (typeof(this.measureTimeData) === "undefined") {
            var mtd = this.measureTimeData = new MeasureTime();
            $(this).on('focus', function () {
                mtd.startEdit(this.value);
        $(this).on('input.measuretime select.measuretime cut.measuretime copy.measuretime paste.measuretime', function () {
           mtd.edit(this.value);
           $(this).trigger('timeMeasured', [mtd.getEvent()]); 
        });
            $(this).on('blur', function () {
                mtd.stopEdit();
                $(this).trigger('timeMeasured', [mtd.getEvent()]); 
                $(this).off('measuretime');
            });
        });
        }
    }
    $.fn.measureTime = function () {
        $(this).each(EnsureMeasureTime);
        return this;
    };
})();

示例用法(fiddle):

var inputs = $('input, select');
inputs.measureTime();
var all = {};
inputs.on('timeMeasured', function (ev, data) {
    console.log(ev, data);
    all[ev.target.name] = data.total();
    console.log("First edit time: " + data.first);
    console.log("Last edit time: " + data.last);
    console.log("All edits durations: " + data.all.join(", "));
    console.log("Current edit duration: " + data.current());
    console.log("Total edit duration: " + data.total());
    var s = "";
    for(var n in all) {
        s+= n + ": " + all[n]+"\n";
    }
    $("#times").text(s);
});

你也可以通过element.measureTimeData访问原始的MeasureTime对象,以获取编辑时间。

0
你可以在这个代码片段中找到我尝试的内容。 对我来说,最重要的是你一遍又一遍地累加时间,因为初始时间没有改变,你多次添加了回答时间。
if (name in times) {
    console.log('exists');
    times[name] = times[name] + (b - a);
    //here you already had added (b1 - a) with b1 < b
    //either you reset 'a' here or you store the diff in a variable and sum it up at the end
} else {
    times[name] = b - a;
}

我将答题时间存储在一个变量中,并在blur时添加到数组中,尽可能与您的原始方法保持一致。

然而,仍有一些我错过的东西,主要与作弊有关。据我所知,您只想计算真正的更改时间(从focus到最后一个input),不计算从最后一个inputblur的时间,也绝对不计算查看页面和在Wordpad环境中编写答案的时间。

在一个公平和安全的系统中,我认为您应该考虑某人在浏览测试时所花费的时间,而不是实际编写答案的时间。但这显然取决于测试的目的!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接