【问题标题】:"Smart" text area auto indent“智能”文本区域自动缩进
【发布时间】:2010-08-14 13:45:05
【问题描述】:

我正在尝试制作一个自动缩进的文本区域,到目前为止它可以与以下代码一起使用。我遇到的问题是,我目前正在阻止默认操作按 Enter 以计算行中的选项卡,然后插入换行符。

这可行,但我想要 textarea 的默认操作,如果你按住 enter 键,它不会滚动 textarea,直到插入符号击中底行,然后滚动条与插入符号保持在最下面一行。如果在 textarea 中的任何位置使用,下面的当前代码将插入符号保持在视野中,但它会导致插入符号上方的内容向上滚动,这是一种折衷方案,因为插入符号不再消失。如果没有其他解决方案,这将正常工作,但我希望有其他想法。

    var start = this.selectionStart-1;
    var end = this.selectionEnd;
    var sT = this.scrollTop;
    var sH = this.scrollHeight;
    var vH = $(this).height();

    var x = (sH - sT) - vH;

    // Check if hitting enter on the first line as no newline will be found
    if (this.value.lastIndexOf('\n',start)==-1)
     var startSubstr = 0;
    else 
     var startSubstr = this.value.lastIndexOf('\n',start)+1;

    var endFirst = end - startSubstr;

    var valueToScan = this.value.substr(startSubstr,endFirst);
    var count = 0;

    // Count only \t at the beginning of the line, none in the code   
    while (valueToScan.indexOf('\t')!=-1) {
     if (valueToScan.indexOf('\t')!=0)
      break;
     count++;
     valueToScan = valueToScan.substr(valueToScan.indexOf('\t')+1);
    }

    // Command to isert the newline, and then add the \t's found in previously  
    $(this).insertAtCaret('\n');
    for (var i=0;i<count;count--) {
     $(this).insertAtCaret('\t');
    }  

    var sH = this.scrollHeight;
    this.scrollTop = (sH - x) - vH;

编辑 作为更新,为了消除任何混淆,我正在尝试创建一个 IDE 样式的文本框,例如在大多数 IDE 中,如果您键入以下内容

