Как выделить строку текста, которая ближе всего к мышке? - PullRequest
6 голосов
/ 16 марта 2010

У меня длинный текст, и я хотел бы предложить пользователю помощь в чтении: текущая строка должна быть выделена. Чтобы сделать это проще, я просто буду использовать координату Y мыши (таким образом, указатель мыши не будет мешать). У меня есть большой DIV с идентификатором content, который заполняет всю ширину, и небольшой DIV с классом content для текста ( см. Здесь пример ).

Я использую jQuery 1.4. Как выделить строку текста, ближайшую к текущей позиции мыши?

Ответы [ 3 ]

17 голосов
/ 16 марта 2010

Не уверен, что jQuery сильно вам здесь поможет, но вы можете взглянуть на метод element.getClientRects, описанный в MSDN и MDC . В частности, этот пример в MSDN в некотором роде похож на то, чего вы хотите достичь, выделяя строки, используя хитро z-indexed элемент div, который идет за текстом в координатах, возвращаемых getClientRects().

Вы должны быть в состоянии достичь того же самого, перебирая объекты TextRectangle, возвращенные в onmousemove документа, и проверяя, находится ли значение y курсора мыши> сверху и <низ каждого прямоугольника, и перемещая умный z-индексированный div для той же позиции / высоты. </p>

Все текущие основные браузеры поддерживают getClientRects().

<Ч />

http://jsbin.com/avuku/15

ОБНОВЛЕНО - работает в Chrome, IE6 / 7/8, Firefox, Opera, Safari. Первоначальные проблемы, с которыми я столкнулся в других браузерах, были связаны с DIV, который должен быть display: inline.
ОБНОВЛЕНО СНОВА - Мне пришлось обратиться к этому ответу для получения более новых вопросов, поэтому я нашел время, чтобы обновить его, чтобы пересчитать строки при изменении размера окна. Похоже, что другие тоже играли вокруг, теперь он на ревизии 15.

5 голосов
/ 16 марта 2010

Я не понимаю, как вы могли бы реально сделать это без явно обернутого текста (то есть, новых строк или <br> элементов).

Насколько я знаю, у DOM нет способа узнать, где конкретный фрагмент текста обернут, по символам или по пикселям - включая то, что я знаю о API диапазона - не говоря уже о динамическом характере текста, который можно предположить, например, при использовании функции масштабирования текста в браузерах.

Но если вам удастся как-то сгенерировать / внедрить явные окончания строк, то, я думаю, у меня есть решение для вас.

EDIT

Благодаря потрясающей информации в ответе Пекки, я собрал функциональный прототип, но у него есть существенное предостережение - он работает только с простым текстовым контентом. Любой HTML, представленный в теле элемента, будет удален.

<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript"> google.load("jquery", "1.4.1"); </script>
<script type="text/javascript">

  jQuery.fn.wrapLines = function( openTag, closeTag )
  {
    var dummy = this.clone().css({
            top: -9999,
            left: -9999,
            position: 'absolute',
            width: this.width()
        }).appendTo(this.parent())
      , text = dummy.text().match(/\S+\s+/g);

    var words = text.length
      , lastTopOffset = 0
      , lines = []
      , lineText = ''
    ;

    for ( var i = 0; i < words; ++i )
    {
      dummy.html(
          text.slice(0,i).join('') +
          text[i].replace(/(\S)/, '$1<span/>') +
          text.slice(i+1).join('')
      );

      var topOffset = jQuery( 'span', dummy ).offset().top;

      if ( topOffset !== lastTopOffset && i != 0 )
      {
        lines.push( lineText );
        lineText = text[i];
      } else {
        lineText += text[i];
      }

      lastTopOffset = topOffset;
    }
    lines.push( lineText );

    this.html( openTag + lines.join( closeTag + openTag ) + closeTag );
  };

  $(function()
  {
    $('p').wrapLines( '<span class="line">', '</span>' );
  });

</script>

<style type="text/css">
span.line:hover {
  background-color: lightblue;
}
</style>

<p style="width: 400px;">
 one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty-one twenty-two twenty-three
</p>
3 голосов
/ 16 марта 2010

Наилучший подход, который приходит на ум, - это разделение каждой строки на элемент <span> или <div>, который имеет класс CSS :hover с установленным параметром "highlight":

span.line:hover { background-color: lightblue; }

Это было бы наименее дорогостоящим решением, так как браузер позаботится обо всей подсветке. Если вам нужны причудливые эффекты, вы все равно можете добиться этого, добавляя к каждой строке события mouseover и mouseout.

Самым сложным, конечно, является разбиение контента на строки в конце строки браузера. Вы должны сделать это динамически, чтобы линии фактически отражали позиции, в которых браузер разбивает текст.

Может быть, принятый ответ на этот вопрос - шаг в правильном направлении:

Получение конкретной строки с использованием jQuery

Как это работает:

Он проходит через весь элемент (фактически, клон элемента), вставляя элемент в каждое слово. Верхнее смещение диапазона кэшируется - когда это смещение изменяется, мы можем предположить, что находимся на новой строке.

...