网站搭建 / 计算机技术 · 2021年2月7日 0

express渲染markdown

前言

好久没写博客了,哈哈,主要这一年将要忙于考研,所以更新的文章会比较少的。

我想可以写一个基于nodejs的express的框架系统,来渲染markdown写的文章,来记录自己对数据结构这门课程的学习,今天来尝试地做一下。

 

 

 


express的基本环境与Jade模板引擎

老朋友,还记得express吗?不记得没关系,来根据官网一步一步走。

 

安装Express

首先,你一定是由nodejs才点开这篇文章的对吧,打开你的编译器,然后:

通过 npm init 命令为你的应用创建一个 package.json 文件。 欲了解 package.json 是如何起作用的,请参考 Specifics of npm’s package.json handling.

$ npm init

此命令将要求你输入几个参数,例如此应用的名称和版本。 你可以直接按“回车”键接受大部分默认设置即可,下面这个除外:

entry point: (index.js)

键入 app.js 或者你所希望的名称,这是当前应用的入口文件。如果你希望采用默认的 index.js 文件名,只需按“回车”键即可。

接下来在 myapp 目录下安装 Express 并将其保存到依赖列表中。如下:

$ npm install express --save

如果只是临时安装 Express,不想将它添加到依赖列表中,可执行如下命令:

$ npm install express --no-save

 

Express Generator

这里我就不全自己写了,这里利用一个Express生成器,默认来生成Jade模板

通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。

你可以通过 npx (包含在 Node.js 8.2.0 及更高版本中)命令来运行 Express 应用程序生成器。

$ npx express-generator

然后安装所有依赖包:

npm install

启动应用

npm start

然后访问本机3000端口,就可以看到效果了 !

