обнаружение разрывов строк с помощью jQuery?

возможно ли, чтобы jQuery/javascript определял, где строка сломана (чтобы соответствовать ограничениям ширины CSS), чтобы вставлять элементы DOM перед началом новой строки?


person Mild Fuzz    schedule 12.01.2011    source источник
comment
Вы ищете, где слово обернуто, или вы ищете <br>?   -  person Marnix    schedule 12.01.2011
comment
какая строка на входе?   -  person amosrivera    schedule 12.01.2011
comment
Какой контент вы вставляете перед началом каждой строки?   -  person Jacob    schedule 12.01.2011
comment
@Marnix ищет обертку. @amosrivera просто предложение, это заголовок. @ Джейкоб не уверен, что ты имеешь в виду? перед динамическим содержанием есть ‹h3› и ‹span›   -  person Mild Fuzz    schedule 13.01.2011


Ответы (7)


Я придумал подход, но он может быть излишним для ваших целей, поэтому примите это во внимание.

Вам нужно создать клон элемента, очистить оригинал, а затем переместить каждое слово обратно в исходный элемент. Если высота изменяется в любой точке, перед этим словом ставится разрыв строки. Это было бы довольно просто сделать с помощью $(el).text(), но становится сложнее, если внутри могут быть другие теги, а не только текст. Я попытался объяснить, как разбить его по узлу в этом поле для ответов, но мне оказалось проще просто создать плагин jQuery в jsFiddle. Ссылка здесь: http://jsfiddle.net/nathan/qkmse/ (Gist).

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

person Nathan MacInnes    schedule 15.09.2011
comment
Работает из коробки - Грубая сила для победы! - person Trass Vasston; 06.08.2012
comment
Этот комментарий обращается к чему-то подобному, он оборачивает каждую строку текста в диапазон (с уникальным классом!). Он использует этот подключаемый модуль. - person Steve Meisner; 24.08.2012

Вот один подход. Примечание: я не вижу идеального решения без использования моноширинных шрифтов. Знак равенства с символами значительно упрощает эту задачу.

  1. Символы одинаковой ширины
  2. Рассчитать размер одного символа
  3. Рассчитать размер контейнера
  4. Найти символы в строке
  5. Найдите место разрыва строки (например, пробелы, тире и т. д.)
  6. Получить все ломаные индексы.

Взгляните на jsfiddle для связанного html. Я не выполнил эту функцию. При расчете индекса разрыва необходимо ввести дополнительные проверки. Прямо сейчас он использует lastIndexOf(' '), но игнорирует тот факт, что следующий индекс может быть пробелом или текущим. Также я не учитываю другие символы разрыва строки. Однако это должно стать отличной отправной точкой.

var text = $('#text').text(),                   // "lorem ipsum ... "
    len = text.length,                          // total chars
    width = $('#text').width(),                 // container width
    span = $('<span />').append('a').appendTo('#sandbox'),
    charWidth = span.width(),                  // add single character to span and test width
    charsPerRow = Math.floor(width/charWidth); // total characters that can fit in one row

var breakingIndexes = [], // will contain indexes of all soft-breaks
    gRowStart = 0,        // global row start index
    gRowEnd = charsPerRow;// global row end index

while(gRowEnd < len){
    var rowEnd = text.substring(gRowStart, gRowEnd).lastIndexOf(' '); // add more checks for break conditions here
    breakingIndexes.push(gRowStart + rowEnd); // add breaking index to array
    gRowStart = gRowStart + rowEnd + 1; // next start is the next char
    gRowEnd = gRowStart + charsPerRow;  // global end inxex is start + charsperrow
}

var text2 = $('#text2').text();           // "lorem ipsum ... " now not width bound
var start = 0, newText = '';
for(var i=0; i < breakingIndexes.length; i++){
    newText += text2.substring(start, breakingIndexes[i]) + '<br />'; // add hard breaks
    start = breakingIndexes[i]; // update start
}

$('#text2').html(newText); // output with breaks

http://jsfiddle.net/Y5Ftn/1/

