likes
comments
collection
share

文档渲染(DOC,DOCX,PDF,TXT)方案以及解决微前端中子应用DOCX解析失效!

作者站长头像
站长
· 阅读数 13

DOC

前端暂无方式预览,最好后端一个转PDF服务支持

DOCX

docx-previewmammoth底层都是基于jszip解析DOCX, 仅仅支持DOCX!!!!

/**
* @file  doc
* @author shenzhiqiang01
* @date 2023-08-03
*/

import React, {useRef, useState, useEffect} from 'react';
import * as docx from '../../../libs/docx-preview/docx-preview';
import style from './index.module.less';
import ErrStatus from './errStatus';
import {Loading} from 'acud';
import mammoth from 'mammoth';
// import {default as htmlParser} from 'react-html-parser'; // 支持react Deff



const DocRender = ({file}) => {
  const ref = useRef(null);
  const [loading, setLoading] = useState(true);
  const [convertedText, setConvertedText] = useState('');
  const [isErr, setIsErr] = useState(false);
  const renderBlob = async file => {
    docx.renderAsync(file, ref.current, undefined)
      .then(x => {
        setLoading(false);
        console.log('docx: finished');
      }).catch(err => {
        console.log(err, 'err');
        setIsErr(true);
      }).finally(final => {
        console.log(final, 'final');
        setLoading(false);
      });

  };
  const convertToWord = () => {
    if (file) {
      const reader = new FileReader();
      reader.onload = event => {
        const arrayBuffer = event.target.result;
        const options = {
          arrayBuffer: arrayBuffer
        };

        mammoth.convertToHtml(options)
          .then(result => {
            console.log(result, 'result');
            setConvertedText(result.value);
            setLoading(false);

          })
          .catch(error => {
            console.error(error);
          });
      };

      reader.readAsArrayBuffer(file);
    }
  };
  useEffect(() => {
    if (file) {
      setLoading(true);
      setIsErr(false);
      renderBlob(file);
    }
  }, [file, ref]);


  return (
    <div className={style['doc-render']}>
      {loading ? <Loading /> : ''}
      {
      isErr ? <ErrStatus className={style.errStatus} /> : <div id='doc' ref={ref}></div>
      }

    </div>
  );
};


export default DocRender;

问题:在微前端中如果子应用相关库使用了jszip,如何解决jszip失效(docx的解析依赖jszip)

需要主应用去加载jszip,挂载在winnow中。

gcdn.grapecity.com.cn/showtopic-1…

文档渲染(DOC,DOCX,PDF,TXT)方案以及解决微前端中子应用DOCX解析失效!

解决:

在主应用中加载jszip

        <script src="/jszip.min.js"></script>
        <!-- <script async src="https://unpkg.com/jszip@3.10.1/dist/jszip.min.js"></script> -->

PDF

react-pdf 兼容性较好

/**
* @file  index2
* @author shenzhiqiang01
* @date 2023-08-02
*/

import React, {useState, useMemo, useRef, useCallback} from 'react';
import {Document, Page, pdfjs} from 'react-pdf';
import styles from './index.module.less';
import {useMeasure} from 'react-use';

import {Loading} from 'acud';
import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';
import {map} from 'lodash';

const EVERY_COUNT = 1; // 每次滑倒底时预加载几页


pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;

const PdfRender = ({file}) => {
    const [ref, {width: wrapWidth}] = useMeasure();
    const [numPages, setNumPages] = useState(0);// pdf总页数;
    const currRef = useRef(); // backtop父元素dom信息

    const onDocumentLoaded = ({numPages}) => {
        setNumPages(numPages);
    };

    const pdfRenderer = useMemo(() => {
        if (!file) {
            return <Loading />;
        }
        return (
            <div
                ref={currRef}
            >
                <Document
                    file={file}
                    onLoadSuccess={onDocumentLoaded}
                    loading={<Loading size="large" />}
                    renderMode='canvas'
                >
                    {
                        map(new Array(numPages).fill(Math.random()), ((item, index) => {
                            return (
                                <Page
                                    key={index}
                                    width={wrapWidth}
                                    pageNumber={index + 1}
                                    loading={<Loading size="large" />}
                                // customTextRenderer={textRenderer}
                                />
                            );
                        }))
                    }

                </Document>
            </div>
        );
    }, [file, numPages, wrapWidth]);

    return (
        <div
            ref={ref}
            className={styles['pdf-render']}
        >
            {
                pdfRenderer
            }
        </div>
    );
};


