2011-12-10 29 views
12

我想在iframecontentEditable之間定位浮動div元素,以防用戶輸入某個組合鍵(用於自動完成目的) 。如何從iframe中的當前插入符號位置獲得像素偏移量with contentEditable

我知道如何讓光標處: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorOffset

我可以用這個來計算的div left屬性,但我似乎無法弄清楚如何獲得top

我想到了用另一種可能性: document.getElementById('elm1_ifr').contentWindow.getSelection().anchorNode.parentNode

而且使用jQuery得到抵消,但如果父母有很長的文本行,我只能就能夠提取第一線的頂部位置。

任何人都可以幫助我嗎?

回答

12

這樣做的唯一可靠方法是在插入符處插入一個臨時元素(確保它爲零寬度),獲取其位置並再次移除它。您還應該將文本節點的兩端(如果它是包含脫字符的文本節點)粘合在一起,以確保DOM與插入節點之前的狀態相同。但是,請注意,這樣做(或對可編輯內容進行的任何其他手動DOM操作)會中斷瀏覽器的內部撤銷堆棧。

原因是仔細閱讀the spec for the getBoundingClientRect() method of Range表明getBoundingClientRect()沒有義務返回摺疊範圍的Rect。從概念上講,文檔中並不是每個位置都有一個明確的邊界矩形。然而,插入符號的確在屏幕上有物理位置,我認爲這應該由Selection API提供,但目前瀏覽器中沒有提供這個位置的東西。

+2

無法在設定的範圍是從0到當前插入符的位置,然後使用'getBoundingClientRect()'讓左+寬度與頂部+高度偏移,然後恢復插入符號,以它的前面設置? – Mottie

+3

舊的線程是的,但值得nting插入一個元素[使用'execCommand('insertHTML')']並刪除它混淆撤銷/重做堆棧。如果撤銷/重做不重要,則無關緊要。 – techfoobar

+0

@techfoobar:好的,謝謝。我在答案中添加了一個註釋。 –

7

我今天進入這個問題。經過一些測試,我得到了這個工作,沒有使用temorary元素。

在IE中,使用TextRange對象的offsetLeft和offsetTop屬性很容易。儘管webkit需要一些努力。

這裏是測試,你可以看到結果。 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

好的回答朋友! –

+0

這個問題,正如我在我的回答中提到的那樣,Firefox和其他瀏覽器中的'range.getBoundingClientRect()'有時會返回包含全部爲零的Rect以顯示合攏範圍。例如,請參閱http://jsfiddle.net/CK3e8/。 –

+0

沒錯,蒂姆。我嘗試將選擇的一個字符移回,並從那裏計算插入位置。 – osamu

相關問題