如何將我的下拉菜單放置在textarea內的光標位置?我發現這個問題已經在這裏問了很多次,但我不能夠弄清楚正確的解決方案..如何在textarea內的光標位置放置下拉菜單?
這是JSBIN
請幫我看看你的建議
在此先感謝
如何將我的下拉菜單放置在textarea內的光標位置?我發現這個問題已經在這裏問了很多次,但我不能夠弄清楚正確的解決方案..如何在textarea內的光標位置放置下拉菜單?
這是JSBIN
請幫我看看你的建議
在此先感謝
您可以獲取鼠標的位置,然後將下拉列表移至此位置。 您只需確保彈出窗口內容具有比您想要遮擋的元素更高的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>
我知道這是不是對這個問題的確切答案(此解決方案不使用一個文本,而是一個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
(但只有在您點擊鏈接部分時纔會觸發),它將繼續工作。
我想不出有什麼辦法在文本框中這樣做,因爲你不能在文本框中插入一個元素。有可能的是使用帶有contentEditable =「true」的div,並以某種方式將其格式化爲文本框。您可以使用selectionStart確定偏移量,然後用'abcd
是的,我試着用contenteditable div但是在插入另一個div在光標位置時遇到了問題。我想插入一個div時,我在光標位置鍵入'@',並沒有找到一種方法去...使用.append()不會插入光標位置的div時,我鍵入'@'中間的任何地方http://jsbin.com/uyufiw/25/edit – selvagsz
'$('#target')。selectionStart'或類似的東西可以用來查找光標的偏移量,您可以使用它來創建兩個子串。一個從開始到遊標,一個從遊標到結束。然後你可以用'firststring + yourdiv + laststring'替換$('#target')'的內容。要插入某些東西,可以用所選的選項替換'
'。 (這只是半句法,但在li元素上有'this.parent.outerHTML = this.value'之類的東西。) 同樣很抱歉,我無法真正在這臺計算機上測試,所以無法做到很多,但給出了神祕的線索。 – Sumurai8