nodejs实现解析chm文件列表,无需转换为PDF文件格式,在线预览chm文件以及目录,不依赖任何网页端插件


特性:

1、支持任意深度的chm文件解析

2、解析后内容结构转换为tree数据呈现

3、点击树节点可以在html实时查看数据 

4、不依赖任何浏览器端插件,兼容性较好

nodejs端核心代码 

const $g = global.SG.$g, fs = global.SG.fs, router = global.SG.router, xlsx = global.SG.xlsx;
module.exports = global.SG.router;let webRootPath = 'http://127.0.0.1:9999/chm/';//测试环境chm文件根目录//上传单个文件(all方法支持POST、GET、PUT、PATCH、DELETE传参方式)
let uploadFileName = '';//获取上传后的文件名
router.all("/chm/upload",//接口路径$g.dir.upload("./upload",//存储临时上传文件的路径({ fileName, } = {}) => { uploadFileName = fileName; }).single("file"),//上传单个文件(req, res) => {// 开始解压上传的upload文件----------------------------------------let cp = require('child_process');cp.exec("reg query HKEY_CLASSES_ROOT\\360zip\\shell\\open\\command /ve", function (e, stdout, stderr) {let rootPath = `${__dirname.split('\\').slice(0, -3).join('\\')}`;let uploadFolderPath = `${rootPath}\\upload\\${uploadFileName}`;let targetFolderPath = `${rootPath}\\chm\\${uploadFileName}`;let str = stdout.match(/\"([^\"]+)\"/)[0];if (str) {// console.log('已经找到360zip程序,详细地址为:'+str);cp.exec(`${str} -x ${uploadFolderPath} ${targetFolderPath}`, { encoding: 'binary' }, function (e, stdout, stderr) {// 遍历读取目录里面的文件----------------------------------------let files = [];let walker = require('walk').walk(targetFolderPath, { followLinks: false });walker.on('file', function (roots, stat, next) {if (stat.name.includes(`.hhc`)) {let hhcFilePath = `${roots}/${stat.name}`;files.push(hhcFilePath);fs.readFile(hhcFilePath, 'utf-8', (err, data) => $g.json.res(req, res, "chm文件解析成功", {htmPath: `${webRootPath}${uploadFileName}/`,hhcFilePath: `${webRootPath}${uploadFileName}/${stat.name}`,hhcData: data,}, true));} else next();});walker.on('end', function () {files.length === 0 && $g.json.res(req, res, "没有找到hhc文件,请仔细检查chm文件是否正确!", { targetFolderPath }, false);});});} else {console.log('没有找到360zip程序,无法完成解压缩功能,请在服务器端安装360zip软件!');}});}
);

vue前端核心代码

