Я знаю, что название неясно, но по сути я пытаюсь сделать свой собственный рендеринг для epub, и я в настоящее время использую наивный подход к тому, чтобы подготовить содержание главы и попытаться отображать его в веб -просвети после разделения контента на основе тегов. View. Содержимое накоплено непосредственно до превышения высоты. Определение логики или недостатка расчета здесь в сравнении высоты макета. Дайте мне знать, если я что -то пропустил.import { EPUBChapter, epubHtmlTemplate, ParsedEPUB } from "@/lib/EpubParser";
import { useEffect, useRef, useState } from "react";
import { parseDocument, DomUtils } from "htmlparser2";
import render from "dom-serializer";
import { WebView } from "react-native-webview";
import { Text } from "./ui/text";
import { useHtmlHeightMeasurer } from "@/hooks/useHtmlHeightMeasurer";
import { View, PixelRatio, FlatList } from "react-native";
export function WebViewCarousel({
parsedEpub,
currentChapterIndex = 0,
}: {
parsedEpub: ParsedEPUB;
currentChapterIndex: number;
}) {
const chapters = parsedEpub.chapters;
const [currentChapter, setCurrentChapter] = useState(
undefined
);
const view = useRef(null);
// const { html } = useHtmlHeightMeasurer(viewDimensions.width, viewDimensions.height);
const { measureHtmlHeight, MeasuringWebView, resizeWebView } =
useHtmlHeightMeasurer(355, 355);
const [pages, setPages] = useState([]);
async function* pageGenerator(
chapterHtml: string,
dimensions: { width: number; height: number }
) {
resizeWebView({ height: dimensions.width, width: dimensions.height });
const parsedChapterHtml = parseDocument(chapterHtml);
const htmlNodes = parsedChapterHtml.children;
let pageNodes: typeof parsedChapterHtml.children = [];
const chapterContent = DomUtils.findOne(
(elem) => elem.name === "section",
htmlNodes
);
// const pixelHeight = PixelRatio.getPixelSizeForLayoutSize(dimensions.height);
const pixelHeight = dimensions.height;
if (chapterContent) {
for (const [index, node] of chapterContent.children.entries()) {
const testPage = render([...pageNodes, node]);
// console.log('Node: ' + render(node));
if (testPage.trim()) {
const webViewHeight = await measureHtmlHeight(
epubHtmlTemplate(testPage)
);
console.log("View height: " + pixelHeight);
console.log("Measured Height: " + webViewHeight);
if (webViewHeight >= pixelHeight) {
console.log("Yielding Page");
yield pageNodes;
pageNodes = [];
}
pageNodes.push(node);
}
}
}
console.log("Final page");
return pageNodes;
}
// const generatePage = pageGenerator(chapters[currentChapterIndex].content);
async function generatePages({
width,
height,
}: {
width: number;
height: number;
}) {
const pagesToAdd = [];
for await (const page of pageGenerator(
chapters[currentChapterIndex].content,
{ width, height }
)) {
console.log(render(page));
pagesToAdd.push(render(page));
}
setPages([...pages, ...pagesToAdd]);
}
return (
{
generatePages({
height: e.nativeEvent.layout.height,
width: e.nativeEvent.layout.width,
});
}}
>
{pages.length > 0 && (
)}
);
}
< /code>
Компонент вне экрана, используемый для измерения контента, пока он не переполнит < /p>
import { epubHtmlTemplate } from "@/lib/EpubParser";
import React, { useRef, useState } from "react";
import { View } from "react-native";
import { WebView } from "react-native-webview";
const measureJs = `
(() => {
const observer = new MutationObserver(measure)
let debounce;
function measure() {
clearTimeout(debounce);
debounce = setTimeout(() => {
try {
const container = document.getElementById('epub-content');
if(container) {
const height = container.scrollHeight;
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'measurement',
value: height
}));
} else {
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'error',
value: 'Missing container with id epub-content'
}));
}
} catch (error) {
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'error',
value: error.message
}));
}
}, 150);
}
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true
});
measure();
})()
`;
export function useHtmlHeightMeasurer(width: number, height: number) {
const [html, setHtml] = useState("");
const resolver = useRef void>();
const webViewRef = useRef(null);
const [webViewDimensions, setWebViewDimensions] = useState({
height: 0,
width: 0
});
const measureHtmlHeight = (htmlString: string) =>
new Promise((resolve) => {
resolver.current = resolve;
setHtml(htmlString);
});
const resizeWebView = ({ width, height }: { width: number, height: number }) => {
setWebViewDimensions({ width, height })
}
const MeasuringWebView = () => (
{
const data = JSON.parse(event.nativeEvent.data);
if(data.type === 'error') {
console.error(data.value)
}
if (data.type === "measurement") {
const h = Number(data.value);
if (resolver.current) {
resolver.current(h);
resolver.current = undefined;
}
}
}}
style={{ width: webViewDimensions.width, height: webViewDimensions.height, backgroundColor: "transparent" }}
/>
);
return { measureHtmlHeight, MeasuringWebView, resizeWebView };
}
Подробнее здесь: https://stackoverflow.com/questions/797 ... a-web-view
Реагируйте родную высоту вида и высоту DIV внутри веб -вида ⇐ Android
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение