持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
ejs的基本使用
首先安装ejs:
npm install ejs
第一种用法
const ejs = require('ejs')
const html = '<div><%= user.name %></div>'
const options = {}
const data = {
user: {
name: 'pcj'
}
}
const data2 = {
user: {
name: 'pcj2'
}
}
// 这一步是编译,返回compile function, 用于解析html中的ejs模板,主要消耗性能就是这一步
const template = ejs.compile(html, options)
const template1 = template(data)
const template2 = template(data2)
console.log(template1, template2) // <div>pcj</div> <div>pcj2</div>
第二种用法
const templateRender = ejs.render(html, data, options)
console.log(templateRender) // <div>pcj</div>
这种就是把上面要执行两步的统一了,这种用法适用于渲染一次,如果需要渲染多次,使用第一种用法。
第三种用法
传入一个文件路径作为参数。注意,这里文件不一定是html后缀的文件,可以是任何文件,它都会被ejs解析成字符串。
// template.html
<div><%= user.name %></div>
// index.js
// promise的用法
const renderFile = ejs.renderFile(
path.resolve(__dirname, './template.html'),
data,
options
)
renderFile.then(file => {
console.log(file) // '<div>pcj</div>\n' 后面有个换行符
})
// 回调函数的用法
ejs.renderFile(
path.resolve(__dirname, './template.html'),
data,
options,
(err, file) => {
console.log(file) // '<div>pcj</div>\n' 后面有个换行符
}
)
ejs标签的含义
1. <% js脚本 %>
脚本标签,用于流程控制,无输出。
<% if (user) { %> // 因为是无输出,所以这一行不会在最后的结果中显示
<div><%= user.name -%></div>
<% } %>
显示:
<div>pcj</div>
2. <%-
输出非转义的数据到模板。
// index.html
<div><%- user.nickname -%></div>
const data = {
user: {
name: 'pcj',
nickname: '<h2>sam</h2>',
copyright: '2020'
}
}
ejs.renderFile(
path.resolve(__dirname, './index.html'),
data,
{},
(err, file) => {
console.log(file) // <div><h2>sam</h2></div>
}
)
可以看到,输出的结果中不会转义<h2>sam</h2>,原样输出。如果是<%= user.nickname -%>,那么结果是<div><h2>sam</h2></div>。
3. -%>
删除紧随其后的换行符。因为%>后面都会带有一个空行,为了不显示空行可以用-%>。
<%- user.nickname %>
<%- user.nickname -%>
可以看到空行没有了。
ejs常用的辅助功能
包含
<%- include('header', { header: 'header' }); -%>
<h1>
Title
</h1>
<p>
My page
</p>
<%- include('footer', { footer: 'footer' }); -%>
自定义分隔符
const ejs = require('ejs')
const users = ['geddy', 'neil', 'alex']
// 单个模板文件
ejs.render('<?= users.join(" | "); ?>', {users: users},
{delimiter: '?'});
// => 'geddy | neil | alex'
// 全局
ejs.delimiter = '$';
ejs.render('<$= users.join(" | "); $>', {users: users});
// => 'geddy | neil | alex'
自定义文件加载器
它可以在加载文件之前统一做一些操作,类似于钩子函数。
const ejs = require('ejs')
let myFileLoader = function (filePath) {
return 'myFileLoader: ' + fs.readFileSync(filePath);
};
ejs.fileLoader = myFileLoad;
重新定义了fileLoader逻辑后,那么所有读取的文件的时候都会先执行这个myFileLoader。
这里我们可以定义自己的逻辑,但是需要注意的时候在使用include引用文件的时候,也会执行这个方法。
ejs如何动态生成代码
我们在使用vue-cli创建vue项目时,public/index.html有如下代码:
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
这个就是ejs语法,它里面的值是用户定义的,所以一开始不会写死。
我们在开发脚手架项目时,也遇到一个问题:当用脚手架创建一个项目时,项目的名称和版本号需要动态的根据用户传入的值填入。
那如何完成呢?
首先修改package.json,把需要动态填入的值用ejs语法占位
{
"name": "<%= className %>",
"version": "<%= version %>",
}
最后根据用户的值进行渲染:
function ejsRender(options) {
const dir = process.cwd()
// 项目信息
const projectInfo = this.projectInfo
return new Promise((resolve, reject) => {
// 利用glob库把根目录下的所有文件筛选出来
glob(
'**',
{
cwd: dir,
// 忽略那些文件,比如node_modules
ignore: options.ignore,
// 不包含文件夹本身,我们只需要文件夹里面的内容
nodir: true
},
function (err, files) {
if (err) {
reject(err)
}
Promise.all(
files.map(file => {
const filePath = path.join(dir, file)
return new Promise((resolve1, reject1) => {
// 使用projectInfo的值填充ejs语法对应的值
ejs.renderFile(
filePath,
projectInfo,
{},
function (err, result) {
if (err) {
reject1(err)
} else {
// 现在拿到的是编译后的字符串,但是并没有帮我们写入到文件中
fse.writeFileSync(filePath, result)
resolve1(result)
}
}
)
})
})
)
.then(() => {
resolve()
})
.catch(err => {
reject(err)
})
}
)
})
}
至此,就完成了动态生成代码。