2011-12-10 40 views
12

Tôi muốn định vị phần tử div nổi trong iframe với contentEditable, trong trường hợp người dùng nhập một tổ hợp phím nào đó (cho mục đích tự động hoàn thành) .Cách lấy điểm ảnh bù từ vị trí dấu nháy hiện tại trong iframe có contentEditable

Tôi biết làm thế nào để có được vị trí dấu nháy: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorOffset

Tôi có thể sử dụng để tính toán left tài sản của div, nhưng tôi dường như không thể tìm ra cách để có được những top.

Một khả năng tôi nghĩ về đã sử dụng: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorNode.parentNode

Và sử dụng jQuery để có được bù đắp, nhưng nếu cha mẹ có một dòng văn bản dài, tôi sẽ chỉ có thể trích xuất các vị trí hàng đầu của dòng đầu tiên .

Có ai có thể giúp tôi với điều này không?

Trả lời

12

Cách đáng tin cậy duy nhất để thực hiện việc này là chèn phần tử tạm thời vào dấu mũ (đảm bảo rằng nó có chiều rộng bằng 0), lấy vị trí của nó và loại bỏ nó một lần nữa. Bạn cũng nên dán hai đầu của nút văn bản (nếu đó là một nút văn bản chứa dấu mũ) lại với nhau để đảm bảo DOM giống như trước khi chèn nút. Tuy nhiên, lưu ý rằng việc thực hiện điều này (hoặc bất kỳ thao tác DOM thủ công nào khác trên nội dung có thể chỉnh sửa) sẽ phá vỡ ngăn xếp hoàn tác nội bộ của trình duyệt.

Lý do cho điều này là việc đọc cẩn thận the spec for the getBoundingClientRect() method of Range cho thấy rằng getBoundingClientRect() không có nghĩa vụ trả lại Rect cho một phạm vi thu gọn. Về mặt khái niệm, không phải mọi vị trí trong tài liệu đều có hình chữ nhật giới hạn được xác định rõ ràng. Tuy nhiên, dấu nháy có vị trí vật lý trên màn hình mà theo ý kiến ​​của tôi nên được API lựa chọn cung cấp, nhưng hiện tại không có gì trong trình duyệt để cung cấp điều này.

+2

Không thể bạn thiết lập phạm vi là từ 0 đến vị trí dấu nháy hiện tại, sau đó sử dụng 'getBoundingClientRect()' để có được trái + chiều rộng & Đầu Trang + chiều cao bù đắp, sau đó khôi phục lại caret để nó trước cài đặt? – Mottie

+3

Chủ đề cũ có, nhưng đáng nting rằng chèn một phần tử [sử dụng 'execCommand ('insertHTML')'] và loại bỏ nó messes up undo/redo stack. Không quan trọng nếu undo/redo là không đáng kể. – techfoobar

+0

@techfoobar: Tốt, cảm ơn. Tôi đã thêm một ghi chú vào câu trả lời. –

7

Tôi đã gặp phải vấn đề này ngay hôm nay. Sau khi thử nghiệm một số, tôi đã làm việc này, mà không sử dụng yếu tố temorary.

Trong IE, thật dễ dàng để làm việc với tài sản offsetLeft và offsetTop của đối tượng TextRange. Một số nỗ lực là cần thiết cho webkit mặc dù.

Đây là một thử nghiệm, bạn có thể xem kết quả. http://jsfiddle.net/gliheng/vbucs/12/

var getCaretPixelPos = function ($node, offsetx, offsety){ 
    offsetx = offsetx || 0; 
    offsety = offsety || 0; 

    var nodeLeft = 0, 
     nodeTop = 0; 
    if ($node){ 
     nodeLeft = $node.offsetLeft; 
     nodeTop = $node.offsetTop; 
    } 

    var pos = {left: 0, top: 0}; 

    if (document.selection){ 
     var range = document.selection.createRange(); 
     pos.left = range.offsetLeft + offsetx - nodeLeft + 'px'; 
     pos.top = range.offsetTop + offsety - nodeTop + 'px'; 
    }else if (window.getSelection){ 
     var sel = window.getSelection(); 
     var range = sel.getRangeAt(0).cloneRange(); 
     try{ 
      range.setStart(range.startContainer, range.startOffset-1); 
     }catch(e){} 
     var rect = range.getBoundingClientRect(); 
     if (range.endOffset == 0 || range.toString() === ''){ 
      // first char of line 
      if (range.startContainer == $node){ 
       // empty div 
       if (range.endOffset == 0){ 
        pos.top = '0px'; 
        pos.left = '0px'; 
       }else{ 
        // firefox need this 
        var range2 = range.cloneRange(); 
        range2.setStart(range2.startContainer, 0); 
        var rect2 = range2.getBoundingClientRect(); 
        pos.left = rect2.left + offsetx - nodeLeft + 'px'; 
        pos.top = rect2.top + rect2.height + offsety - nodeTop + 'px'; 
       } 
      }else{ 
       pos.top = range.startContainer.offsetTop+'px'; 
       pos.left = range.startContainer.offsetLeft+'px'; 
      } 
     }else{ 
      pos.left = rect.left + rect.width + offsetx - nodeLeft + 'px'; 
      pos.top = rect.top + offsety - nodeTop + 'px'; 
     } 
    } 
    return pos; 
}; 
+0

Người bạn trả lời hay! –

+0

Vấn đề với điều này, như tôi đã nói đến trong câu trả lời của tôi, là 'range.getBoundingClientRect()' trong Firefox và các trình duyệt khác đôi khi trả về một Rect chứa tất cả các số 0 cho một phạm vi thu gọn. Xem http://jsfiddle.net/CK3e8/ cho một ví dụ. –

+0

Đó là sự thật, tim. Tôi đã cố gắng di chuyển lựa chọn một nhân vật trở lại, và làm việc ra vị trí caret từ đó. – osamu

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