生成器自动生成的目录结构:

  • app.js应用的初始化文件,包括引入应用程序的基础依赖项、设置视图即view的引擎目录以及模板、设置静态资源路径、配置通用的中间件、引入路由和一些错误处理中间件等。
  • package.json应用的配置文件,文件内包含程序的基础信息、启动脚本和依赖包等。
  • bin/www应用的启动文件,文件内包含引用要启动的应用、设置应用监听的端口和启动http服务等。
  • public/**应用的静态资源文件目录,该目录下的文件资源不需要经过文件映射就可以直接访问。
  • routes/**应用的路由文件,这些路由文件中设置的接口最终会以指定的HTTP请求方式暴露给用户,并在用户请求之后将结果返回。
  • views应用的视图文件,在app.js中设置好视图引擎和模板之后,该目录即为应用视图的根目录,然后路由文件就会根据app.js中的设置加载并渲染该目录下的视图文件。

 

Jade的基本语法

Express生成器默认生成的是Jade模板,jade是超高性能的node JavaScript模板引擎,有着非常强大的API和大量杰出的特性。它主要针对node的服务端。

下面的内容主要搬自这个网页——https://blog.csdn.net/no10086/article/details/89646189

随着前端业务的不断发展,页面交互逻辑的不断提高,让数据和界面实现分离渐渐被提了出来。JavaScript的MVC思想也流行了起来,在这种背景下,基于node.js的模板引擎也随之出现。

什么是模板引擎?

它用于解析动态数据和静态页面所生成的视图文件,将原本静态的数据变为动态,快速地实现页面交互;
目前使用较广的模板引擎有以下几种:Jade / Pug、EJS、Handlebars。

jade模板引擎

jade模板引擎相较于原来的html会显得更加简洁,它将标签原本的”<>”符号去掉,用括号代替,层级使用tab缩进来分,并且也支持js语法;

下面来简单记录一下Jade的基本语法:

1、jade对很多html操作进行了简化,如下:
html
	head
		style
	body
		div(class="content")
			h1 正文

了解过html语句的,从结构上一定会发现,它将原本的双标签省略了,尖括号也不见了,而层级的划分则由缩进实现,默认的,jade会把几乎所有缩进后的字母变为标签(行内元素)。以下代码会变为:

<html>
  <head>
    <style></style>
  </head>
  <body>
    <div class="content">
      <h1>正文</h1>
    </div>
  </body>
</html>

也将用div(class=”content”)代表,简化了代码的书写;

2、“|”符号的作用

有时想让标签成为文字,那么“|”成为了绝好的工具:

div(class="content",id="content")
			| center

可以看到,他将center作为文字原封不动的写入了html中,而不是作为一个标签渲染。
用它来转换js语句:

script
		| var cli = document.getElementById("content");
		| cli.onclick=function(){
		|	alert("aaa");
		| }

他将会变为:

<script>
    var cli = document.getElementById("content");
    cli.onclick=function(){
        alert("aaa");
    }
</script>
3、识别js语句:

可以通过 script. 来识别js语法:

script.
		var cli = document.getElementById("content");
		cli.onclick=function(){
			alert("aaa");
		}

他也会变为:

<script>
    var cli = document.getElementById("content");
    cli.onclick=function(){
        alert("aaa");
    }
</script>

可以看到,相比于用 | 使用script. 更加方便快捷。

4、引入其他js文件:

想在jade的js标签中引入其他js文件?没错,它也支持。前提请确保他们在同一文件夹下:

script
		include click.js
    link(rel='stylesheet',type='text/css',href='../css/main.css')
    script(src='../js/manipu.js')

 

5、表达式

“-”允许直接写js语法,在变量调用时,通过 #{a+b} 或 div=a+b 进行:

html
	head
		
	body
		-var a=10
		-var b=20
		div a+b为:#{a+b}
		div=a+b

会得到:

<html>
  <head></head>
  <body>
    <div>a+b为:30</div>
    <div>30</div>
  </body>
</html>
6、for循环:

“-“也可以用于循环语句的使用

html
	head
	
	body
		-var arr=0;
		-for(var i=5;i>arr;i--)
			div=i
		div the number = #{i}

得到:

<html>
  <head></head>
  <body>
    <div>5</div>
    <div>4</div>
    <div>3</div>
    <div>2</div>
    <div>1</div>
    <div>the number = 0</div>
  </body>
</html>

除了-以外,还可以使用=或者!=来直接嵌入js代码:

使用 = ,代码中的特殊字符将会被转义:

p = 'This code is <escaped>!'
<p>This code is <escaped>!</p>

第三种方法是使用 != ,代码中的特殊字符不会被转义:

p = 'This code is <escaped>!'
<p>This code is <escaped>!</p>

 

7、case ,when

类似于switch case语句:

html
	head
	
	body
		- var test = "汉子"
		-var none = "无"
		div The word is #{test}
		case test
			when "a": div the when is a
			when "b": div the second is b
			when "汉子": div the Third is 汉子
			default: The words is #{none}
<html>
  <head></head>
  <body>
    <div>The word is 汉子。</div>
    <div>the Third is 汉子</div>
  </body>
</html>

类似于switch case,只执行when中与case对应的代码块,在匹配后面用 : 来作为要执行的代码,后面跟上标签和对应语句

8、if else条件判断
html
	head
	
	body
		-for(var i=12;i>0;i--)
			-if(i%2==0)
				div(style={background:'#eee',width:'100%',height:'20px',color: '#333'})	偶数
			-else
				div(style={background:'#333',width:'100%',height:'20px',color: '#eee'})	奇数

得到:

<html>
  <head></head>
  <body>
    <div style="background:#eee;width:100%;height:20px;color:#333">     偶数</div>
    <div style="background:#333;width:100%;height:20px;color:#eee">     奇数</div>
    <div style="background:#eee;width:100%;height:20px;color:#333">     偶数</div>
    <div style="background:#333;width:100%;height:20px;color:#eee">     奇数</div>
    <div style="background:#eee;width:100%;height:20px;color:#333">     偶数</div>
    <div style="background:#333;width:100%;height:20px;color:#eee">     奇数</div>
    <div style="background:#eee;width:100%;height:20px;color:#333">     偶数</div>
    <div style="background:#333;width:100%;height:20px;color:#eee">     奇数</div>
    <div style="background:#eee;width:100%;height:20px;color:#333">     偶数</div>
    <div style="background:#333;width:100%;height:20px;color:#eee">     奇数</div>
    <div style="background:#eee;width:100%;height:20px;color:#333">     偶数</div>
    <div style="background:#333;width:100%;height:20px;color:#eee">     奇数</div>
  </body>
</html>
9、style的写法:

在对style样式进行修改时,与script相同,也可使用 . 对其进行编辑,之后对不同的标签在其后面加{},大括号里写css语句1,并使用 ; 隔开

html
	head
		meta(charset="utf-8")
		title jade测试页面
		style.
			body{margin:0;padding:0}
			div
			{width: 100px;height: 100px;background: #ccc;text-align: center;line-height: 100px;margin: 10px auto}
			div.last{clear:left}
	body
		-var a=0;
		while a<12
			if a%2==0 && a!=0
				div.last=a++
			else
				div=a++

得到:

<html>
  <head>
    <meta charset="utf-8"/>
    <title>jade测试页面</title>
    <style>
      body{margin:0;padding:0}
      div
      {width: 100px;height: 100px;background: #ccc;text-align: center;line-height: 100px;margin: 10px auto}
      div.last{clear:left}
    </style>
  </head>
  <body>
    <div>0</div>
    <div>1</div>
    <div class="last">2</div>
    <div>3</div>
    <div class="last">4</div>
    <div>5</div>
    <div class="last">6</div>
    <div>7</div>
    <div class="last">8</div>
    <div>9</div>
    <div class="last">10</div>
    <div>11</div>
  </body>
</html>
10、Mixin

Mixin的作用是对模块的复用,当重复代码有不同内容时,起作用就来了:

- var num = 0;
mixin node
    div The number in mixin node is #{num++}
+node()
+node()
+node()
div At last, the number in mixin node is #{num++}

得到:

<div>The number in mixin node is 0</div>
<div>The number in mixin node is 1</div>
<div>The number in mixin node is 2</div>
<div>At last, the number in mixin node is 3</div>
11、each可以对数组进行遍历

Jade 使用 each 对数组和对象遍历,用法与 JavaScript 大同小异。

// 遍历数组
ul
  each val, index in ['zero', 'one', 'two']
    li= index + ': ' + val


// 遍历对象
ul  
  each val, index in {1:'one',2:'two',3:'three'}
    li= index + ': ' + val

生成的 HTML:

<!-- 遍历数组-->
<ul>
  <li>0: zero</li>
  <li>1: one</li>
  <li>2: two</li>
</ul>
<!-- 遍历对象-->
<ul>
  <li>1: one</li>
  <li>2: two</li>
  <li>3: three</li>
</ul>

 

12、继承

Jade 中使用 extends 来继承代码片段,与 include 本本分分地引用代码段不同,继承可以修改代码片段。
首先,在 layout 页面使用 block 标识符,设置一个可修改的代码片段,紧跟 block 标识符之后的是该代码片段的名字:

//- layout.jade
doctype html
html
  head
    block title
      title Default title
  body
    block content

然后,在 index 页面继承 layout ,并可以根据代码片段的名字修改相关代码:

//- index.jade
extends ./layout.jade


block title
  title Article Title


block content
  h1 My Article
<!doctype html>
<html>
  <head>
    <title>Article Title</title>
  </head>
  <body>
    <h1>My Article</h1>
  </body>
</html>

上述这种继承方式,会抹除原来代码片段的部分,如果想要追加代码片段,可以使用 append 和 prepend 指令。 append 用于在原有代码片段之后追加, prepend 用于在原有代码片段之前追加。一个初始页面:

//- layout.jade
html
  head
    title Layout
  body
    block content
      p Hello

使用 append :

extend layout


block append content
    p World

生成的 HTML:

<html>
  <head>
    <script src="/vendor/jquery.js"></script>
    <script src="/vendor/caustic.js"></script>
  </head>
  <body>
    <p>Hello</p>
    <p>World</p>
  </body>
</html>

 

 

以上就是jade的基本语法了。

 


express渲染markdown以及文件读取

我的基本思路是这样的,将笔记写成markdown的形式,然后统一放在一个目录下,然后由node来读取该目录下的文件,再渲染到web页面上。

渲染markdown

先来尝试用express渲染markdown

我这里使用的是一个npm包,叫做marked ,这里有它的文档

首先使用命令来简单安装这个包(我这里用g来全局安装)

npm install -g marked

然后只要导入包再使用即可,运行Jade框架,然后在index.js中修改内容:

var express = require('express');
var router = express.Router();
var marked = require("marked");

/* GET home page. */
router.get('/', function(req, res, next) {
  var html = marked('# Marked in Node.js\n\nRendered by **marked**.');
  res.send(html);
  //res.render('index', { title: 'Express' });
});

