Текстовое разбиение на страницы внутри DIV с изображением

Я хочу разбивать текст на несколько div, чтобы он соответствовал разрешенной области
Логика довольно проста:
1. Разделить текст на слова
2. добавить слово в слово и вычислить высоту элемента
3. если мы превысим высоту - создаем следующую страницу

Это работает неплохо
enter image description here

вот функция JS, которую я использовал:

function paginate() {
    var newPage = $('<pre class="text-page" />');
    contentBox.empty().append(newPage);
    var betterPageText='';
    var pageNum = 0;
    var isNewPage = false;

    var lineHeight = parseInt(contentBox.css('line-height'), 10);

    var wantedHeight = contentBox.height() - lineHeight;

    for (var i = 0; i < words.length; i++) {        
        if (isNewPage) {
            isNewPage = false;
        } else {            
            betterPageText = betterPageText + ' ' + words[i];
        }
        newPage.text(betterPageText + ' ...');
        if (newPage.height() >= wantedHeight) {
            pageNum++;
            if (pageNum > 0) {
                betterPageText = betterPageText + ' ...';
            }

            newPage.text(betterPageText);
            newPage.clone().insertBefore(newPage)            

            betterPageText = '...';
            isNewPage = true;
        } else {            
            newPage.text(betterPageText);
        }        
    }

    contentBox.craftyslide({ height: wantedHeight });
}

Но когда я добавляю изображение, он разбивает все. В этом случае текст переполняет "зеленую" область.

enter image description here

Рабочий скрипт: http://jsfiddle.net/74W4N/7/

Есть ли лучший способ разбивать текст на страницы и вычислять высоту элемента?

Ответ 1

Решается с помощью метода jQuery.clone() и выполняет все вычисления по скрытой копии исходного HTML-элемента

function paginate() {

     var section = $('.section');

     var cloneSection = section.clone().insertAfter(section).css({ position: 'absolute', left: -9999, width: section.width(), zIndex: -999 });

     cloneSection.css({ width: section.width() });

     var descBox = cloneSection.find('.holder-description').css({ height: 'auto' });

     var newPage = $('<pre class="text-page" />');
     contentBox.empty();
     descBox.empty();
     var betterPageText = '';
     var pageNum = 0;
     var isNewPage = false;

     var lineHeight = parseInt(contentBox.css('line-height'), 10);

     var wantedHeight = contentBox.height() - lineHeight;
     var oldText = '';

     for (var i = 0; i < words.length; i++) {
        if (isNewPage) {
           isNewPage = false;
           descBox.empty();
        }
        betterPageText = betterPageText + ' ' + words[i];

        oldText = betterPageText;

        descBox.text(betterPageText + ' ...');
        if (descBox.height() >= wantedHeight) {

           if (i != words.length - 1) {
              pageNum++;

              if (pageNum > 0) {
                 betterPageText = betterPageText + ' ...';
              }

              oldText += ' ... ';
           }

           newPage.text(oldText);
           newPage.clone().appendTo(contentBox);

           betterPageText = '... ';
           isNewPage = true;
        } else {
           descBox.text(betterPageText);
           if (i == words.length - 1) {
              newPage.text(betterPageText).appendTo(contentBox);
           }
        }
     }

     if (pageNum > 0) {
        contentBox.craftyslide({ height: wantedHeight });
     }

     cloneSection.remove();
}

live demo: http://jsfiddle.net/74W4N/19/

Ответ 2

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

Затем, добавив изображение (почти невозможно, если изображение больше или больше как максимальная ширина или высота), если оно меньше, оно также имеет поля /paddings. и он может начинаться в конце строки и таким образом разбить все снова. Обычно только на первой странице вы можете добавить изображение, просто вычислив его ширину + маржу и высоту + margin/lineheight. но для получения желаемого результата требуется много математики.

Сказал, что некоторое время назад я попытался написать аналогичный script, но остановил причину многих проблем и разных результатов браузера.

Теперь, читая ваш вопрос, я наткнулся на то, что я прочитал некоторое время назад:

-webkit-column-count 

поэтому я сделал другой подход к вашей функции, который не учитывает все эти вычисления.

не судите код, как я его написал сейчас (я тестировал на хроме, другим браузерам нужны разные префиксы.)

var div=document.getElementsByTagName('div')[0].firstChild,
maxWidth=300,
maxHeigth=200,
div.style.width=maxWidth+'px';
currentHeight=div.offsetHeight;
columns=Math.ceil(currentHeight/maxHeigth);
div.style['-webkit-column-count']=columns;
div.style.width=(maxWidth*columns)+'px';
div.style['-webkit-transition']='all 700ms ease';
div.style['-webkit-column-gap']='0px';
//if you change the column-gap you need to
//add padding before calculating the normal div.
//also the line height should be an integer that
// is divisible of the max height 

здесь Пример

http://jsfiddle.net/HNF3d/10/

добавление изображения, которое меньше максимальной высоты и ширины на первой странице, не испортило бы все.

и похоже, что он поддерживается всеми современными браузерами (с правильными префиксами)

Ответ 3

По моему опыту, попытка вычислить и переместить текст в HTML - это почти бесполезное упражнение. Слишком много различий между браузерами, операционными системами и проблемами с шрифтами.

Мое предложение состояло в том, чтобы использовать свойство CSS overflow. Это, в сочетании с использованием размера em для высот, должно позволить вам определить блок div, который отображает только определенное количество строк (независимо от размера и типа шрифта). Объедините это с небольшим количеством javascript, чтобы прокрутить содержащий элемент div, и у вас есть разбиение на страницы.

Я взломал быстрое доказательство концепции в JSFiddle, которое вы можете увидеть здесь: http://jsfiddle.net/8CMzY/1/

Отсутствует предыдущая кнопка и способ отображения количества страниц, но это должны быть очень простые дополнения.

EDIT: я изначально был связан с неправильной версией концепции JSFiddle

Ответ 4

На самом деле я пришел к более простому решению, основанному на том, что сделал @cocco, что также работает в IE9. Для меня было важно сохранить обратную совместимость, а анимацию и т.д. Было неактуально, поэтому я их убрал. Вы можете увидеть это здесь: http://jsfiddle.net/HNF3d/63/

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

var parentDiv = div = document.getElementsByTagName('div')[0];
var div = parentDiv.firstChild,
    maxWidth = 300,
    maxHeigth = 200,

    t = function (e) {
        div.style.webkitTransform = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
        div.style["-ms-transform"] = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
    };

div.style.width = maxWidth + 'px';
currentHeight = div.offsetHeight;
columns = Math.ceil(currentHeight / maxHeigth);

links = [];
while (columns--) {
    links[columns] = '<span>' + (columns + 1) + '</span>';
}
var l = document.createElement('div');
l.innerHTML = links.join('');
l.onclick = t;
document.body.appendChild(l)