javascript-类似HTML的分页

如何将HTML文件的内容分成屏幕大小的块,以在WebKit浏览器中“分页”?

每个“页面”应显示完整数量的文本。 这意味着不得在屏幕的顶部或底部边界将文本行切成两半。

编辑

该问题最初被标记为“ Android”,因为我的目的是构建Android ePub阅读器。 但是,看来该解决方案只能用JavaScript和CSS来实现,因此我扩大了问题的范围,使其与平台无关。

hpique asked 2019-10-08T06:25:46Z
10个解决方案
30 votes

在Dan的答案基础上,是我对这个问题的解决方案,直到现在我一直在为此奋斗。 (此JS可在iOS Webkit上运行,不保证适用于android,但请告诉我结果)

var desiredHeight;
var desiredWidth;
var bodyID = document.getElementsByTagName('body')[0];
totalHeight = bodyID.offsetHeight;
pageCount = Math.floor(totalHeight/desiredHeight) + 1;
bodyID.style.padding = 10; //(optional) prevents clipped letters around the edges
bodyID.style.width = desiredWidth * pageCount;
bodyID.style.height = desiredHeight;
bodyID.style.WebkitColumnCount = pageCount;

希望这可以帮助...

Engin Kurutepe answered 2019-10-08T06:25:59Z
21 votes

从经验上来讲,即使是准系统的观看者,也要花很多时间。 ePub阅读器实际上是我开始学习C#时从事的第一个大型项目,但是ePub标准肯定非常复杂。

您可以在此处找到ePub规范的最新版本:[http://www.idpf.org/specs.htm]其中包括OPS(开放出版物结构),OPF(开放包装格式)和OCF(OEBPS容器格式)。

另外,如果它对您有帮助,那么这里有指向我开始的项目的C#源代码的链接:

[https://www.dropbox.com/sh/50kxcr29831t854/MDITIklW3I/ePub%20Test.zip]

它根本没有充实; 我已经几个月没有玩这个游戏了,但是如果我没记错的话,只需将ePub粘贴在debug目录中,然后在运行程序时键入名称的一部分即可(例如,在Dome下,键入“ dome”)。 它将显示该书的详细信息。

我可以在几本书上正常使用,但是Google图书中的所有电子书都将其完全破坏了。 与其他来源的图书相比,它们对ePub的实现完全是奇怪的(至少对我而言)。

无论如何,希望其中的一些结构代码可以对您有所帮助!

kcoppock answered 2019-10-08T06:27:06Z
18 votes

我也必须编写类似这样的代码,而我的(有效的)解决方案是这样的:

您必须将这些行应用于webview ...

    webView_.getSettings().setUseWideViewPort(true);
    webView_.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);

另外,您必须注入一些JavaScript。 我的活动规模和在Web视图中呈现的内容的规模各不相同,因此我遇到了很多问题,因此我的解决方案没有任何“外部”价值。

    webView_.setWebViewClient(new WebViewClient(){

            public void onPageFinished(WebView view, String url) {
                injectJavascript();
            }

        });

[...]

    public void injectJavascript() {
        String js = "javascript:function initialize() { " +
                "var d = document.getElementsByTagName('body')[0];" +
                "var ourH = window.innerHeight; " +
                "var ourW = window.innerWidth; " + 
                "var fullH = d.offsetHeight; " +
                "var pageCount = Math.floor(fullH/ourH)+1;" +
                "var currentPage = 0; " +
                "var newW = pageCount*ourW; " +
                "d.style.height = ourH+'px';" +
                "d.style.width = newW+'px';" +
                "d.style.webkitColumnGap = '2px'; " +
                "d.style.margin = 0; " +
                "d.style.webkitColumnCount = pageCount;" +
                "}";
        webView_.loadUrl(js);
        webView_.loadUrl("javascript:initialize()");
    }

请享用 :)

Nacho L. answered 2019-10-08T06:27:48Z
12 votes

