2016-08-16 6 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> 

В Chrome например, проверить страницу. Затем в представлении «Элементы» выберите один из тегов <p>. Визуализированный вид покажет подсвеченный фон, проходящий через область изображения:

show para image overlap

Это потому, что изображение плавающее вправо действительно потреаяся часть максимально возможное кадрирования абзаца. Если вы хотите рассмотреть только текст абзаца, это кажется неправильным, но это то, как работает модель макета CSS. В зависимости от ваших размеров шрифта и т. Д. Вы можете выбрать третий пара, поскольку он течет под изображением, и он действительно перетекает в тот же самый правый край.

С учетом float: right изображения контейнера браузер «думает» об изображении и его контейнере <div> s «живет» справа от первого пара, но до второго. Это его логическая «точка привязки» или «опорная точка». Выберите первый параграф, и браузер знает, что изображение не включено. Выберите вторую и аналогичную. Однако выберите комбинацию, и изображение будет правильно включено, потому что точка привязки живет между двумя абзацами. Попросите ограничительную рамку одного из абзацев, и браузер отвечает плотной коробкой. Но попросите tb-границы выбора, который охватывает эти парамы, и он должен содержать опорную точку и содержащее изображение, которое представляет собой опорная точка. Правильный ответ - намного больший ограничивающий прямоугольник, включая изображение.

Хорошо, так много для теории макета, объясняющей , почему так бывает. Теперь как, чтобы заставить его делать то, что вы хотите, и исключить содержащееся изображение из рамки выбора?

Учитывая, что CSS и браузер не интерпретируют выбор так, как вы хотите, вы не сможете напрямую использовать getBoundingClientRect(). Тем не менее, вы можете перейти от выбора к включенным узлам и отфильтровать любые теги, которые вы не хотите. В этом случае вам, похоже, нужны только теги <p>, которые достаточно легки для фильтрации. Вычислите ограничительную рамку каждого абзаца в вашем выборе, а затем верните поле, которое является их объединением.

Остерегайтесь того, что работа с диапазонами несколько сложна, особенно когда у браузеров исторически были разные модели управления ими. Кросс-браузерная библиотека, например, rangy, может помочь, хотя простое переключение с диапазона на базовые узлы, вероятно, не требует такой дополнительной дополнительной инфраструктуры. Существует множество статей о переполнении стека о «переходе от выбора JavaScript к базовым узлам» со многими примерами кода. Они не все просто ... но просто фильтрация для парасов - довольно простой случай. Или, если вы не хотите погружаться во все проблемы с диапазоном, вы можете использовать что-то вроде Selection.containsNode() менее элегантно, но все же быстро перебирать возможные узлы и посмотреть, находятся ли они в выборе.

Также будьте осторожны: ваш примерный документ упрощает процесс, просто требуя фильтрации для парасов, и имея только один плавающий элемент для исключения. Но изменчивость во всех документах HTML/CSS составляет огромный. Эта изменчивость может сделать решения хрупкими. Например. если иногда вам нужно отфильтровать больше, чем просто <p> элементов или нужно фильтровать в середине текстовых узлов, не связанных с плотно обернутым тегом, все быстро становится более рискованным. Варианты и различные краевые случаи усложнят вашу переинтерпретацию того, что ограничивающий блок выбора должен заключить (и должен игнорировать).