【问题标题】:Display dynamic html content like an epub/ebook, without converting html to epub format?显示动态 html 内容,如 epub/ebook,而不将 html 转换为 epub 格式?
【发布时间】:2018-08-26 02:49:44
【问题描述】:

我想使用动态 html 作为源,创建类似于 epub/ebook 阅读器(如 Kindle 应用程序或 iBooks)的响应式、移动优化阅读体验。

想象一篇长篇文章或博客文章需要大量垂直滚动才能阅读,尤其是在小型移动设备上。我想做的是将长页面分成多个全屏部分,允许用户使用左/右导航箭头和/或滑动手势来“翻页”文章。

有许多可用的 JS 库可以创建预定义幻灯片的“幻灯片放映”或“轮播”(使用 div 或其他容器元素)。但我希望文本和 html 内容能够动态地重新流动以适应任何设备视口并且仍然可读......就像 epub/ebook 用户界面,如 Kindle 应用程序或 iBooks。因此,对于同一篇文章,手机上的“页面”将比平板电脑或桌面视口上的多得多,并且如果/当视口大小发生变化时,这些“页面”将需要动态创建/调整(比如在移动设备上从纵向切换到横向)。

这是一个 javascript .epub 阅读器的示例:epub.js

...注意响应行为。当您调整视口大小时,所有文本都会重新排列以适应可用空间,从而增加或减少“页面”的总数。问题是 epub.js 需要一个 .epub 文件作为其源。

我想要的是与 html 页面相同的用户界面和功能。

我已经搜索并搜索了某种可以开箱即用的库,但找不到任何东西。

我意识到我可以使用转换脚本将我的 html 页面转换为 .epub 文件,然后使用 epub.js 在浏览器中呈现该文件,但这似乎非常迂回和笨拙。使用 html 作为直接源来模拟或模拟 .epub 阅读器用户体验会好得多,呈现/模拟客户端响应式电子书用户体验。

有谁知道这样的东西是否已经存在,或者我该如何自己构建它?

关键功能是动态/响应式文本重排。当视口尺寸减小时,文本/内容需要回流到下一个“页面”以避免任何垂直滚动的需要。我不知道如何有效地做到这一点。如果我自己编写代码,我可能会使用 jQuery Columnize 插件之类的东西,将所有列设置为width: 100vw; height: 100vh,这样每一列就像一个“页面”,然后弄清楚如何在这些“之间创建一个滑动 UI”页”。

非常感谢任何帮助!

【问题讨论】:

  • 这是一个非常广泛的问题,并不具体或技术性不够,无法在此处发布。因此,它不值得回答,也许需要消失?无论如何,您需要寻找“响应式分页”脚本/库。从 2012 年开始,here's an answer,这就是我要开始的地方。使用 JS 分析“长格式”HTML 内容并根据视口大小动态分解。从那里找出动画页面的控件(滑动、箭头等)。如果您还考虑过动态服务器通信,那就是另一种蠕虫。
  • @user2655393 你找到解决办法了吗?

标签: javascript jquery html css


【解决方案1】:

如果 html 页面很复杂,例如具有精确定位的元素或图像,这将变得非常困难。但是,如果(如 epub.js 示例中)内容仅包含标题和段落,则可以实现。

基本思想是逐步添加内容,直到页面溢出。通过跟踪我们开始和停止添加内容的位置,点击下一页就是将页面开始更改为上一页结束的情况(如果您要返回,反之亦然)。

将内容重塑为页面的过程

假设您将所有内容都放在一个长字符串中。首先将所有内容拆分为一组单词和标签。它不像用空格分割那样容易,因为<> 之间的空格应该被忽略(你想在每个标签中保留类名等)。标签也应该分开,即使标签和单词之间没有空格。

接下来,您需要一个检查元素内容是否溢出元素的函数。 This question 有一个复制粘贴解决方案。

您需要两个变量 pageStartpageEnd 来跟踪数组中的哪些索引是当前页面的开头和结尾。

pageStart 中的索引开始,您将数组中的元素作为内容添加到页面,每次添加后检查内容是否溢出。当它们确实溢出时,您将您达到的索引减去 1 作为pageEnd 的索引。

在分页符之间保留标签

现在,如果所有的ticketyboo 那么这应该会很好地填满页面。当您想转到下一页时,将新的pageStart 设置为pageEnd + 1 并重复该过程。但是,您可能需要解决一些问题。

首先,如果页面在段落中间溢出怎么办?严格来说,结束标记</p> 在 HTML 中不是必需的,因此我们无需担心。但是下一页的开头呢?它将缺少一个开始标签,这是一个主要问题。所以我们确保我们检查页面的内容是否以标签开头,如果不是,那么我们得到当前pageStart之前最接近的开始标签(只需从pageStart返回数组)并添加它在其余内容之前。

其次,如示例所示,如果一个段落继续到下一页,则当前页面的最后一行仍然是对齐的。您需要检查pageEnd 是否在段落的中间,如果是,则将syle="text-align-last:justify;" 添加到该段落的开始标记。