我最近尝试了类似的方法,并添加了一些CSS样式以将布局更改为水平而不是垂直。 这给了我所需的效果,而无需以任何方式修改Epub的内容。

此代码应该起作用。

mWebView.setWebViewClient(new WebViewClient() {
    public void onPageFinished(WebView view, String url) {

        // Column Count is just the number of 'screens' of text. Add one for partial 'screens'
        int columnCount = Math.floor(view.getHeight() / view.getWidth())+1;

        // Must be expressed as a percentage. If not set then the WebView will not stretch to give the desired effect.
        int columnWidth = columnCount * 100;

        String js = "var d = document.getElementsByTagName('body')[0];" + 
            "d.style.WebkitColumnCount=" + columnCount + ";" + 
            "d.style.WebkitColumnWidth='" + columnWidth + "%';";
        mWebView.loadUrl("javascript:(function(){" + js + "})()");
    }
});

mWebView.loadUrl("file:///android_asset/chapter.xml");

因此,基本上,您是在章节加载后注入JavaScript来更改body元素的样式(非常重要)。 这种方法的唯一缺点是,当内容中包含图像时,计算出的列数就会歪斜。 修复起来并不难。 我的尝试是注入一些JavaScript来为DOM中没有任何图像的所有图像添加width和height属性。

希望能帮助到你。

-担

Dan answered 2019-10-08T06:28:24Z
4 votes

也许可以使用XSL-FO。 对于移动设备来说,这似乎很沉重,也许是过大了,但是它应该可以工作,并且您不必自己实现良好的分页的复杂性(例如,如何确保每个屏幕都不会将文本切成两半) 。

基本思想是:

  • 使用XSLT将XHTML(和其他EPUB内容)转换为XSL-FO。
  • 使用XSL-FO处理器将XSL-FO渲染为可以在移动设备上显示的页面格式,例如PDF(可以显示吗?)

我不知道是否有适用于Android的XSL-FO处理器。 您可以尝试Apache FOP。 RenderX(XSL-FO处理器)具有页面HTML输出选项的优点,但是我也不知道它是否可以在Android上运行。

LarsH answered 2019-10-08T06:29:15Z
1 votes

有几种方法可以完成此操作。 如果每一行都在其自己的元素中,那么您要做的就是检查其边缘之一是否超出视图范围(浏览器或“书页”)。

如果您想提前知道有多少个“页面”,只需将它们暂时移入视图并获取页面结束的行。 这可能很慢,因为浏览器需要页面重排才能知道任何内容。

否则,我认为您可以使用HTML5 canvas元素来测量文本和/或绘制文本。

有关此的一些信息:     [https://developer.mozilla.org/en/Drawing_text_using_a_canvas]     [http://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa-excanvas.js/demo/8_2_canvas_measureText.html]

Frank answered 2019-10-08T06:30:00Z
1 votes

最近有同样的问题,并受到答案的启发,找到了使用CSS3的column- *属性的简单CSS解决方案:

/* CSS */
.chapter {
    width: 600px;
    padding: 60px 10px;
    -webkit-column-gap: 40px;
    -webkit-column-width: 150px;
    -webkit-column-count: 2;
    height:400px;
}

/* HTML */
<div class="chapter">
    your long lorem ipsum arbitrary HTML
</div>

上面的示例在视网膜iPhone上给出了很好的结果。 玩弄不同的属性会导致页面等之间的间距不同。

例如,如果您需要支持需要从新页面开始的多个章节,则在github上有一个XCode 5示例:[https://github.com/dmrschmidt/ios_uiwebview_pagination]

Dennis answered 2019-10-08T06:30:38Z
1 votes

我能够改进Nacho的解决方案,以使用WebView获得水平滑动分页效果。 您可以在此处找到解决方案和示例代码。

编辑:

解决方案代码。

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        WebView.setWebContentsDebuggingEnabled(true);
    }
    wv = (HorizontalWebView) findViewById(R.id.web_view);
    wv.getSettings().setJavaScriptEnabled(true);
    wv.setWebViewClient(new WebViewClient() {

        public void onPageFinished(WebView view, String url) {
            injectJavascript();
        }
    });

    wv.setWebChromeClient(new WebChromeClient() {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            int pageCount = Integer.parseInt(message);
            wv.setPageCount(pageCount);
            result.confirm();
            return true;
        }
    });
    wv.loadUrl("file:///android_asset/ch03.html");   // now it will not fail here
}