module.exports = router;

这样就成功地将markdown的字符串渲染到了网页上

结合Jade的话:

var express = require('express');
var router = express.Router();
var marked = require("marked");

/* GET home page. */
router.get('/', function(req, res, next) {
  var note = '# Marked in Node.js\n\nRendered by **marked**.';
  //渲染jade视图文件,传入相应参数
  res.render('template', { note:note,
    marked: marked });
});

module.exports = router;

对应的template.jade的内容是:

extends layout

block content
  //- ‘!=’意为着后面的内容作为js代码执行,且特殊字符不转义
  div!= marked(note)

这样就实现了markdown的渲染。

文件流

下面是node.js的文件流问题,最后要自动遍历某目录下的所有markdown文件

先尝试得到一个目录下的所有文件,这里你会需要nodejs的文档

我这里在public目录下创建一个docs目录,然后新建了一个test.md

检索代码index.js如下:

var express = require('express');
var router = express.Router();
var marked = require("marked");

var path = require('path');
var fs = require('fs');

//得到绝对路径
var dirTarget=path.resolve('./public/docs');

//读取dirTarget下的markdown文件,将文件名保存在数组下
function readMarkdownLst(dir){
  var markdownList=[];
  //同步读目录
  var files = fs.readdirSync(dir);
  files.forEach((item, index) => {
      var fullPath = path.join(dir, item);
      //同步得到其状态
      const stat = fs.statSync(fullPath);
      //若不是目录则加入数组
      if (!stat.isDirectory()) {      
        markdownList.push(item);   
      }  
    });
  return markdownList;
}