示例实现

显示这一切的笔在https://codepen.io/anon/pen/ZMJMZZ

HTML 页面包含一个长元素中的所有内容。内容直接取自容器#page,并根据#page 的大小重新形成页面。如果段落中出现分页符,我还没有实现证明最后一行的合理性。调整 css 中 #page 元素的大小并查看内容如何调整自身的大小 - 请注意,由于页面大小是固定的,因此您必须使用向前和向后单击来触发重新计算。将页面大小绑定到窗口大小后,动态重新计算页面只需向调用 fillPage 的窗口添加一个调整大小事件侦听器。

毫无疑问有很多错误,确实有时会显示不正确的内容(例如在页面的开头或结尾跳过或重复单词),但这应该让您知道从哪里开始。

【讨论】:

  • 这似乎也是一个很好的解决方案,只是需要注意一下样式。但它抓住了可视区域的最后一个词,“后退”和“前进”按钮非常正确。
  • 这绝对是最接近要求的实现。感谢您的详尽并提供示例。虽然,我想知道大量文本的性能会如何......话虽如此,在发放赏金之前,我会给大家更多的时间来回答。到目前为止,你最适合它...
  • @JaSuperior 数组只计算一次。对于非常大的内容块,初始加载时间可能很明显,您可能需要考虑使用 Ajax 进行动态加载。更改页面时的加载性能应该与算法相同,只是单步执行相同的数组。相反,页面切换之间的性能取决于页面上可以容纳多少内容。
  • 是的...但是如果屏幕/容器大小发生变化,我不需要重新初始化吗?如果用户改变了他们设备的方向,它怎么知道尺寸变化的原因?
  • 好吧,我还没有进入性能方面……尽管这个解决方案不是响应速度更快的解决方案。上面给定的解决方案 (jsfiddle.net/samu101108/WTPzn/240 ) 是最好的响应性,它是放置导航按钮的问题,这将完成......
【解决方案2】:

查看 GitHub 上的 this 存储库。否则,您可以仅使用CSS (demo) 创建一个包含多个部分的单页网站,每个部分与视口一样高:

.section { height: 100vh; }

或者通过使用JavaScript,在每个部分添加一个锚点以在它们之间导航,并为每个部分的文本应用一个响应单元(我的demo),在调整大小时adapt它......像这样:

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

算法的想法,来自my codepen,使用相同的jQuery 插件

  1. 创建您的阅读器布局,复制其中的整个文本
  2. 使用this jQuery 插件检查视口内的文本 (demo)
  3. 用“Onscreen”标签计算字符/单词的数量 视口(@98​​7654330@)
  4. 将整个文本拆分为一个list,其中包含与 在“Onscreen”标签中有
  5. 为获得的list的每个元素创建一个section,填充每个 section 带有相关文字; list 的元素个数 为您提供整个文本的页数 (sections)。你可以 像上面一样在sections 之间导航
  6. resize 事件中,重做 [2-5] 个算法步骤

干杯

【讨论】:

  • 我喜欢这个选项,会派上用场
  • 我想我在下面对@ravi 的评论中最好地解释了这个意图
  • 还可以看看上面 OP 上留下的 cmets
【解决方案3】:

我们的想法是创建一个包含整个文本的 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});
}

JSFiddle

编辑:在文本重排后调用move_to_page() 以重新计算页面。

【讨论】:

    【解决方案4】:

    您可以在带有列的文本上尝试 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 和浏览器处理。
    • 虽然我实际上尝试了这个,但似乎快照点并没有得到很好的支持。我想可能还有其他解决方案......
    【解决方案5】:

    您只需在加载页面时在正确的位置插入分页符。你可以从这里得到提示:

    Dynamic Page-Break - Jquery

    您可以在此处将页面高度设置为视口高度。您可以使用 javascript 和 css 处理其余部分。

    【讨论】:

    • 被问到的问题是“如何以编程方式确定正确的位置”。我自己和提出问题的人都在寻找一种算法,可以评估文本并确定需要中断的位置,以便如果页面根据视口或方向改变大小,文本将相应地重排和重新分页。您链接中提供的算法没有这样的事情。
    • @JaSuperior,您是否正确阅读并理解了链接页面?它有脚本和示例来指导您使用算法。事实上,假设页面长度为 960 像素和 100 像素,它确实为您提供了正确的位置。您应该阅读所有答案并尝试其中的小提琴。这个论坛是为了指导你,而不是做你的工作。
    • 对于否决这个答案的人,应该礼貌地提供原因。无缘无故投反对票是蹩脚的。
    • 我投了反对票。我告诉你为什么。尽管您认为这是正确的答案,但我看不出您的链接与任何事情有什么关系。我已经尝试过小提琴,并阅读了他们的答案。虽然,他们的打印实现似乎描述了与我们正在寻找的类似的东西,但所提出的算法并没有这样的事情。所以我投了反对票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    • 2013-08-02
    • 1970-01-01
    相关资源
    最近更新 更多