private void injectJavascript() {
    String js = "function initialize(){\n" +
            "    var d = document.getElementsByTagName('body')[0];\n" +
            "    var ourH = window.innerHeight;\n" +
            "    var ourW = window.innerWidth;\n" +
            "    var fullH = d.offsetHeight;\n" +
            "    var pageCount = Math.floor(fullH/ourH)+1;\n" +
            "    var currentPage = 0;\n" +
            "    var newW = pageCount*ourW;\n" +
            "    d.style.height = ourH+'px';\n" +
            "    d.style.width = newW+'px';\n" +
            "    d.style.margin = 0;\n" +
            "    d.style.webkitColumnCount = pageCount;\n" +
            "    return pageCount;\n" +
            "}";
    wv.loadUrl("javascript:" + js);
    wv.loadUrl("javascript:alert(initialize())");
}

在我的WebChromeClient的onJsAlert中,获取传递给自定义HorizontalWebView来实现分页效果的水平页面数

HorizontalWebView.java

public class HorizontalWebView extends WebView {
    private float x1 = -1;
    private int pageCount = 0;

    public HorizontalWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                float x2 = event.getX();
                float deltaX = x2 - x1;
                if (Math.abs(deltaX) > 100) {
                    // Left to Right swipe action
                    if (x2 > x1) {
                        turnPageLeft();
                        return true;
                    }

                    // Right to left swipe action
                    else {
                        turnPageRight();
                        return true;
                    }

                }
                break;
        }
        return true;
    }

    private int current_x = 0;

    private void turnPageLeft() {
        if (getCurrentPage() > 0) {
            int scrollX = getPrevPagePosition();
            loadAnimation(scrollX);
            current_x = scrollX;
            scrollTo(scrollX, 0);
        }
    }

    private int getPrevPagePosition() {
        int prevPage = getCurrentPage() - 1;
        return (int) Math.ceil(prevPage * this.getMeasuredWidth());
    }

    private void turnPageRight() {
        if (getCurrentPage() < pageCount - 1) {
            int scrollX = getNextPagePosition();
            loadAnimation(scrollX);
            current_x = scrollX;
            scrollTo(scrollX, 0);
        }
    }

    private void loadAnimation(int scrollX) {
        ObjectAnimator anim = ObjectAnimator.ofInt(this, "scrollX",
                current_x, scrollX);
        anim.setDuration(500);
        anim.setInterpolator(new LinearInterpolator());
        anim.start();
    }

    private int getNextPagePosition() {
        int nextPage = getCurrentPage() + 1;
        return (int) Math.ceil(nextPage * this.getMeasuredWidth());
    }

    public int getCurrentPage() {
        return (int) (Math.ceil((double) getScrollX() / this.getMeasuredWidth()));
    }

    public void setPageCount(int pageCount) {
        this.pageCount = pageCount;
    }
}
Gautam Chibde answered 2019-10-08T06:31:28Z
0 votes

您可以将页面拆分为单独的XHTML文件,并将它们存储在文件夹中。 例如:page01,page02。 然后,您可以将这些页面彼此一一呈现。

Charles answered 2019-10-08T06:31:52Z
0 votes

您可以查看[http://www.litres.ru/static/OR/or.html?data=/static/trials/00/42/47/00424722.gur.html&art=424722&user=0&trial=1], 代码可能会被大量混淆,因此只需使用Firebug来检查DOM。

如果该链接无效,请发表评论-将为您解决。

kagali-san answered 2019-10-08T06:32:23Z
translate from https://stackoverflow.com:/questions/3636052/html-book-like-pagination