2016-08-16 54 views
1

我需要獲取文本選擇的邊界矩形。我使用此代碼:爲什麼選擇範圍的邊界矩形比實際的文本選擇寬?

if (window.getSelection && window.getSelection().rangeCount) { 
     var range = window.getSelection().getRangeAt(0).cloneRange() 
     if (range.getBoundingClientRect && range.getBoundingClientRect()!=null) 
     return range.getBoundingClientRect() 
    } 

但它往往會返回一個矩形,比文本選擇更廣泛,即使所選文本的每一個元素不延長該寬。

例如,當我選擇第一個段落https://simple.wikipedia.org/wiki/Gluon的第一段文字時,該矩形包含右側的圖片。

似乎每次段落邊界位於文本選區內部時都會出現此問題,並且這會使矩形擴展到段落寬度。

如何解決這個問題?

回答

0

包含在多段選擇中的圖像可能是您想要完成的或您想要解釋文檔結構的方式的問題 - 但從視圖的角度來看並不是「錯誤的」 HTML/CSS佈局模型或瀏覽器的佈局引擎。

簡化文檔結構:

<div id="nw-content-text"> 
    <div style="float: right"> 
     <img src="gluons.png"> 
    </div> 
    <p>From Wikipedia...</p> 
    <p>Gluons are what hold quarks together...</p> 
    ... 
</div> 

在鉻例如,檢查頁面。然後在元素視圖中選擇<p>標記中的任意一個。渲染視圖將顯示高亮背景橫跨圖像區域延伸:

show para image overlap

這是因爲像浮在右邊的確是消費款的最大可能邊框的一部分。如果您只想考慮段落文本,那就感覺不對,但這是CSS佈局模型的工作原理。根據您的字體大小等,您可以選擇第三段,因爲它在圖像下方流動,並且它確實流向相同的最右邊緣。

鑑於圖像容器的float: right,瀏覽器會「認爲」圖像及其容器<div>在第一段的右側,但在第二段之前「生活」。這是它的邏輯「附加點」或「錨點」。選擇第一段,並且瀏覽器知道圖像不包括在內。選擇第二個,同樣。不過,請選擇組合,並且圖像正確包含,因爲錨點位於兩個段落之間。詢問單獨的para和邊界框,瀏覽器用一個緊密的方框進行響應。但是要求跨越這些段落的選擇的範圍,並且它必須包括定位點和包含的定位點所代表的圖像。包含圖像的更大的邊界框是正確的答案。

好的,這麼多的佈局理論解釋爲什麼這種情況發生,因爲它的確如此。現在如何讓它做你想做的事情,並從選擇邊界框中排除包含的圖像?

鑑於CSS和瀏覽器不以您想要的方式解釋選擇,您將無法直接在選擇上使用getBoundingClientRect()。但是,您可以從選擇導航到包含的節點,並篩選出您不需要的任何標籤。在這種情況下,您似乎只想要<p>標籤,這些標籤很容易過濾。計算您選擇的每個段的邊界框,然後返回一個與它們結合的框。

要小心使用範圍有點棘手,特別是瀏覽器歷史上有不同的模型來管理它們。像rangy這樣的跨瀏覽器的庫可能會有所幫助,但只需從一個範圍導航到底層節點可能不需要太多額外的框架。關於「從JavaScript選擇到底層節點」的Stack Overflow有很多文章和很多代碼示例。它們並不都是簡單的...但是僅僅爲了para而過濾是一個相當簡單的例子。或者,如果您不想深入瞭解所有範圍問題,則可以使用類似Selection.containsNode()這樣的優雅方式,但仍然可以快速遍歷可能的節點並查看它們是否處於選擇狀態。

另外要注意:您的示例文檔通過僅需要過濾para,並且僅排除一個浮動項目而使事情變得簡單。但是,所有HTML/CSS文檔的變化都是巨大的。這種可變性可能會使解決方案變得脆弱。例如。如果有時候您需要過濾不僅僅是<p>元素,或者需要過濾到與緊密包裝的標籤無關的文本節點的中間,那麼事情會很快變得更加危險。變化和不同的邊緣情況會使你重新解釋選擇的邊界框應該包含的內容(應該忽略)。