2013-06-25 75 views
5

如何将我的下拉菜单放置在textarea内的光标位置?我发现这个问题已经在这里问了很多次,但我不能够弄清楚正确的解决方案..如何在textarea内的光标位置放置下拉菜单?

这是JSBIN

请帮我看看你的建议

在此先感谢

+0

我想不出有什么办法在文本框中这样做,因为你不能在文本框中插入一个元素。有可能的是使用带有contentEditable =“true”的div,并以某种方式将其格式化为文本框。您可以使用selectionStart确定偏移量,然后用'abcd

yourdiv
efgh'替换'abcd [cursor] efgh'。由于这不是你的问题的答案,我会留下它作为评论。 – Sumurai8

+0

是的,我试着用contenteditable div但是在插入另一个div在光标位置时遇到了问题。我想插入一个div时,我在光标位置键入'@',并没有找到一种方法去...使用.append()不会插入光标位置的div时,我键入'@'中间的任何地方http://jsbin.com/uyufiw/25/edit – selvagsz

+0

'$('#target')。selectionStart'或类似的东西可以用来查找光标的偏移量,您可以使用它来创建两个子串。一个从开始到游标,一个从游标到结束。然后你可以用'firststring + yourdiv + laststring'替换$('#target')'的内容。要插入某些东西,可以用所选的选项替换'

    '。 (这只是半句法,但在li元素上有'this.parent.outerHTML = this.value'之类的东西。) 同样很抱歉,我无法真正在这台计算机上测试,所以无法做到很多,但给出了神秘的线索。 – Sumurai8

    回答

    0

    您可以获取鼠标的位置,然后将下拉列表移至此位置。 您只需确保弹出窗口内容具有比您想要遮挡的元素更高的Z-index,并且它的位置已设置为绝对。

    这是我写过一次的小测试样本。

    <!DOCTYPE html> 
    <html> 
    <head> 
    <script> 
    function byId(e){return document.getElementById(e);} 
    function newEl(tag){return document.createElement(tag);} 
    function newTxt(txt){return document.createTextNode(txt);} 
    function toggleClass(element, newStr) 
    { 
        index=element.className.indexOf(newStr); 
        if (index == -1) 
         element.className += ' '+newStr; 
        else 
        { 
         if (index != 0) 
          newStr = ' '+newStr; 
         element.className = element.className.replace(newStr, ''); 
        } 
    } 
    function forEachNode(nodeList, func) 
    { 
        var i, n = nodeList.length; 
        for (i=0; i<n; i++) 
        { 
         func(nodeList[i], i, nodeList); 
        } 
    } 
    
    window.addEventListener('load', mInit, false); 
    
    function mInit() 
    { 
    } 
    
    function onShowBtn(e) 
    { 
        var element = byId('popup'); 
        element.className = element.className.replace(' hidden', ''); 
        var str = '';//'border-radius: 32px; border: solid 5px;'; 
        e = e||event; 
        str += "left: " + e.pageX + "px; top:"+e.pageY+"px;" 
        element.setAttribute('style',str); 
    } 
    function onHideBtn() 
    { 
        var element = byId('popup'); 
        if (element.className.indexOf(' hidden') == -1) 
         element.className += ' hidden'; 
    } 
    
    </script> 
    <style> 
    #controls 
    { 
        display: inline-block; 
        padding: 16px; 
        border-radius: 6px; 
        border: solid 1px #555; 
        background: #AAA; 
    } 
    #popup 
    { 
        border: solid 1px #777; 
        border-radius: 4px; 
        padding: 12px; 
        background: #DDD; 
        display: inline-block; 
        z-index: 2; 
        position: absolute; 
    } 
    #popup.hidden 
    { 
        visibility: hidden; 
    } 
    </style> 
    </head> 
    <body> 
        <div id='controls'> 
         <input type='button' value='show' onclick='onShowBtn()'> 
         <input type='button' value='hide' onclick='onHideBtn()'> 
        </div> 
        <br> 
        <div id='popup'> 
         <p>This is some assorted 
          text</p> 
          <hr> 
         <ul> 
          <li>item a</li> 
          <li>item 2</li> 
          <li>item iii</li> 
         </ul> 
        </div> 
    </body> 
    </html> 
    
    +1

    我如何阅读它,OP是询问如何在光标位置显示某些东西(即显示您正在输入的文本框中的哪个位置) - 或换句话说,如何获取光标的坐标,* not *其中鼠标是当用户按下某个键时,而不是*如何在这些坐标上显示某些内容。对于keyDown事件,e.pageX不存在。 – Sumurai8

    +0

    确实。我刚刚重新阅读。现在看起来很清楚。对于我错误回答的问题,这是一个完全不同的问题。谢谢。 :) – enhzflep

    3

    我知道这是不是对这个问题的确切答案(此解决方案不使用一个文本,而是一个CONTENTEDITABLE DIV),但我不认为有越来越x,y坐标的任何方式使用事件,textarea上的属性或函数或Selection对象上的属性或函数。

    我已经啮合了一个例子on JSBin。请注意,我没有在其他浏览器中测试兼容性,并且它不会将插入符号返回到您离开的位置。我无法弄清楚这个代码。我相信window.getSelection()在IE中不起作用,而在IE8中则完全不同。您可能也想确保菜单不会从屏幕边缘正确显示。


    的HTML

    <div id="target" contentEditable="true">Type @ to see the dropdown.... </div> 
    <div class="dropdown"> 
        <ul id="dropdown" class="dropdown-menu hide" role="menu" aria-labelledby="dropdownMenu"> 
        <li><a>One</a> </li> 
        <li><a>Two</a></li> 
        <li><a>Three</a></li> 
        <li><a>Four</a> </li> 
    
        </ul> 
    </div> 
    

    的CSS

    #target { 
        height: 100px; 
        border: 1px solid black; 
        margin-top: 50px; 
    } 
    
    #dummy { 
        display: inline-block; 
    } 
    
    .dropdown { 
        position: absolute; 
        top: 0; 
        left: 0; 
    } 
    

    的JavaScript/JQuery的

    $("#target").keydown(function(e) { 
    
        if(e.which === 50 && e.shiftKey === true) { 
        //Prevent this event from actually typing the @ 
        e.preventDefault(); 
    
        //console.log(window.getSelection()); 
        var sel = window.getSelection(); 
    
        var offset = sel.baseOffset; 
        var node = sel.focusNode.parentNode; 
    
        //Get the text before and after the caret 
        var firsttext = node.innerHTML.substr(0,sel.baseOffset); 
        var nexttext = (sel.baseOffset != sel.focusNode.length) ? node.innerHTML.substr(sel.baseOffset, sel.focusNode.length) : ""; 
    
        //Add in @ + dummy, because @ is not in there yet on keydown 
        node.innerHTML = firsttext + '@<div id="dummy"></div>' + nexttext; 
    
        //Transfer all relevant data to the dropdown menu 
    
        $('.dropdown').css('left', $('#dummy')[0].offsetLeft).css('top', $('#dummy')[0].offsetTop).prop('x-custom-offset', offset + 1); 
    
        //Delete the dummy to keep it clean 
        //This will split the contents into two text nodes, which we don't want 
        //$('#dummy').remove(); 
        node.innerHTML = firsttext + '@' + nexttext; 
    
        //Put the caret back in place where we left off 
        //...I can't seem to figure out how to correctly set the range correctly... 
    
        $('#dropdown').removeClass('hide').addClass('show');  
        } else { 
        $('#dropdown').removeClass('show').addClass('hide'); 
        $('.dropdown').removeProp('x-custom-offset'); 
        } 
    }); 
    
    $('#dropdown').on('click', 'li a', function(e) { 
        e.preventDefault(); 
    
        $('#target').html(function(i, oldtext) { 
        var firsttext = oldtext.substr(0, $('.dropdown').prop('x-custom-offset')); 
        var nexttext = oldtext.substr($('.dropdown').prop('x-custom-offset'), oldtext.length); 
    
        console.log(e); 
    
        var inserttext = e.target.innerText; 
    
        //Cleanup 
        $('#dropdown').removeClass('show').addClass('hide'); 
    
        return firsttext + inserttext + nexttext; 
        }); 
    }); 
    

    解释

    本例将根据您可以在CONTENTEDITABLE插入元素和检索它的偏移到顶部和屏幕的左侧。当按下shift +键50时,事件处理程序将阻止@被写入,而是插入@ +虚拟对象本身。然后我们从这个对象中检索偏移量,并将下拉菜单移动到该偏移量。此外,我们将字符偏移保存为菜单的自定义属性x-custom-offset,以便我们可以在该特定位置插入值。然后,我们需要删除虚拟div,但是如果我们将删除虚拟文件,虚拟文件​​前面的文本节点和虚拟文件后面的文本节点将不会合并。这会删除最后一个文本节点,如果我们将其他@放在某个地方和/或将它放在错误的位置。因此,我们再简单地替换可编辑div的内容。最后,脱字符号必须回到原来的位置。我无法弄清楚如何正确地做到这一点。

    第二个处理程序是将文本插入到文本框中。代码应该是不言自明的。我们之前设置的x-custom-offset属性在此用于将文本插入到文本框中的正确位置。 $('#dropdown').on('click', 'li a', function(e) { ... });会将点击事件附加到ul而不是li,因此如果您动态创建li(但只有在您点击链接部分时才会触发),它将继续工作。

    相关问题