Я хочу создать отзывчивый, оптимизированный для мобильных устройств опыт чтения, подобный читалке epub / ebook, такой как приложение Kindle или iBooks, с использованием динамического HTML в качестве источника.
Представьте себе длинную статью или сообщение в блоге, для чтения которой требуется много вертикальной прокрутки, особенно на небольшом мобильном устройстве. Что я хотел бы сделать, так это разбить длинную страницу на несколько полноэкранных разделов, чтобы пользователь мог использовать стрелки навигации влево / вправо и / или жест смахивания для перехода к «странице» через статью.
Доступно множество JS-библиотек, которые могут создавать «слайд-шоу» или «карусель» предварительно определенных слайдов (с использованием div или других элементов контейнера). Но я хочу, чтобы текст и содержимое html динамически перетекали в соответствии с областью просмотра любого устройства и при этом оставались читабельными ... точно так же, как пользовательский интерфейс epub / ebook, например приложение Kindle или iBooks. Таким образом, для той же статьи на телефоне будет намного больше «страниц», чем на планшете или рабочем столе, и эти «страницы» нужно будет динамически создавать / корректировать, если / когда размер области просмотра изменится ( как переключение с книжной на альбомную на мобильном устройстве).
Вот пример программы для чтения файлов .epub на javascript: epub.js
... обратите внимание на отзывчивое поведение. Когда вы изменяете размер области просмотра, весь текст перетекает, чтобы соответствовать доступному пространству, увеличивая или уменьшая общее количество «страниц». Проблема в том, что epub.js требует в качестве источника файла .epub.
Я хочу тот же пользовательский интерфейс и функциональность для html-страницы.
Я искал и искал какую-то библиотеку, которая может сделать это из коробки, но не смог ничего найти.
Я понимаю, что могу использовать сценарий преобразования для преобразования моей html-страницы в файл .epub, а затем использовать epub.js для рендеринга этого файла в браузере, но это кажется очень беспорядочным и неуклюжим. Было бы намного лучше имитировать или имитировать взаимодействие с пользователем .epub reader с html в качестве прямого источника, отображая / имитируя отзывчивый пользовательский интерфейс электронной книги на стороне клиента.
Кто-нибудь знает, существует ли что-то подобное уже, или как я мог бы сделать это сам?
Важнейшей функцией является динамическое / отзывчивое переформатирование текста. Когда размеры области просмотра уменьшаются, текст / контент необходимо переформатировать на следующую «страницу», чтобы избежать необходимости в вертикальной прокрутке. Я не знаю, как это сделать эффективно. Если бы я сам написал код, я мог бы использовать что-то вроде плагина jQuery Columnize, установив для всех столбцов значение width: 100vw; height: 100vh, чтобы каждый столбец был похож на «страницу», а затем выяснил, как создать интерфейс пролистывания между этими «страницами». .
Любая помощь высоко ценится!
Это действительно широкий вопрос, он недостаточно конкретный или технический, чтобы его можно было разместить здесь. Таким образом, он не заслуживает ответа и, возможно, должен исчезнуть? В любом случае вам нужно искать скрипты / библиотеки с «адаптивной пагинацией». С 2012 года, вот ответ, я бы начал именно с этого. Используйте JS для анализа «длинного» HTML-контента и его динамического разделения в соответствии с размером области просмотра. Оттуда выясните элементы управления для анимации страниц (пролистывание, стрелки и т. д.). Если вы также имели в виду динамическую связь с сервером, это еще одна баня червей.
@ user2655393 вы нашли решение?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Взгляните на репозиторий это на GitHub. В противном случае вы можете создать одностраничный веб-сайт с множеством разделов, каждый из которых имеет высоту области просмотра, используя только CSS (демонстрация):
.section { height: 100vh; }
или используя JavaScript, добавляя привязку к каждому разделу для навигации между ними и применяя адаптивный блок (мой демонстрация) для текста каждого раздела, к адаптироваться его при изменении размера ... Примерно так:
var curr_el_index = 0;
var els_length = $(".container").length;
$(".next_section").on("click", function(e) {
curr_el_index++;
if (curr_el_index >= els_length) {
curr_el_index = 0;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
$(".previous_section").on("click", function(e) {
curr_el_index--;
if (curr_el_index < 0) {
curr_el_index = els_length - 1;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
}); * {
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body {
background-color: #1a1a1a;
}
section {
height: 100vh;
background-color: #eee;
border: 2px solid red;
font-size: 6vw;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class = "container">Section 1 <a href = "#" class = "previous_section">Previous</a> <a href = "#" class = "next_section">Next</a></section>
<section class = "container">Section 2 <a href = "#" class = "previous_section">Previous</a> <a href = "#" class = "next_section">Next</a></section>
<section class = "container">Section 3 <a href = "#" class = "previous_section">Previous</a> <a href = "#" class = "next_section">Next</a></section>
<section class = "container">Section 4 <a href = "#" class = "previous_section">Previous</a> <a href = "#" class = "next_section">Next</a></section>
<section class = "container">Section 5 <a href = "#" class = "previous_section">Previous</a> <a href = "#" class = "next_section">Next</a></section>РЕДАКТИРОВАТЬ # 1
Идея алгоритма, который исходит от мой код, который использует тот же плагин jQuery:
Onscreen» в
область просмотра (Рекомендации)list, содержащий столько символов / СЛОВ, сколько
есть в метке "Onscreen"section для каждого элемента полученного list, заполнив каждый
section с относительным текстом; количество элементов list
дает вам количество страниц (sections) всего текста. Вы можете
перемещаться между sections, как указано вышеresize повторите [2-5] шагов алгоритма.Ваше здоровье
Мне такой вариант нравится, пригодится
Я думаю, что лучше всего объяснил намерение в своем комментарии к @ravi ниже.
Также посмотрите выше на комментарии, оставленные на OP
Вы можете попробовать точки привязки прокрутки CSS к тексту со столбцами
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points
Каким-то образом сделайте столбцы такой же ширины, как и область просмотра, и разрешите горизонтальную прокрутку с привязкой.
Обновлять
Я хочу попытаться сделать текст полностью плавным, используя css. Ручка:
https://codepen.io/ericc3141/pen/RYZEpr
body {
scroll-snap-type: mandatory;
scroll-snap-points-x: repeat(100%);
}
#columns-test {
height: 80vh;
columns: 90vw auto;
}
Задаваемый вопрос относится к алгоритму, необходимому для перекомпоновки и переформатирования текста, если в клиенте срабатывает событие изменения размера. Ваше предложение отлично работает для обеспечения реальной анимации, но не для перекомпоновки текста.
@JaSuperior Обновлено с примером. Никакого алгоритма не требуется, потому что макет обрабатывается CSS и браузером.
Теперь, когда я действительно пробую это сделать, кажется, что точки привязки не очень хорошо поддерживаются. Я полагаю, что, вероятно, есть и другие решения, плавающие вокруг ...
Идея состоит в том, чтобы иметь div, который будет содержать весь текст (назовем этот div #epub_container). Тогда у вас будет div с тем же размером области просмотра страницы (назовем его #displayer), и он будет содержать #epub_container.
#displayer будет иметь css overflow:hidden. Поэтому, когда сайт загружается, он будет показывать только первую страницу, потому что остальная часть #epub_container будет скрыта.
Затем вам понадобится навигатор по страницам для увеличения / уменьшения номера страницы. Когда номер страницы изменится, мы переместим верхнее смещение #epub_container в зависимости от этого.
Это функция jQuery:
function move_to_page() {
var height = window.innerHeight;
var width = window.innerWidth;
var $displayer = $('#displayer');
var offset = $displayer.offset();
$displayer.height(height - offset.top - 5);
var $epub = $('#epub_container');
var offset_top = offset.top - $displayer.height() * m_page;
$epub.offset({top: offset_top, left: offset.left});
}
Обновлено: вызовите move_to_page() после перекомпоновки текста, чтобы пересчитать страницы.
Все, что вам нужно, это вставить разрыв страницы в нужных местах при загрузке страницы. Вы можете взять реплику отсюда:
Динамический разрыв страницы - JQuery
Здесь вы можете установить высоту страницы в соответствии с высотой вашего окна просмотра. С остальным вы можете справиться с помощью javascript и css.
Возникает вопрос: «Как программно определить, где находятся нужные места». И я, и человек, задающий вопрос, ищем алгоритм, который может оценить текст и определить, где должны быть разрывы, чтобы, если страница изменит размер в зависимости от области просмотра или ориентации, текст будет соответственно перекомпонован и изменен. Алгоритм, представленный по вашей ссылке, этого не делает.
@JaSuperior, Вы правильно прочитали и поняли связанную страницу? В нем есть сценарий и примеры, которые помогут вам разобраться в алгоритме. Фактически, это действительно дает вам правильное место, если длина страницы составляет 960 пикселей и 100 пикселей. Вы должны прочитать все ответы и опробовать прикрепленные к ним скрипки. Этот форум предназначен для вас, а не для выполнения вашей работы.
Ибо тот, кто проголосовал против этого ответа, должен любезно указать причину. Голоса против без причины - это отстой.
Я проголосовал против. И я сказал вам почему. Хотя вы считаете, что это правильный ответ, я не понимаю, какое отношение ваша ссылка к чему-либо имеет. Я пробовал играть на рабочий примерх и читал их ответы. И хотя их реализация для печати, кажется, описывает нечто похожее на то, что мы ищем, представленный алгоритм не делает этого. Так что я проголосовал против.
Это становится очень трудным, если html-страница сложная, например, с точно расположенными элементами или изображениями. Однако, если (как в примере с epub.js) контент состоит только из заголовков и абзацев, это возможно.
Основная идея состоит в том, чтобы постепенно добавлять контент, пока не произойдет переполнение страницы. Отслеживая, где мы начинаем и прекращаем добавление контента, щелчок на следующей странице - это случай изменения начала страницы на конец предыдущей (или наоборот, если вы возвращаетесь).
Предположим, у вас есть весь ваш контент в одной длинной строке. Начните с разделения всего содержимого на массив слов и тегов. Это не так просто, как разделение пробелами, поскольку пробелы между < и > следует игнорировать (вы хотите сохранить имена классов и т. д. В каждом теге). Также теги должны быть разделены, даже если между тегом и словом нет пробелов.
Затем вам понадобится функция, которая проверяет, не выходит ли содержимое элемента за пределы этого элемента. Этот вопрос имеет решение для копирования и вставки.
Вам нужны две переменные, pageStart и pageEnd, чтобы отслеживать, какие индексы в массиве являются началом и концом текущей страницы.
Начиная с индекса в pageStart, вы добавляете элементы из массива в качестве содержимого на страницу, проверяя после каждого добавления, переполняется ли содержимое. Когда они переполняются, вы берете индекс, который вы используете, минус 1, как индекс для pageEnd.
Теперь, если все в порядке, тогда это должно хорошо заполнить страницу. Если вы хотите перейти на следующую страницу, установите новый pageStart как pageEnd + 1 и повторите процесс. Однако есть некоторые проблемы, которые вы, возможно, захотите исправить.
Во-первых, что произойдет, если страница выйдет за край в середине абзаца? Строго говоря, закрывающий тег </p> не требуется в HTML, поэтому нам не о чем беспокоиться. Но как насчет начала следующей страницы? В нем не будет открывающего тега, и это серьезная проблема. Итак, мы должны убедиться, что мы проверяем, начинается ли содержимое страницы с тега, и если это не так, мы получаем ближайший открывающий тег до текущего pageStart (просто сделайте шаг назад по массиву от pageStart) и добавим его перед остальное содержание.
Во-вторых, как показано в примере, если абзац продолжается на следующей странице, последняя строка текущей страницы все еще выравнивается. Вам нужно проверить, находится ли pageEnd в середине абзаца, и если да, добавить syle = "text-align-last:justify;" в открывающий тег этого абзаца.
Ручка, показывающая все это в действии, находится по адресу https://codepen.io/anon/pen/ZMJMZZ.
HTML-страница содержит все содержимое в одном длинном элементе. Контент берется прямо из контейнера #page и преобразуется в страницы в зависимости от размера #page. Я не реализовал выравнивание последней строки, если в абзаце происходит разрыв страницы. Измените размер элемента #page в CSS и посмотрите, как изменяется сам контент - обратите внимание, что, поскольку размер страницы фиксирован, вам придется использовать щелчок вперед и назад, чтобы вызвать пересчет. Как только вы привязываете размер страницы к размеру окна, пересчет страниц на лету просто включает добавление слушателя события изменения размера к окну, которое вызывает fillPage.
Несомненно, существует множество ошибок, действительно, иногда он может отображать вещи неправильно (например, пропуск или повторение слов в начале или конце страницы), но это должно дать вам представление о том, с чего начать.
Это тоже кажется очень хорошим решением, просто нужно немного позаботиться о стиле. Но последнее слово за видимой областью улавливает и кнопки «назад» и «вперед» вполне подходят.
Это определенно кажется наиболее близким к запрошенной реализации. Спасибо за подробности и примеры. Хотя мне интересно, какой будет производительность с большим массивом текста ... При этом я дам пользователю немного больше времени, чтобы ответить, прежде чем назначать награду. Пока что вы лучший кандидат на это ...
@JaSuperior массив рассчитывается только один раз. Для очень больших блоков контента начальное время загрузки может быть заметным, и вы можете рассмотреть возможность динамической загрузки с помощью Ajax. После загрузки производительность при смене страниц должна быть такой же, как и алгоритм, просто проходящий через один и тот же массив. Вместо этого производительность между переключениями страниц зависит от того, сколько контента может поместиться на странице.
да ... но разве мне не нужно было бы повторно инициализировать, если размер экрана / контейнера изменился? как еще он мог бы узнать, как учесть изменение размеров, если, скажем, пользователь изменил ориентацию своего устройства?
Что ж, я пока не занимаюсь производительностью ... хотя это решение не самое отзывчивое. Приведенное выше решение (jsfiddle.net/samu101108/WTPzn/240) лучше всего для отзывчивости, и это вопрос размещения кнопок навигации, и это будет сделано ...
@JaSuperior Повторная инициализация не требуется. Вначале весь контент разбивается на массив тегов и слов. Изменение размера страницы путем изменения размера окна или переориентации устройства не требует пересчета содержимого массива, необходимо только определить, какой раздел массива отображать на странице, что сравнительно дешево. В пером выше splitInput(), который превращает контент в массив, запускается только на window.onload.
Вот один лайнер для разделения содержимого (с использованием регулярного выражения вместо настраиваемой функции разделения) let splittedContent = htmlString.match(/<[^>]*>|[^<\s]+/gm). В остальном я все еще работаю над его оптимизацией (для контента более 10 тысяч слов требуется больше нескольких секунд)
взгляните на github.com/internetarchive/bookreader