vue+element实现word⽂档(转成markdown了)带⽬录预览⽬录
背景
当前所做项⽬(vue-cli+element)有⼀个需求,做⼀个帮助⽂档,把word⽂档在页⾯中展⽰出来,要求能⽬录跳转。
思考过程
拿到这个需求,感觉这个难点在于⽬录跳转,word就算读取也全是字,⽆法识别哪⾥是⽬录,然后去提取⽬录和做定位。年前做项⽬时,因为项⽬中公共组件⽐较多,就想写个使⽤说明,专门去学过markdown的语法,在markdown中,1个到6个#号分别对应html标签中h1-h6,如果能把word转成markdown,不就可以根据#提取出⼀个⽬录了吗?所以要做的第⼀部就是把word转成markdown。
word转markdown
word转markdown的⾸先想的是有没在线⼯具,不⽤下载直接⽤还是⽐较舒服的。在⽹上倒是到了⼀个,但是说实话,效果不太好。之前玩游戏要⾃⼰做⼀个筛选页⾯,因为excel看着实在太费劲了,需要把ecexl表格转JSON数据,然后再处理成组件需要的格式,那会也是了好多在线的都不好⽤,最后⽤的是⼀个excel⾃带的插件,名字叫excel to json,还是⾮常好⽤的。对了,那个筛选页⾯我扔到码
云上了,已发布到⽹上,,上⾯那个筛选组件(我叫选项卡)是我⼿写的,有需要的可以联系我。所以最后考虑word有没⾃带的插件能把它转成⼀个md⽂件,最后还真到了⼀个插件 Writage 转md⽂件效果特别好,会把word⽂档⾥的图⽚提取到⼀个⽂件夹⾥,打开md⽂件,所有图⽚均能正常显⽰,15000+字的⽂档只有⼀处错误,⼿动改了。Writage 安装好之后,最上⾯就能看到。
安装好之后点⽂件,另存为,选择存放位置,选择格式,这⾥格式⼀定要选md。
然后你就可以在之前选择的位置到它的md格式版,同时还会有⼀个⽬录,⽤来存放⽂档中所有涉及到的图⽚,⾄于help.js是⼲什么的后⾯会解释。
到这⾥有两种选择,⼀种是md⽂件和media⽂件夹都放在服务器上,通过请求后端接⼝来展⽰,另⼀种是都放在前端,纯前端展⽰。这⾥先说第⼀种,都放在服务器上,通过接⼝请求md内容,然后再做展⽰。
⽤node的express框架搭建服务器
这⾥的代码啥意思就不说了,直接上代码
// express-static得⽤npm下载 npm i express-static --save
const express = require("express");
const expressStatic = require("express-static");
const fs = require('fs');
var server = express();
server.listen(5566);
console.log('服务器启动成功地址是: localhost:5566');
// 配置请求头
server.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "X-Requested-With")
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS")
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8")
next()
});
// 读取help.md⾥的内容并返回给前端
server.use("/getHelp", function (req, res) {
// 同步读取⽂件
let helpData = fs.readFileSync("./document/help.md");
res.send(helpData);
});
// 静态⽂件⽬录
server.use(expressStatic("./document"));
终端启动服务器,后⾯是⽬录结构
后端服务写好了,现在让我们来写前端代码,因为是要做demo,所以直接在app.vue⾥写,这⾥⽤的是axios(npm i axios -S)进⾏的请求。
mehtods⾥
getHelp() {
this.$axios
.get("localhost:5566/getHelp")
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
},
created⾥调⽤这个⽅法,我们就拿到了help点md⾥的内容。接下来考虑怎么把md格式的内容展⽰到页⾯上。
展⽰md⽂件到页⾯上
把md⽂件展⽰到页⾯上我们需要借助⼀个插件 marked.js 这个插件可以把md格式转换成html,我们就可以直接通过插值表达式或者v-html去渲染到页⾯上了,⽤法也很简单
repressing是什么意思npm i marked --save 然后再引⼊使⽤就可以了,我这⾥是在main⾥引⼊,然后绑定到全局了
import marked from "marked";
Vue.prototype.$marked = marked;
对getHelp⽅法进⾏改造
getHelp() {
this.$axios
.get("localhost:5566/getHelp")
.then((res) => {
// 原始md⽂件内容
this.helpData = res.data;
// 转换后的html
this.help = this.$marked(res.data);
})
.catch((err) => {
console.log(err);
});
},
然后我们之间在页⾯上去渲染help属性就好了。这⾥有个坑是图⽚的,因为⽤Writage转md后,所有图⽚的引⼊链接全是
media/943f402e73aecc2c08ffaeb88de41720.png ,需要⼿动全局替换⽬录地址,可以另外打开⼀个页⾯能成功看到图⽚,然后再做全局修改,这⾥我是这么做的。
接下来就是提取⽬录,然后⽬录跟页⾯内容⼀⼀对应起来。说实话,刚开始到这确实没有思路,直到看到了md转换成html后的内容,发现会⾃动给每个h标签添加⼀个id,其id值为标题内容,但是稍微有点坑,坑后⾯再说。这样的话,我们可以提取出来⼀个⽬录结构,然后通过锚点(创建⼀个a标签,href值为#标题名,点击这个a标签)跳转到对应的部分。这个⽬录我⽤的是element的树结构,所以先从原始md⽂件内容提取出来⼀个符合其树结构的数据格式的⽬录吧。
提取⽬录
我这⾥卡的⽐较久,可能是因为js基础不够扎实。因为md中,1个#到6个#是⼀⼀对应的,所以并且是按顺序的,所以我们⼀定可以通过代码来⽣成我们需要的⽬录。这⾥直接放代码(注释全写代码⾥了),你们如果有其他更好的⽅式可以分享出来,让我学习学习。
// 获取⽬录树
getTitle() {
// 提取出所有#和后⾯标题,放到⼀个数组中
let titleList = this.helpData.match(/#+.+/g);
// 把每个标题出现次数统计出来,必须保证标题唯⼀,全部使⽤1.1.1.1这是⼀个好办法
// 因为marked 会把#后⾯的内容添加为id ,如果标题重复,锚点跳转会只跳第⼀个
let count = duce((obj, name) => {
if (name in obj) {
obj[name]++;
} else {
obj[name] = 1;
}
return obj;
}, {});
// 删除只出现了⼀次的
for (let item in count) {
if (count[item] == 1) {
delete count[item];stata scalar 命令
}
}
// console.log(count);
// 能保证标题唯⼀的话,可以不⽤加这⾏代码
titleList = titleList.map((item, index) => (item = index + "$" + item)); // console.log(titleList);
// 最后⼀个各级别的标题
let nowLabel = [];
iferror与vlookup连用// ⽣成的标题
let title = [];
/
/ 当前对象
let cur;
for (let item of titleList) {
// 当前⽬录级别
let level = item.match(/#+/)[0].length;
// 其⽗级⽬录⽂字
let label = nowLabel[level - 2];
// 更新当前⽬录⽂字
nowLabel[level - 1] = item;
// console.log(item, nowLabel, "===============");
if (level == 1) {
cur = {
level: level,
label: item,
value: item,
children: [],
};
title.push(cur);
} else {
let obj = Obj(label, cur, level);
// console.log(obj);
// 把当前⽬录添加到其⽗级⽬录对象的children⾥
obj.children.push({
level: level,文件格式转换app
label: item,
value: item,
children: [],
});
}
}
// 这⾥是去除标题⾥的#和空格(如果上⾯没添加$和索引的话)
vbscript函数用法this.titleData = veTitleData(title);
},
/
/ 该⽅法根据传⼊参数,返回其⽗级⽬录对象
// 当前⽬录⽗级⽬录,当前⼀级⽬录对象,当前⽬录级别
getObj(label, cur, level) {
if (level - 1 > cur.level) {
for (let item of cur.children) {
let res = Obj(label, item, level);
if (res) {
return res;
js简单50行代码小游戏} else {
continue;
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论