<template><div :class="$options.name"><div class="sg-left " v-loading="loading"><!-- 树节点 --><div class="tree-header"><!-- 树节点 --><div class="tree-header"><div class="sg-left "><el-tooltip popper-class="sg-el-tooltip" :enterable="false" effect="dark" :content="`支持拖拽到树上传文件`"placement="top-start"><el-button type="text" icon="el-icon-upload" size="mini"@click="d => $refs.sgUpload.triggerUploadFile()">上传chm文件</el-button></el-tooltip></div><div class="sg-right "></div></div></div><div class="tree-body" @click="treeData.length === 0 ? $refs.sgUpload.triggerUploadFile() : ''"><el-tree ref="tree" @current-change="current_change" :data="treeData":props="{ label: 'Name', children: 'children' }" :icon-class="'folder-tree-node'" :indent="25"@node-click="nodeClick" node-key="id" :filter-node-method="filterNode" default-expand-allhighlight-current :default-expanded-keys="default_expanded_keys"><div slot="reference" class="node-label" slot-scope="{ node, data }"><label class="left" :title="node.label">{{ node.label }}</label></div></el-tree><sgUpload drag ref="sgUpload" :data="{accept: `.${['chm'].join(',.')}`,// actionUrl: `http://127.0.0.1:9999/api/chm/upload`,actionUrl: `http://xxx.xxxxxx.cn:33/api/chm/upload`,headers: {},}" @beforeUpload="beforeUpload" @uploadSuccess="uploadSuccess" @error="uploadError" hideUploadTray /></div></div><div class="sg-right "><iframe id="iframe" ref="iframe" :src="src" frameborder="no" style="width:100%;height:100%;"></iframe></div><div class="hhcHTML" ref="hhcHTML" style="display: none;"> </div></div>
</template><script>
import sgUpload from "@/vue/components/admin/sgUpload";
export default {name: 'chmDecode',components: {sgUpload,},data() {return {loading: false,htmPath: '',src: '',current_node: null,default_expanded_keys: [],treeData: [],}},created() {},methods: {// 解析hhc文件decodeHhcData(doms) {let r = [];let _recursion = (doms, d) => {[].slice.call(doms).forEach(v => {let OBJECT = v.querySelector(`OBJECT`);let p0 = OBJECT.querySelectorAll(`param`)[0];let p1 = OBJECT.querySelectorAll(`param`)[1];let obj = {id: this.$g.UUID(),[p0.getAttribute('name')]: p0.getAttribute('value'),//文件别名[p1.getAttribute('name')]: p1.getAttribute('value'),filePath: `${this.htmPath}${p1.getAttribute('value')}`,//文件路径}this.current_node || (this.current_node = obj);d.push(obj)if (OBJECT.nextElementSibling) {obj.children = []_recursion(OBJECT.nextElementSibling.children, obj.children)}});}_recursion(doms, r);return r;},// 开始上传beforeUpload(d) {this.loading = true;},// 上传成功uploadSuccess(d, f) {this.htmPath = d.data.htmPath;this.$refs.hhcHTML.innerHTML = d.data.hhcData;this.$nextTick(() => {let treeData = this.decodeHhcData(this.$refs.hhcHTML.querySelectorAll(`.hhcHTML>ul>li`))this.treeData = treeData;this.loading = false;this.$nextTick(() => {this.$refs.tree.setCurrentKey(this.current_node.id)this.src = this.current_node.filePath;});});},// 上传失败uploadError(d, f) { this.loading = false; },//点击节点nodeClick(data) { },//过滤节点filterNode(value, data) { },// 树节点修改current_change(d) { this.src = d.filePath; },}
};
</script>
<style lang="scss" scoped>
.chmDecode {width: 100%;display: flex;flex-wrap: nowrap;$treeWidth: 610px;$treeControlWidth: 100px;&>.sg-left {width: $treeWidth;flex-wrap: nowrap;white-space: nowrap;flex-shrink: 0;.tree-header {display: flex;justify-content: space-between;align-items: center;&>.sg-left {}&>.sg-right {}}.tree-body {height: calc(100vh - 200px);}}&>.sg-right {margin-left: 20px;flex-grow: 1;height: calc(100vh - 170px);.baseinfo {width: 100%;height: 100%;overflow-x: hidden;overflow-y: auto;position: relative;.form-body {height: calc(100% - 60px);overflow-y: auto;overflow-x: hidden;}.form-footer {position: absolute;height: 70px;box-sizing: border-box;padding-top: 20px;width: 100%;display: flex;justify-content: space-between;bottom: 0;&>* {width: 100%;flex-grow: 1;}}}}
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/86460.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【资料分享】全志科技T507-H工业核心板规格书

1 核心板简介 创龙科技SOM-TLT507是一款基于全志科技T507-H处理器设计的4核ARM Cortex-A53全国产工业核心板&#xff0c;主频高达1.416GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案&#xff0c;国产化率100%。 核心板通过邮票孔连接方式引出MIPI C…

聊聊51单片机

目录 1.介绍 2.发展 3.应用领域 4.发展前景 1.介绍 51单片机&#xff08;AT89C51&#xff09;是一种常见的8位微控制器&#xff0c;属于Intel MCS-51系列。它是一种低功耗、高性能的单片机&#xff0c;广泛应用于嵌入式系统中。 51单片机具有很多特点和功能&#xff0c;例如…

漫话拥塞控制:BBR 是个单流模型

概要(便于检索主题)&#xff1a;单流&#xff0c;多流收敛&#xff0c;probe buffer 挤压带宽&#xff0c;maxbw-filter wnd。 我曾经经常说 BBR 是个单流模型&#xff0c;而不是多流收敛模型&#xff0c;也做过不少评论&#xff0c;最近在复听 IETF 的大会&#xff0c;在 IET…

关于前端动态调试解密签名校验的分享

首先我们先来看一下&#xff0c;下面这张图是笔者近期测试遇到的问题&#xff0c;那就是程序每次生成请求都会生成signature的验签&#xff0c;该验签生成方式暂不可知&#xff0c;唯一知道的就是用一次就失效&#xff0c;这对测试的成本造成了很不好的影响&#xff0c;那么我们…

JAVA设计模式----原型设计模式

文章目录 一、简介二、实现方式三、原型模式的注意事项浅拷贝与深拷贝浅拷贝深拷贝一、简介 定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 类型:创建类模式 类图: 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Protot…

Golang函数以及函数和方法的区别

在接触到go之前&#xff0c;我认为函数和方法只是同一个东西的两个名字而已&#xff08;在我熟悉的c/c&#xff0c;python&#xff0c;java中没有明显的区别&#xff09;&#xff0c;但是在golang中者完全是两个不同的东西。官方的解释是&#xff0c;方法是包含了接收者的函数。…

【C++11】lambda表达式 | 包装器

文章目录 一.lambda表达式1.lambda表达式概念2.lambda表达式语法3.lambda表达式交换两个数4.lambda表达式底层原理 二.包装器1.function包装器①function包装器介绍②function包装器统一类型③function包装器的意义 2.bind包装器①bind包装器介绍②bind包装器绑定固定参数③bin…

构建Docker容器监控系统(Cadvisor +Prometheus+Grafana)

Cadvisor PrometheusGrafana 1.1、Cadvisor产品简介 Cadvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行Cadvisor用户可以轻松的获取到当前主机上容器的运行统计信息&#xff0c;并以图表的形式向用户展示。 1.2、安装docker-ce [rootloc…

30.基于XML的声明式事务

基于XML的声明式事务 主要是使用XML去代替注解&#xff0c;来实现起到代替注解的作用&#xff0c;实际使用频率很低 将BookServiceImpl.java中的Transactional注解删除&#xff0c;确保用户余额充足 spring-tx-xml.xml <?xml version"1.0" encoding"UTF-8…

uniapp 获取 view 的宽度、高度以及上下左右左边界位置

<view class"cont-box"></view> /* 获取节点信息的对象 */ getElementRect() {const query uni.createSelectorQuery().in(this);query.select(".cont-box").boundingClientRect(res > {console.log(res);console.log(res.height); // 10…

算法基础之插入排序

1、插入排序基本思想 插入排序的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常采用in-place排序&#xff08;即只需用到O(1)的额外空间的排序&#xff09;&a…

实现Jenkins自动发包配置

参考抖音&#xff1a;Java不良人 其中的视频演示代码 不推荐把jenkins端口一直开放&#xff0c;推荐使用时候放开&#xff08;版本不太新&#xff0c;避免漏洞攻击&#xff09; [rootVM-4-12-centos soft]# docker-compose -v Docker Compose version v2.19.1docker-compose.…

PHP8的跳转语句-PHP8知识详解

如果循环条件满足的时候&#xff0c;则程序会一直执行下去。如果需要强制跳出循环&#xff0c;则需要使用跳转语句来完成。PHP8的跳转语句包括break语句、continue语句和goto语句。 1、break语句 break语句的作用是完全终止循环&#xff0c;包括while、do…while、for、switch…

物联网的定义、原理、示例、未来

什么是物联网? 物联网 (IoT) 是指由嵌入传感器、软件和网络连接的物理设备、车辆、电器和其他物理对象组成的网络&#xff0c;允许它们收集和共享数据。这些设备(也称为“智能对象”)的范围可以从简单的“智能家居”设备(如智能恒温器)到可穿戴设备(如智能手表和支持RFID的服…

Docker源码阅读 - goland环境准备

docker 源码分为两部分 cli 和 moby&#xff08;docker&#xff09; tips: docker是从moby拷贝过去的&#xff1b;docker整体是一个C-S架构&#xff0c;cli客户端&#xff0c;docker服务端 docker-ce&#xff1a;https://github.com/docker/docker-ce cli&#xff1a;https://…

【深度学习】再谈向量化

前言 向量化是一种思想&#xff0c;不仅体现在可以将任意实体用向量来表示&#xff0c;更为突出的表现了人工智能的发展脉络。向量的演进过程其实都是人工智能向前发展的时代缩影。 1.为什么人工智能需要向量化 电脑如何理解一门语言&#xff1f;电脑的底层是二进制也就是0和1&…

Python教程(7)——一文弄懂Python字符串操作(上)|字符串查找|字符串分割|字符串拼接|字符串替换

Python字符串操作 字符串简介字符串查找使用 in 关键字使用 find() 方法使用 index() 方法使用正则表达式 字符串替换使用 replace() 方法使用正则表达式使用字符串模板 字符串分割字符串拼接使用加号 () 运算符使用字符串的格式化方法使用 f-string&#xff08;格式化字符串&a…

jackson库收发json格式数据和ajax发送json格式的数据

一、jackson库收发json格式数据 jackson库是maven仓库中用来实现组织json数据功能的库。 json格式  json格式一个组织数据的字符文本格式&#xff0c;它用键值对的方式存贮数据&#xff0c;json数据都是有一对对键值对组成的&#xff0c;键只能是字符串&#xff0c;用双引号包…

wireshark入门指北

文章目录 前言安装Linux上wireshark安装 使用捕获的时候添加过滤条件抓取浏览器https内容 附录抓取非浏览器的https流量 前言 本文长期维护&#xff0c;记录使用wireshark的使用过程。 虽然有官方文档-Wireshark User’s Guide&#xff0c;但是不想去慢慢读。应用层的图形软件…

【OpenCV常用函数:轮廓检测+外接矩形检测】cv2.findContours()+cv2.boundingRect()

文章目录 1、cv2.findContours()2、cv2.boundingRect() 1、cv2.findContours() 对具有黑色背景的二值图像寻找白色区域的轮廓&#xff0c;因此一般都会先经过cvtColor()灰度化和threshold()二值化后的图像作为输入。 cv2.findContous(image, mode, method[, contours[, hiera…