person Josiah Ruddell    schedule 12.01.2011
comment
Проблема в том, что у многих персонажей разное пространство. Одна вещь, которую вы можете сделать, это принять 1ex за charWidth. Или, может быть (что сложнее) создать оценку charWidth. Но это зависит от языка, с помощью которого персонаж с большей вероятностью будет в вашем тексте. Или, если перенос слов не то, что вы ищете, было бы неплохо взять max-char, например W, который является огромным символом. Или, может быть, рассматривать это как функцию Gaussian с дисперсией? - person Marnix; 13.01.2011
comment
@marnix - я не вижу, чтобы какие-либо из этих расчетов были очень точными, потому что немоноширинные шрифты имеют разную ширину символов. Конечно, вы можете рассчитать ширину всех общих символов и фактически рассчитать каждую строку на основе ширины отдельных символов. Однако это кажется ужасно неэффективным. - person Josiah Ruddell; 13.01.2011
comment
Я только что протестировал это в IE 7 (корпоративный стандарт здесь :(), и он неправильно отформатирован, но отлично выглядит в Chrome 8! Просто подумал, что вам может быть интересно узнать, может быть, что-то можно сделать... - person Suirtimed; 13.01.2011
comment
Как я уже сказал, он не должен рассчитываться в каждой строке. Хотя это выполнимо за полиномиальное время, это то, чего вы не хотите. Создание оценки для языка, на котором вы работаете. Большинство естественных процессов являются гауссовыми, так что было бы неплохо начать с них, или вы могли бы сделать это дискретным E[X], потому что количество символов дискретно. 'W' кажется хорошим символом в качестве max-char, потому что почти в каждом шрифте это самый большой символ. Так что да, составить оценку приятнее, чем просто взять «а» в SPAN. - person Marnix; 13.01.2011

это мой скрипт, который берет текст, а затем делает каждую строку диапазоном

CSS:

    margin: 0;
        padding: 0;
    }

    .title{
        width: 300px;
        background-color: rgba(233,233,233,0.5);
        line-height: 20px;
    }

    span{
        color: white;
        background-color: red;
        display: inline-block;
        font-size: 30px;
    }

    a{
        text-decoration: none;
        color: black;
    }

HTML

<div class="title">
        <a href="">SOME TEXT LONG TEXT ANDTHISISLONG AND THIS OTHER TEXT</a>
    </div>

JS

$(function(){

        $(".title").find("a").each(function(){

            var $this = $(this);
            var originalText = $this.text();
            $this.empty();

            var sections = [];

            $.each( originalText.split(" "), function(){
                var $span = $("<span>" + this + "</span>");
                $this.append($span);

                var index = $span.position().top;

                if( sections[index] === undefined ){
                    sections[index] = "";
                }

                sections[index] += $span.text() + " ";
            });

            $this.empty();

            for(var i = 0; i< sections.length; i++){
                if( sections[i] !== undefined ){
                    var spanText = $.trim(sections[i]);                     
                    $this.append("<span>" + spanText + "</span>");
                }
            }

        });

    });

Вы должны включить jQuery.

person Chris Panayotoff    schedule 02.04.2013
comment
Это довольно мило, спасибо! Хотя есть несколько крайних случаев, например, браузер может сломаться в местах, отличных от пробела (табуляция, новая строка, U + 2028, может быть, дефис). - person TextGeek; 19.03.2020

Я не знаю какой-либо встроенной функции jQuery или javascript для этого. Однако вы можете сделать это самостоятельно, но это будет потенциально медленно, если у вас много текста.

Теоретически вы можете убедиться, что высота установлена ​​​​на авто, удалить текст, а затем слово за словом снова вставить его. При изменении высоты вы удаляете последнее слово и вставляете свой элемент dom. Опять же, это будет медленно, если текста много, и лучший способ сделать это — не изменять исходный элемент, а сделать это в другом элементе, который может быть скрыт, а затем заменить исходный элемент по завершении. Таким образом, ваш пользователь не увидит, как контент исчезает, а затем возвращается слово за словом.

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

Тем не менее, есть способ измерить текст с помощью холста, но это может быть экстремально. Теоретически это было бы так: создайте элемент холста, получите контекст, установите все свойства шрифта, а затем используйте метод context.measureText(). Пример его использования можно найти здесь. .

person LoveAndCoding    schedule 12.01.2011

Не знаю, каков именно ваш вариант использования, но http://code.google.com/p/hyphenator/ может быть решением вашей проблемы, или если вы покопаетесь в исходном коде hyphenator.js, вы сможете найти код, который ищете.

person Josh Schumacher    schedule 13.01.2011

Я думаю, что было бы легче обнаружить с помощью регулярного выражения - гораздо меньше кода при сохранении эффективности.

Вот что сработало для меня:

if ((/(\r\n|\n|\r)/.test($(this).val()))) {
    alert('there are line breaks here')
}

Я не уверен, что это будет работать с вашими неработающими строками, но это работает для обнаружения разрывов строк с помощью jQuery.

person streetlight    schedule 11.02.2013
comment
этот код выбирает разрывы, вызванные обычным переносом текста в DOM? - person Mild Fuzz; 12.02.2013
comment
Я провел только предварительное тестирование, но думаю, что да. Я знаю, что это определенно работает в текстовых областях, где я использовал его в прошлом. - person streetlight; 13.02.2013
comment
он работает в текстовых областях, потому что редактирование элемента изменяет DOM. это не относится к другим элементам. - person Michael; 26.03.2015

В качестве альтернативы вы можете сравнить ширину текстового блока с шириной его родителя. Если блок составляет не менее 98% ширины своего родителя, он почти наверняка сломается.

person Harijs Deksnis    schedule 23.05.2013