/* GET home page. */
router.get('/', function(req, res, next) {
  // var note = '# Marked in Node.js\n\nRendered by **marked**.';
  // //渲染jade视图文件,传入相应参数
  // res.render('template', { note:note,
  //   marked: marked });
  var content="";
  readMarkdownLst(dirTarget).forEach(function(e){
    content+=e;
  })
  res.send(content);
});

module.exports = router;

不出意外,运行成功后你的主机面就是你docs目录下的文件名。

下面,将检索到的文件名制成的数组利用jade循环制作成无序列表超链接,链接跳转到另一个js文件——content.js

修改后的index.js中的路由处理:

router.get('/', function(req, res, next) {
  //将readMarkdownLst方法读取的文件数组返回出来,传给jade模板
  res.render('index',{titleList:readMarkdownLst(dirTarget)});
});

在index.jade中:

extends layout

block content
  ul 
    -for(var i=1;i<=titleList.length;i++) 
      li
        a(href="content")= titleList[i-1]

这里要再写一个content.js:

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('恭喜!');
});

module.exports = router;

而在程序入口文件app.js中要做相应的添加:

var contentRouter = require('./routes/content');
app.use('/content', contentRouter);

好了,下面可以多做几个docs下的文件,来看看动态效果是否成功:

文件流非常成功,那么后面的内容就是我们要将对应的选中的markdown文章的内容渲染在content这个页面下面。

 

实现选中文章顺利阅读功能

我们刚才实现了根据目录下的md文件自动生成无序列表超链接,那么用户选择连接时,我们要将选择的是哪一个文章发送给我们的content.js,故在index.jade中,超链接里写好get请求:

extends layout

block content
  ul 
    -for(var i=1;i<=titleList.length;i++) 
      li
        //- 超链接中用get方式请求,将文章名作为参数
        a(href="content/?"+"article="+titleList[i-1])= titleList[i-1]

对应的content.js文件里进行接收参数,同时进行markdown文件的读写,还有markdown文件渲染到页面

var express = require('express');
var router = express.Router();
var marked = require("marked");

var path = require('path');
var fs = require('fs');

//得到绝对路径
var dirTarget=path.resolve('./public/docs');

//读取dirTarget下的markdown文件内容
function readMarkdown(dir,articleName,encode){
  var articleContent;
  //同步读目录
  var dir=dir+"/"+articleName;
  articleContent=fs.readFileSync(dir,encode);

  return articleContent;
}

router.get('/', function(req, res, next) {
  //得到前端发来的选中文章名
  var article=req.query.article;
  var articleContent=readMarkdown(dirTarget,article,"utf-8");
  //渲染jade视图文件,传入相应参数 
  res.render('content', { title:"正在浏览"+article,note:articleContent, 
    marked: marked });
});

module.exports = router;

content.jade的内容如下:

extends layout

block content
    //- ‘!=’意为着后面的内容作为js代码执行,且特殊字符不转义 
    div!= marked(note)

这样,我们就可以成功将docs目录下的md文件渲染到html页面上了!

 


基本的简单功能就实现了,后面就是按照自己的需求来增添一些样式和功能了!

大功告成!

 

 

 

 

 

 

 

商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢

 

 

是的,我就是计算机界的枭雄!