2013-06-25 20 views
5

Làm cách nào tôi có thể định vị thả xuống ở vị trí con trỏ bên trong vùng văn bản? Tôi đã tìm thấy câu hỏi này đã được hỏi ở đây nhiều lần nhưng tôi không thể hình có thể ra các giải pháp đúng ..Làm thế nào tôi có thể định vị một menu thả xuống ở vị trí con trỏ bên trong một vùng văn bản?

đây là JSBIN

hãy giúp tôi với đề xuất của bạn

Cảm ơn trước

+0

Tôi không thể nghĩ ra bất kỳ cách nào để thực hiện điều đó trong hộp văn bản, bởi vì bạn không thể chèn phần tử vào hộp văn bản. Điều gì có thể là có thể sử dụng một div với 'contentEditable =" true "' và bằng cách nào đó định dạng nó thành một hộp văn bản. Bạn có thể xác định offset với selectionStart, sau đó thay thế 'abcd [cursor] efgh' bằng' abcd

yourdiv
efgh'. Vì nó không thực sự là một câu trả lời cho câu hỏi của bạn, tôi sẽ để nó như một bình luận. – Sumurai8

+0

vâng tôi đã thử với div có thể chỉnh sửa nội dung nhưng đã bị tấn công khi chèn một div khác vào vị trí con trỏ. Tôi đang cố gắng để chèn một div khi tôi gõ '@' tại vị trí con trỏ và không tìm thấy một cách để đi ... Sử dụng .append() sẽ không chèn div tại vị trí con trỏ khi tôi gõ '@' bất cứ nơi nào ở giữa http://jsbin.com/uyufiw/25/edit – selvagsz

+0

'$ ('# target'). selectionStart' hoặc một cái gì đó tương tự có thể được sử dụng để tìm bù đắp của con trỏ, mà bạn có thể sử dụng để tạo hai chất nền. Một từ đầu đến con trỏ và một từ con trỏ đến cuối. Sau đó bạn có thể thay thế nội dung của '$ ('# target')' bằng 'firststring + yourdiv + laststring'. Để chèn nội dung nào đó, bạn có thể thay thế '

    'bằng tùy chọn được chọn. (Đây chỉ là cú pháp bán, nhưng cái gì đó giống như 'this.parent.outerHTML = this.value' trên một phần tử li.) Cũng xin lỗi, nhưng tôi thực sự không thể thử nghiệm trên máy tính này, vì vậy không thể làm nhiều nhưng đưa ra manh mối khó hiểu. – Sumurai8

    Trả lời

    0

    Bạn có thể lấy vị trí của con chuột và sau đó di chuyển danh sách thả xuống đến vị trí này. Bạn chỉ cần đảm bảo nội dung bật lên có chỉ mục z cao hơn phần tử bạn muốn nó xuất hiện và vị trí của nó được đặt thành tuyệt đối.

    Đây là mẫu thử nhỏ tôi đã viết một lần.

    <!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

    Làm thế nào tôi đọc nó, OP hỏi làm thế nào để hiển thị một cái gì đó trên vị trí của con trỏ (điều đó hiển thị nơi trong một hộp văn bản bạn đang gõ) - hay nói cách khác - làm thế nào để có được tọa độ của con trỏ, * không * trong đó chuột là khi người dùng nhấn phím và * không * cách hiển thị nội dung nào đó trên các tọa độ đó. e.pageX không tồn tại cho sự kiện keyDown. – Sumurai8

    +0

    Thật vậy. Tôi vừa đọc lại nó. Nó có vẻ rất rõ ràng bây giờ. Đó là một câu hỏi khá khác với câu hỏi mà tôi đã trả lời sai. Cảm ơn bạn. :) – enhzflep

    3

    Tôi biết nó không phải là một câu trả lời chính xác về vấn đề (giải pháp này không sử dụng một textarea, nhưng một div contentEditable), nhưng tôi không nghĩ rằng có bất kỳ cách nào nhận được xy-tọa độ sử dụng sự kiện, thuộc tính hoặc hàm trên vùng văn bản hoặc thuộc tính hoặc hàm trên đối tượng Selection.

    Tôi đã kết hợp một ví dụ on JSBin. Xin lưu ý rằng tôi đã không làm phiền kiểm tra tính tương thích trong các trình duyệt khác và rằng nó sẽ không trả lại dấu nháy cho đến nơi bạn đã dừng lại. Tôi không thể tìm ra mã cho điều đó. Tôi tin rằng window.getSelection() sẽ không hoạt động trong IE và trong IE8, nó sẽ hoàn toàn khác. Bạn có thể muốn đảm bảo quá, rằng menu sẽ không được hiển thị ngay từ cạnh của màn hình.


    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; 
    } 
    

    Các 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; 
        }); 
    }); 
    

    Lời giải thích

    Ví dụ này hoạt động dựa trên mà bạn có thể chèn một phần tử trong một contentEditable và lấy nó bù đắp cho phía trên và bên trái của màn hình. Khi nhấn phím shift + phím 50, trình xử lý sự kiện sẽ ngăn không cho @ được viết và thay vào đó chèn chính đối tượng @ + giả. Sau đó, chúng tôi lấy bù đắp từ đối tượng này và di chuyển menu thả xuống để bù đắp đó. Hơn nữa, chúng tôi lưu ký tự bù đắp như một thuộc tính tùy chỉnh x-custom-offset của trình đơn, để chúng tôi có thể chèn một giá trị tại vị trí cụ thể đó. Sau đó chúng ta cần phải loại bỏ div giả, nhưng nếu chúng ta loại bỏ giả với $('#dummy').remove() nút văn bản trước giả và nút văn bản phía sau giả sẽ không hợp nhất. Thao tác này sẽ xóa văn bản cuối cùng nếu chúng tôi đặt một @ khác ở đâu đó và/hoặc đặt nó ở vị trí sai. Do đó, chúng tôi chỉ cần thay thế lại nội dung của div có thể chỉnh sửa. Cuối cùng, dấu mũ phải được đặt trở lại vị trí ban đầu của nó. Tôi không thể tìm ra cách để làm điều này đúng mặc dù.

    Trình xử lý thứ hai là chèn văn bản vào hộp văn bản.Mã phải tự giải thích. Thuộc tính x-custom-offset mà chúng tôi đã thiết lập trước đó được sử dụng ở đây để chèn văn bản vào đúng vị trí trong hộp văn bản. $('#dropdown').on('click', 'li a', function(e) { ... }); sẽ đính kèm sự kiện nhấp vào ul thay vì li 's, để nó sẽ tiếp tục hoạt động nếu bạn tự động tạo li' s (nhưng nó sẽ chỉ kích hoạt nếu bạn bấm vào phần liên kết).

    Các vấn đề liên quan