export default PdfRender;

TXT

txt预览仅需要将blob流转成字符串即可。

但需要注意的是txt转字符串需要指定对应的编码格式,否则出现乱码。

可以使用jschardet来判断编码

/**
* @file  txt
* @author shenzhiqiang01
* @date 2023-08-03
*/

import React, {useRef, useState, useEffect} from 'react';
import {Input, Loading} from 'acud';
import style from './index.module.less';
import jschardet from 'jschardet';



const TxtRender = ({file}) => {
    const [txtVal, setTxt] = useState();
    const [loading, setLoading] = useState(true);

    // 将Blob流转为字符串
    const blobToString = async (blob, charset) => {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => {
                resolve(reader.result);
            };
            reader.onerror = reject;
            console.log(charset, 'charset');
            reader.readAsText(blob, 'KOI8-R');
        });
    };

    const getCharset = async blob => {
        return new Promise((resolve, reject) => {
            let reader = new FileReader();
            reader.readAsDataURL(blob);
            reader.onload = function (e) {
                let base64Str = reader.result;
                let str = atob(base64Str.split(';base64,')[1]);
                console.log(str, 'str');
                jschardet.enableDebug();
                let encoding = jschardet.detect(str, {
                    minimumThreshold: 0.1, detectEncodings:
                        ['UTF-8', 'windows-1252', 'gb2312']
                });
                console.log(encoding, 'encoding---');
                encoding = encoding.encoding;
                if (encoding === 'window-1252') {
                    encoding = 'ANSI';
                }
                resolve(encoding);
            };
        });

    };

    const renderBlob = async file => {
        // 使用示例
        let charset1 = await getCharset(file);
        console.log(charset1, 'charset1');
        let charset = 'KOI8-R';
        blobToString(file, charset)
            .then(text => {
                setTxt(text);
                setLoading(false);
            })
            .catch(error => {
                console.error('转换失败:', error);
            });

        console.log(file, 'response');
    };
    useEffect(() => {
        if (file) {
            setLoading(true);
            renderBlob(file);
        }
    }, [file]);


    return (
        <div className={style['txt-render']}>
            {loading ? <Loading /> : ''}
            <Input.TextArea
                value={txtVal}
                autoSize
                bordered={false}
                allowClear={false}
                style={{
                    color: '#151B26',
                    backgroundColor: '#fff',
                    border: 'none'
                }}
            />
        </div>
    );
};


export default TxtRender;

DOC和DOCX区别

docx-preview 是一个用于预览 DOCX 格式的文档的库,它并不支持 DOC 文件的预览。这是因为 DOCX 和 DOC 两种文件格式有着不同的结构和编码方式。

DOCX 格式是基于 Office Open XML 格式的文档,它是以 XML 和 ZIP 压缩方式存储的,其中包含了文本、样式、图像和其他元数据等信息。docx-preview 可以解析和渲染 DOCX 文件,因为它能够理解和处理 DOCX 文件的结构。

然而,DOC 格式是一种较早期的二进制格式,它的结构和编码方式与 DOCX 格式不同。因此,docx-preview 无法直接解析和渲染 DOC 文件。

要在网页中预览 DOC 文件,您可能需要使用其他的库或服务,如 Apache POI、Aspose.Words 或者将 DOC 文件转换为 PDF 或 HTML 格式并在网页中进行展示。这些库和服务提供了将 DOC 文件转换为可预览的格式的功能,以便在网页中进行展示。具体选择和实现方式取决于您的项目需求和技术栈。