如何使用javascript高效地记录用户输入?

如何使用javascript高效地记录用户输入?,javascript,Javascript,我希望能够录制并回放文本区域中发生的任何事情 我遇到过一些解决方案,但它们并不可靠,比如通过AJAX发送每次击键。在这种情况下,我的数据库中会有数百万行 我想到的想法是将击键记录到客户端的一个变量,用操作更新该变量,但跟踪每个击键之间的时间。还要确保它也支持删除数据 最后,我会将整个变量发送到db一次,然后我可以稍后对其进行解码以便播放 关于变量外观的思维导图: hellooo[1.2][backspace][0.6][backspace]World![return] Idle time

我希望能够录制并回放文本区域中发生的任何事情

我遇到过一些解决方案,但它们并不可靠,比如通过AJAX发送每次击键。在这种情况下,我的数据库中会有数百万行

我想到的想法是将击键记录到客户端的一个变量,用操作更新该变量,但跟踪每个击键之间的时间。还要确保它也支持删除数据

最后,我会将整个变量发送到db一次,然后我可以稍后对其进行解码以便播放

关于变量外观的思维导图:

   hellooo[1.2][backspace][0.6][backspace]World![return]
Idle time __^     Removes one char __^
我相信google docs正在做类似的事情来回放用户键入的内容


有什么想法吗?

幸运的是,JavaScript事件已经为您解决了所有编码问题。您可以直接将keyup/keydown/keypress/任何内容所包含的整个事件对象放入数组中

每个对象包含:

  • 事件类型
  • 时间戳
  • 使用了什么键(或组合键)
  • 焦点是什么
  • 其他一些可能最终有用的东西
然后,您可以对阵列进行编码,并使用您最喜欢的ajax方法将其发送到服务器进行存储

因此,您的代码只需要一个可以存储数据的函数。不要使用这个确切的函数,它只是为了演示

var handler = function (e) { 
    handler.data.push(e);
    console.log(handler.data);
}
handler.data = [];

window.addEventListener("keyup",    handler); 
window.addEventListener("keydown",  handler); 
window.addEventListener("keypress", handler);
因为它是一个数组,所以它们都应该是有序的,但在奇怪的事件中,它会出错,每个事件都有时间戳数据(这也让你可以找出事件之间的延迟,如果你使用混合按键,这是非常棒的)


然后,您可以按照自己的意愿重新播放事件——但现在您不必发明自己的规范,因为w3c可爱的fokes在设计DOM事件规范时为您做了所有艰苦的工作。

数据库可以处理数百万条记录,所以这不是一个真正的问题


如果您仍然不想这样做,您可以将与会话相关的所有数据编码为JSON,并将其存储在数据库的文本字段中或服务器上的文件中。在这种情况下,如果数据确实很大,则加载数据并将其发送到浏览器可能需要一段时间,从而导致用户延迟。

存储每个操作的时间和该操作的结果,以及完成序列化日志并存储该日志。
单独重播每个动作过于复杂。假设一个用户向后移动几个字符并在那里添加新字符。您需要跟踪光标位置。
只需记住每次击键时textarea的整个值。没有必要记得那是怎么发生的,是吗

这是一个实现


变量回放={
//在对象中存储操作发生的时间和结果状态
//不要使用数组,因为它们不是稀疏间隙键
//必须进行迭代
记录:{},
初始化:函数(recorderId、playbackId){
this.recorder=document.getElementById(recorderId);
this.playback=document.getElementById(playbackId);
this.recorder.addEventListener('focus',function(){
Playback.record={};
这个值=“”;
},假);
this.recorder.addEventListener('keyup',函数(e){
Playback.record[(new Date()).getTime()]=this.value;
},假);
this.recorder.addEventListener('blur',函数(e){
Playback.Playback.value='';
//存储序列开始的时间
//这样我们就可以从后面的动作中减去它
var-mark=null;
for(Playback.record中的变量t){
如果(标记){
var超时=t标记;
}否则{
var超时=0;
马克=t;
}
//我们需要创建一个回调函数,它结束于t的值
//因为在运行此命令时,t会发生变化
setTimeout(Playback.changeValueCallback(Playback.record[t]),超时);
}
},假);
},
changeValueCallback:函数(val){
返回函数(){Playback.Playback.value=val}
}
}
init('recorder','Playback');
警告:
事件处理仅适用于兼容浏览器,您需要自己适应internet explorer

服务器不是用来处理数百万ajax查询的,至少是我的服务器+我绝对不会对每个事件都提出一个记录请求。在每个请求中可以同时发送许多事件。我喜欢你的回答,非常清楚,而且我忘记了序列化javascript事件数组+1Thanks@Ryan很高兴您发现它很有用。我正在尝试使用以下命令触发事件:
$(“#回放”).trigger(e)但它不输入字符,我假设它只触发回调函数,有什么想法吗?那么你用鼠标移动光标的方法是什么?@Ryan My方法会完全记录所有发生的数据以及绑定到处理程序的事件发生的时间。我对jQuery的触发器不太熟悉。但是,我实际上一直在一个新的textarea上重新触发事件,虽然没有输入,但似乎收到了事件。谢谢@meouw,这似乎是一个快速的n脏的替代方案,我也喜欢,但它需要更多的存储空间,因为当textarea的值变大时,它被越来越多地复制,直到输入一段时间后变成一个巨大的200MB文件:D
<textarea id="recorder"></textarea>
<textarea id="playback"></textarea>

<script type="text/javascript">

var Playback = {
    //store the time an action occured and the resulting state in an object
    //don't use an array because they are not sparce - interstitial keys
    //will have to be iterated over
    record: {},
    init: function( recorderId, playbackId ) {
        this.recorder = document.getElementById( recorderId );
        this.playback = document.getElementById( playbackId );

        this.recorder.addEventListener( 'focus', function() {
            Playback.record = {};
            this.value = '';
        }, false );

        this.recorder.addEventListener( 'keyup', function( e ) {
            Playback.record[ (new Date()).getTime() ] = this.value;
        }, false );

        this.recorder.addEventListener( 'blur', function( e ) {
            Playback.playback.value = '';
            //store the time the sequence started
            //so that we can subtract it from subsequent actions
            var mark = null;
            for( var t in  Playback.record ) {
                if( mark ) {
                    var timeout = t - mark;
                } else {
                    var timeout = 0;
                    mark = t;
                }
                // We need to create a callback which closes over the value of t
                // because t would have changed by the time this is run
                setTimeout( Playback.changeValueCallback( Playback.record[t] ), timeout );
            }
        }, false );

    },

    changeValueCallback: function( val ) {
        return function() { Playback.playback.value = val }
    }
}

Playback.init( 'recorder', 'playback' );

</script>