2013-06-25 102 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(但只有在您點擊鏈接部分時纔會觸發),它將繼續工作。

    相關問題