开发一个页面组件,原本想着本身纯手工撸,通过大大的指导发现有个叫handleBars的模版工具,能够减小不少开发工做量,因而试了一下,这东西有点老,也有坑,但整体用下来比本身纯手写样式仍是香不少。php
Handlebars是一种简单的模版语言,使用模版和输入对象来生成HTML或者其余文本格式,是个带有嵌入式的handlebars表达式,就相似{{表达式}},在执行模版时,这些表达式就会被输入对象中的值所替换html
1.使用Handlebars最快的方式就是cdnnode
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script> <script> // compile the template var template = Handlebars.compile("Handlebars <b>{{doesWhat}}</b>"); // execute the compiled template and print the output to the console console.log(template({ doesWhat: "rocks!" })); </script>
2.使用npm安装webpack
(1)npm install handlebarsweb
使用webpack进行打包,还须要额外安装包(handlebars-loader 和 handlebars-webpack-plugin)进行配置npm
const HtmlWebpackPlugin = require("html-webpack-plugin"); const HandlebarsWebpackPlugin = require("handlebars-webpack-plugin"); const path = require("path"); module.exports = { mode: "development", entry: "./src/index.ts", output: { filename: "handlebars-demo.js", libraryTarget: "umd", globalObject: "this", library: "Demo", libraryExport: "default", }, module: { rules: [ { enforce: "pre", test: /\.jsx?$/, exclude: /node_modules/, loader: "eslint-loader", options: { fix: true, formatter: "eslint-friendly-formatter", }, }, { test: /\.hbs$/, loader: "handlebars-loader", exclude: /node_modules/, options: { partialDirs: [ path.join(__dirname, "../src/generatedpartial", "partials"), // partials的路径,注册全部该路径下的代码模块 ], helperDirs: [ path.join(__dirname, "../src/generatedpartial", "helper"),// helper的路径,注册全部该路径下的代码模块 ], }, }, ], }, resolve: { extensions: [".ts", ".tsx", ".js"], alias: { "@": path.resolve(__dirname, "../src/"), }, }, plugins: [ new HtmlWebpackPlugin({ template: "src/index.html", // the output file name filename: "index.html", // inject: "head", }), new HandlebarsWebpackPlugin({ htmlWebpackPlugin: { enabled: true, // register all partials from html-webpack-plugin, defaults to `false` prefix: "html", // where to look for htmlWebpackPlugin output. default is "html" HtmlWebpackPlugin, // optionally: pass in HtmlWebpackPlugin if it cannot be resolved }, entry: path.join(process.cwd(), "src", "generatedpartial", "*.hbs"), // 会将generatedpartial目录下的hbs文件输出为html output: path.join(process.cwd(), "dist", "[name].html"), partials: [path.join(process.cwd(), "src", "partials", "*", "*.hbs")], // 将全部的partials进行转换 }), ], };
hbs主要包含helper和partials两大模块,具体模块用法在接下来详细讲解。数组
(2)操做模版时在对应的js文件中将hbs文件require引入就好app
const headerTpl = require("./generatedpartial/head.hbs"); const data={ title:[{ label: "demo1", type: "", key: "demo1", }], srcAddr:'', destAddr:'', orderStatus:'', demo1:'这是一个demo' }; const basicMsgWrap = document.createElement("div"); basicMsgWrap.classList.add("basic-msg"); basicMsgWrap.innerHTML = headerTpl(data); // data对应的是须要传入的对象 // data里面须要包含head.hbs中的字段
/* head.hbs */ <div class="basic-msg__main"> {{#each title}} {{>msg parameter=(lookup .. key)}} {{/each}} <div class="msg__value"> <span id="src-short">{{srcAddr}}</span> — <span id="dest-short"> {{destAddr}} </span> </div> </div> <div class="basic-msg__status"> <span class="basic-msg__status__text"> {{orderStatus}} </span> </div>
hbs文件看起来和html文件相似,可是里面多了一些特有的语法,具体的语法接下来详细讲解。less
(1)partials,代码片断函数
代码片断顾名思义就是一个某段代码,在编写模版的时候会出现一些可复用的模块,此时就须要使用块助手,实现编写一次模块,可在多个地方重复使用的目的。
使用代码片断用{{> 代码片断名称 param=data}}
,param用于传参
// 注册代码片断 Handlebars.registerPartial('myPartial', '{{prefix}}'); // 使用注册的代码片断 {{> myPartial }}
head.hbs中的msg就是已写好的一个代码片断,因为我项目用webpack打包,注册代码片断的过程webpack已经帮忙作了,在代码中就不须要手动进行registerPartial
(2)helper,块助手
块助手本质上就是一些辅助函数,经过块助手代码来调用模板上下文,以此实如今模板中处理渲染逻辑,使模板更加通用化。
// 注册块助手代码 Handlebars.registerHelper("noop", function(options) { return options.fn(this); }); // 自定义的块助手代码 equal.js // this对应的就是上下文参数,option是默认的参数,option包含一个option.fn函数 // 这个函数的意义是v1等于v2时才返回上下文,不然不返回任何值 module.exports = function (v1, v2,option) { if (v1 === v2) { return option.fn(this); } }; // 使用equal // 次数若是传入的title等于操做历史时才会走入equal中间的逻辑 {{#equal title '操做历史'}} {{>history data=(lookup ../this content)}} {{/equal}}
和代码片断同样,用webpack打包以后咱们不须要用registerHelper进行注册,而是直接exports对应函数就好(目前是一个函数一个js模块)
使用块助手用{{#块助手名称 参数1 参数2 ...}}代码块{{/块助手名称}}
,块助手代码必须闭环,不然会报错,知足逻辑的代码块将被渲染
(3)内置助手代码
Handlebars定义了几个内置的助手代码,方便使用,接下来简单介绍一下
根据条件渲染代码块,若是参数返回false,undefined,null,"",0或者[]时,该代码块将不会被渲染
{{#if 0 === 1}}<div>我永远不会被渲染</div>{{/if}}
和#if相反,当表达式返回false时渲染代码块{{#unless 0 === 1}}<div>我会被渲染</div>{{/unless}}
遍历列表,能够使用this来引用被迭代的元素{{#each title}}{{this.key}}{{/each}}
假设title是个对象数组,此时渲染出来的就是每一个对象中key的值,若title是head.hbs中的title,此时this.key === 'demo1'
在each中还提供了一个else,该代码块只会在列表为空时显示
{{#each paragraphs}}<p>{{this}}</p>{{else}}<p class="empty">No content</p> {{/each}}
当遍历 each
中的项目时,你能够选择经过 {{@index}}
引用当前循环的索引。
对于对象迭代,能够使用 {{@key}}
引用当前的键名,经过 @first
和 @last
变量记录迭代的第一项和最后一项,要访问父级的索引,能够使用 {{@../index}}
更改上下文表达式,就是说#with后面的参数就能够作为#with内容中的this,这个对于多重嵌套的模板十分好用,嵌套层次很深的时候,就再也不须要a.b.c.d
这种形式进行数据引用
`{{#with city as | city |}}
{{#with city.location as | loc |}}
{{city.name}}: {{loc.north}} {{loc.east}}
{{/with}}
{{/with}}`
其中as用于给对应的参数取别名,取别名以后就能够使用别名进行引用了
lookup
lookup容许使用变量进行动态的参数解析,它的使用方法跟上面的#不同,是直接使用,相似于函数,动态的参数解析在进行数组索引时十分有用
const data={ title:[{ label: "demo1", type: "", key: "demo1", },{ label: "demo2", type: "", key: "demo2", }], srcAddr:'', destAddr:'', orderStatus:'', demo1:'这是一个demo', demo2:'this is demo' }; // hbs代码部分 {{#each title}} {{>msg parameter=(lookup .. key)}} {{/each}}
此时parameter传回的是父级对应的key值的字段对应的值,也就是'这是一个demo'和'this is demo'。
容许在执行模板时记录上下文的状态
(4)补充语法
{{{里面的内容原样输出}}}
模板语言分为预设处理模块和模板编辑模块两个部分,预设处理模块是预设一些模板的处理逻辑,当系统遇到这些逻辑时,就会进行相应的处理,好比在处理handlebars时,遇到{{}}
时,系统就会将双括号内的代码识别为特殊逻辑,进行对应的处理。
一个简单的demo,实现字符串的替换(ps:正则真的很重要)
const mapping = (data)=>({ title:'test', key:'testKey', }[data]) const demo = text =>{ if(text){ return text.replace(/\{\{(.*?)\}\}/g, (match, key) => mapping(key)} } demo('{{title}}&{{key}}') // test&testKey