function example(whatever) {
     Example Stuff // And then hit enter here

我希望它带您到与“示例内容”相同的标签距离左边框,以使您的代码更易于阅读。我目前具有该功能,但问题是我正在拦截输入键,这意味着我必须提供该功能。我很难复制在光标碰到底部边框之前不滚动文本框的确切功能。因此,如果您在 textarea 的顶部按住 enter,光标只会向下滚动 textarea,移动任何文本直到它碰到底部边框,然后 textarea 的滚动条将跟随光标。有意义吗?

EDIT 2 更新标签以表明代码使用 PHP

在发布这篇文章的同时,我一直在处理这个问题。我认为,当我有机会时,我将探索的另一个选择是,而不是阻止输入,只允许默认操作按 Enter 键并将字符串从lastIndexOf('\n')-1 读取到最新的\n,以获取任何\t。我认为这会给我我正在寻找的字符串,但不会弄乱 textarea 的行为。待测试后再更新。

EDIT 3 已解决,根据我之前的更新,我决定在按下键后扫描字符串,保留自然行为(为感兴趣的人添加了下面的部分)和唯一真正的问题剩下的是,如果你按住 enter,它不会计算从 enter 按下的原点开始的缩进,这对我来说很好。我将把这个给 http://stackoverflow.com/users/15066/matyr'>matyr,虽然在他回复之前我确实知道他仍然是最接近的。

if (this.value.lastIndexOf('\n',start-2)==-1) {
 var startSubstr = 0;
} else {
 var startSubstr = this.value.lastIndexOf('\n',start-1)+1;
}    
var valueToScan = this.value.substr(startSubstr,start);

【问题讨论】:

    标签: php javascript jquery


    【解决方案1】:

    我想要textarea的默认动作

    如何绑定到keyup 而不是keydown/keypress 并在本机换行符后插入制表符?

    滚动条在底行与插入符号保持一致

    您可以通过恢复scrollTop来保留滚动位置。

    <!DOCTYPE html>
    <title>autoindent example</title>
    <textarea id="TA" rows="8"></textarea>
    <script>
    document.getElementById('TA').addEventListener('keyup', function(v){
      if(v.keyCode != 13 || v.shiftKey || v.ctrlKey || v.altKey || v.metaKey)
        return;
      var val = this.value, pos = this.selectionStart;
      var line = val.slice(val.lastIndexOf('\n', pos - 2) + 1, pos - 1);
      var indent = /^\s*/.exec(line)[0];
      if(!indent) return;
      var st = this.scrollTop;
      this.value = val.slice(0, pos) + indent + val.slice(this.selectionEnd);
      this.selectionStart = this.selectionEnd = pos + indent.length;
      this.scrollTop = st;
    }, false);
    </script>
    <p>(not considering IE here)
    

    【讨论】:

    • 保持滚动位置不是问题,它允许光标在每个新行跟随它之前继续到文本区域的底部。根据我最近的更新,我将尝试使用 keyup 而不是 keydown。
    • 如果你使用 KEYUP 意味着它会触发每个按钮按下,实际上我们有时需要按住一个按钮来拥有多个事件。在这种情况下,KEYDOWN 更好。 KEYDOWN 事件也会在 textarea 字符更新之前触发,因此您想使用 el.keydown(function(e){setTimeout(function(e){/*YOUR KEYDOWN ACTION*/},1) });
    【解决方案2】:

    您是否注意到 Stack Overflow 文本区域如何处理代码?如果你输入:

    function example(whatever) {
        Example Stuff // And then hit enter here
    }
    

    起初,什么都不会发生。然后,当您缩进时(通过键入或单击 101010 按钮),它会在代码上放置不同的背景。 然后,稍等片刻之后,它会在语法上为代码着色。但是,如果您再次开始输入,它会变回黑/白。

    我认为类似的方法可能对您有用。您应该做的是:

    1. 连接一个正常的 onKeySomething 事件,但不要只寻找“输入”;每次按键后:

      1A。将一些全局变量(例如计时器)设置为 new Date();

      1B。 setTimeout(X, timeoutFunction) 其中 X 是您希望在用户停止输入后等待的时间

    2. 创建超时函数;这个函数应该检查全局“timer”变量,如果 new Date() - timer > X trigger actualFunction()

    3. actualFunction 然后可以解析 textarea 的内容,缩进任何你喜欢的东西,并且不会中断用户的正常工作流程

    我知道这并不是“真正的”IDE 的行为方式,但考虑到 JS 和 Web 的限制,它可能是最适合您的方法。

    【讨论】:

    • 该项目的目的是为了能够直接在textarea中编码,并在用户完成后清理代码。
    • 澄清,*不要在用户完成输入后清理代码。我更喜欢像IDE这样的实时。总有办法做某事,你只需要有足够的创造力。我相信我最终会找到方法的;)
    • 好吧,我并不是说你的方法是不可能的,但是......你必须记住,大多数用户运行的不是四核/12 GB RAM 的谷歌浏览器;在运行 IE/Firefox 的普通系统上,JS 性能有点差。因此,即使您找到了“完美”的解决方案,由于 JS 性能滞后,您的大多数用户仍然可能会非常失望。 (PS 如果你能依靠好的硬件+Chrome,没关系)。换句话说,我敢肯定,如果可以的话,SO 的人会让他们的 textarea 响应更快……但他们没有(因为这些限制)。
    【解决方案3】:

    如何子类化文本框并手动处理 WndProc?这可以让您获得更精细的控制,并解决打字键重复问题(KeyPress 和类似事件仅在您按住键时触发一次)。

    public class MyTextBox : System.Windows.Forms.TextBox
    {
        protected override void WndProc(ref Message m)
        {
            // Let the O/S handle the key first
            base.WndProc(ref m);
    
            // Then, if it's the return key, append tabs
            int numTabs = 3;                 // TODO: insert your own value here
            const int WM_CHAR = 0x0102;
            if(m.Msg == WM_CHAR && (char)m.WParam == '\r')
            {
                m.WParam = new IntPtr('\t'); // Recycle m since base is done with it
                for (int i = 0; i < numTabs; i++)
                    WndProc(ref m);
            }
        }
    }
    

    【讨论】:

    • 为什么有人反对我?从原始帖子中并不完全明显。 :(
    【解决方案4】:

    我知道这不是一个直截了当的答案,但是您可以查看网络上的一些示例,这些示例确实可以帮助您实现这一点。

    http://jsfiddle.net
    http://teddevito.com/demos/textarea.html
    http://thelackthereof.org/JQuery_Autoindent

    如果我有更多时间,我肯定会试一试,但不幸的是我没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 1970-01-01
      • 2011-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多