获取文本区域中的光标位置

Posted

技术标签:

【中文标题】获取文本区域中的光标位置【英文标题】:Getting cursor position in a Textarea 【发布时间】:2010-09-25 08:51:36 【问题描述】:

我正在尝试在文本区域中实现自动完成(类似于http://www.pengoworks.com/workshop/jquery/autocomplete.htm)。

我想要做的是,当用户输入一组特定的字符(比如插入:)时,他们将获得一个 AJAX 填充的 div,其中包含可能的可选匹配项。

在常规文本框中,这当然很简单,但在文本区域中,我需要能够根据光标在屏幕上的正确位置弹出 div。

任何人都可以提供任何方向吗?

谢谢, -M

【问题讨论】:

【参考方案1】:

您可以使用 document.selection.createRange() 获取插入符号,然后检查它以显示您需要的所有信息(例如位置)。详情请见thoseexamples。

【讨论】:

【参考方案2】:

在文本区域中实现自动完成并不是那么容易。我实现了一个 jquery 插件,我必须创建一个 texarea 的克隆来猜测光标在 textarea 内的位置。 它的工作,但它并不完美。

您可以在这里查看:http://www.amirharel.com/2011/03/07/implementing-autocomplete-jquery-plugin-for-textarea/

希望对你有帮助。

【讨论】:

【参考方案3】:
    function getCursor(nBox)
    var cursorPos = 0;
    if (document.selection) 
        nBox.focus();
        var tmpRange = document.selection.createRange();
        tmpRange.moveStart('character',-nBox.value.length);
        cursorPos = tmpRange.text.length;
    
    else
        if (nBox.selectionStart || nBox.selectionStart == '0')
            cursorPos = nBox.selectionStart;
        
    

    return cursorPos;


function detectLine(nBox,lines)
    var cursorPos = getCursor(nBox);
    var z = 0; //Sum of characters in lines
    var lineNumber = 1;
    for (var i=1; i<=lines.length; i++)
        z = sumLines(i)+i; // +i because cursorPos is taking in account endcharacters of each line.
        if (z >= cursorPos)
            lineNumber = i;
            break;
        
    

    return lineNumber;

    function sumLines(arrayLevel)
        sumLine = 0;
        for (var k=0; k<arrayLevel; k++)
            sumLine += lines[k].length;
        
        return sumLine;
    




function detectWord(lineString, area, currentLine, linijeKoda)
    function sumWords(arrayLevel)
        var sumLine = 0;
        for (var k=0; k<arrayLevel; k++)
            sumLine += words[k].length;
               
        return sumLine;
    


    var cursorPos = getCursor(area);
    var sumOfPrevChars =0;
    for (var i=1; i<currentLine; i++)
        sumOfPrevChars += linijeKoda[i].length;
    

    var cursorLinePos = cursorPos - sumOfPrevChars;

    var words = lineString.split(" ");
    var word;
    var y = 0;


    for(var i=1; i<=words.length; i++)
        y = sumWords(i) + i;
        if(y >= cursorLinePos)
            word = i;
            break;
        
    

    return word;


var area = document.getElementById("area");
var linijeKoda = area.value.split("\n");
var currentLine = detectLine(area,linijeKoda);
var lineString = linijeKoda[currentLine-1];
var activeWord = detectWord(lineString, area, currentLine, linijeKoda);
var words = lineString.split(" ");
if(words.length > 1)
  var possibleString = words[activeWord-1];

else
  var possibleString = words[0];

这样就可以了... :)

【讨论】:

【参考方案4】:

一个丑陋的解决方案:

即:使用 document.selection...

对于ff:在textarea后面使用pre,将光标前的文本粘贴到其中,在其后放置一个标记html元素(cursorPos),并通过该标记元素获取光标位置

注意事项:|代码很丑,抱歉| pre 和 textarea 字体必须相同 |不透明度用于可视化 |没有自动完成功能,这里只有一个光标跟随 div(当您在 textarea 中输入时)(根据您的需要进行修改)

<html>
<style>
pre.studentCodeColor
    position:absolute;
    margin:0;
    padding:0;
    border:1px solid blue;
    z-index:2;

textarea.studentCode
    position:relative;
    margin:0;   
    padding:0;
    border:1px solid silver;    
    z-index:3;
    overflow:visible;
    opacity:0.5;
    filter:alpha(opacity=50);

</style>

hello world<br/>
how are you<br/>
<pre class="studentCodeColor" id="preBehindMyTextarea">
</pre>
<textarea id="myTextarea" class="studentCode" cols="100" rows="30" onkeyup="document.selection?ieTaKeyUp():taKeyUp();">
</textarea>

<div 
    style="width:100px;height:60px;position:absolute;border:1px solid red;background-color:yellow"
    id="autoCompleteSelector">  
autocomplete contents
</div>

<script>
var myTextarea = document.getElementById('myTextarea');
var preBehindMyTextarea = document.getElementById('preBehindMyTextarea');
var autoCompleteSelector = document.getElementById('autoCompleteSelector');

function ieTaKeyUp()
    var r = document.selection.createRange();
    autoCompleteSelector.style.top = r.offsetTop;
    autoCompleteSelector.style.left = r.offsetLeft;

function taKeyUp()
    taSelectionStart = myTextarea.selectionStart;   
    preBehindMyTextarea.innerHTML = myTextarea.value.substr(0,taSelectionStart)+'<span id="cursorPos">';
    cp = document.getElementById('cursorPos');
    leftTop = findPos(cp);

    autoCompleteSelector.style.top = leftTop[1];
    autoCompleteSelector.style.left = leftTop[0];

function findPos(obj) 
    var curleft = curtop = 0;
    if (obj.offsetParent) 
        do 
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
         while (obj = obj.offsetParent);
    
    return [curleft,curtop];

//myTextarea.selectionStart 
</script>
</html>

【讨论】:

以上是关于获取文本区域中的光标位置的主要内容,如果未能解决你的问题,请参考以下文章

在文本区域中的光标位置之后插入文本

识别不同文本区域中的光标位置并在列表框中选择项目时插入文本

将光标设置到文本区域中特定行上的特定位置

如何在 HTML 文本区域中找到光标位置(X/Y,而不是行/列)? [复制]

在文本区域中找出光标的“行”(行)号

jquery在contenteditable div中设置光标位置