测量输入时间
Measuring time for input
我有一个包含多个输入和选择的简单测验表格,我需要测量参赛者 write/choose 回答所花费的时间。
这就是我正在尝试的方法,但它报告的时间不正确:
$('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>
试试这个..
<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();
});
您可以在 this fiddle 中找到我尝试过的内容。
对我来说,要点是你一遍又一遍地加起来,因为初始时间没有改变,而且你不止一次地添加了回答时间。
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
,比如说,不计算从最后一个 input
到 blur
的时间绝对不是看页面和可能在写字板环境中写答案的时间)。
在一个公平和安全的系统中,恕我直言,考虑某人查看测验的时间要多于 s/he 实际写答案的时间。但这显然取决于测验的目的!
在与您(OP)交谈后,我对您的基本代码进行了一些调整。
首先,每次表单元素获得焦点时都会调用 .on('input ...')
,因此事件处理程序会堆积起来。在模糊处理程序中调用相应的 .off('input ...')
来处理此问题。
接下来,要在 JavaScript 中创建关联数组,我们通常使用对象,所以我创建了 times = {}
。
接下来,times[name] = times[name] + (b - a);
继续使用元素首次聚焦时 a
的初始时间值,因此聚合时间会快速累积。我们可以通过在之后设置 a = b;
来弥补这一点。
最后,为了跟踪 select 何时发生变化,就像输入发生变化时一样,我们可以在 select 时更新内部 selected 值,如 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>
我为此制作了简单的 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 对象以获取编辑时间。
我有一个包含多个输入和选择的简单测验表格,我需要测量参赛者 write/choose 回答所花费的时间。
这就是我正在尝试的方法,但它报告的时间不正确:
$('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>
试试这个..
<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();
});
您可以在 this fiddle 中找到我尝试过的内容。 对我来说,要点是你一遍又一遍地加起来,因为初始时间没有改变,而且你不止一次地添加了回答时间。
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
,比如说,不计算从最后一个 input
到 blur
的时间绝对不是看页面和可能在写字板环境中写答案的时间)。
在一个公平和安全的系统中,恕我直言,考虑某人查看测验的时间要多于 s/he 实际写答案的时间。但这显然取决于测验的目的!
在与您(OP)交谈后,我对您的基本代码进行了一些调整。
首先,每次表单元素获得焦点时都会调用 .on('input ...')
,因此事件处理程序会堆积起来。在模糊处理程序中调用相应的 .off('input ...')
来处理此问题。
接下来,要在 JavaScript 中创建关联数组,我们通常使用对象,所以我创建了 times = {}
。
接下来,times[name] = times[name] + (b - a);
继续使用元素首次聚焦时 a
的初始时间值,因此聚合时间会快速累积。我们可以通过在之后设置 a = b;
来弥补这一点。
最后,为了跟踪 select 何时发生变化,就像输入发生变化时一样,我们可以在 select 时更新内部 selected 值,如 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>
我为此制作了简单的 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 对象以获取编辑时间。