ホームページ >ウェブフロントエンド >htmlチュートリアル >ハンドルバー プレイヤーズ ガイド_html/css_WEB-ITnose
ヒント: テキスト内の「{ {」、「} }」は、実際に使用する場合は、間にスペースを入れずに二重中括弧を使用します。
私がこの記事を書いたのは、テンプレート ページングの特定の機能を実装するために (この問題と解決策は最後に記載されています)、長い間テストした後、公式 Web サイトを何度も読むのに多くの時間を費やしたためです。 , それでも成功しませんでした。その後、勢いよく勉強を続け、ついに問題を解決しました。この時点で、ハンドルバーのことは大体理解できたので、整理するために記事を書いてみました。
フロントエンド テンプレート エンジンについては、式を使って説明します
模板引擎 模板 + 数据 ========> html页面
テンプレート エンジンは、対応するテンプレートにデータを入力し、静的ファイルを生成します。 htmlページ。これはブラウザ側 (Angular の命令で使用されるテンプレートなど) またはサーバー側で実行できますが、通常はサーバー側で使用されます。その機能の 1 つは再利用のために公開ページを抽象化することであるため、サーバー側でデータが埋め込まれている場合、ページにデータをバックフィルするための Ajax リクエストが削減され、ブラウザー側での全体的なページのレンダリング速度が向上します。
私が接したテンプレート エンジンはあまり多くありませんが、最も古いものは本質的にテンプレート エンジンである jsp であり、次に少し強力な freemarker です。そのうちのは Java 言語ファミリーに属します。私は js 言語ファミリーの jade と ejs を使用した経験がありますが、Jade は Python に似た文法規則と解析効率の低さから、初期にはテンプレート エンジンとしてのみ使用していました。その後、機能と記述方法の点で jsp に近い強力な ejs に置き換えられました。最新の Express4 がリリースされるまで、デフォルトは、ロジックが弱い比較的単純なテンプレート エンジンであるハンドルバーに変更されました。
私は次の理由でハンドルバーを使用します:
実行環境: Express4、hbs4
Express や hbs に慣れていない場合は、まずここを読んでください
データ:
{ title: 'Express', obj:{ version: 'v4.3', category: 'node', "date~": '2016' }}
テンプレート:れーれー
HTML ページ:
<p>{ {title} }</p><p>{ {obj.version} }</p><p>{ {obj/category} }</p><p>{ {obj.date~} }</p>ハンドルバー内の変数は (Angular と同様に) 二重中括弧で表されます。実際、これは非常に使いやすいものです。キーボードの位置を考えてから、これらの文字を押すことの難しさを考えてください。変数の属性値にアクセスしたい場合は、json形式と同様に「.」を使用することもできますし、「/」を使用することもできます。
変数名には次の文字を含めることはできません。含まれている場合、上記の「」に示すように、解析されません。
Expressv4.3nodeただし、これらの特殊文字を翻訳するには
" 、 ' 、 [] を使用できます。
このルールは"&&"、"||"、"!" を意味します。この種の論理的判断は適切ではありません。式に表示されます! (この記事を見ると、ロジック テンプレート エンジンが弱すぎるように感じます。笑、もちろん別の解決策があります)
中級者: ヘルパー
空格 ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~
if-else
コード ブロックに似ていますが、やはり、上記の特殊文字のため、if 条件には論理式を含めることはできません。変数または値のみです。
そうでない場合
または、上記の文字のせいで、ハンドルバーは論理否定 (「!」) をサポートしていないため、if
{ {#if author} } <h1>{ {firstName} } { {lastName} }</h1>{ {else} } <h1>Unknown Author</h1>{ {/if} }の反対の別のヘルパーがあります。上記の段落のコードは次のとおりです。
rrree
each
each が for ループと同等であることは誰もが知っていますが、注意すべき点がいくつかあります。
{ {#each passage} } { {#each paragraphs} } { {@../index} }:{ {@index} }:{ {this} }</p> { {else} } <p class="empty">No content</p> { {/each} }{ {/each} }
{ {#each array as |value, key|} } { {#each child as |childValue, childKey|} } { {key} } - { {childKey} }. { {childValue} } { {/each} }{ {/each} }
同时也可以用来遍历对象,这时@key表示属性名,this表示对应的值
{ {#each object} } { {@key} }: { {this} }{ {/each} }
类似js中的with,可以配合分页使用,限定作用域。
{ {#with author as |myAuthor|} } <h2>By { {myAuthor.firstName} } { {myAuthor.lastName} }</h2>{ {else} } <p class="empty">No content</p>{ {/with} }
这个用于以下这种并列数组的情况,可以按照索引来找兄弟变量对应的值。理解起来有些困难,直接看代码
{ groups: [ {id: 1, title: "group1"}, {id: 2, title: "group2"}, ], users: [ {id:1, login: "user1", groupId: 1}, {id:2, login: "user2", groupId: 2}, {id:3, login: "user3", groupId: 1} ], infos: [ 'a','b','c' ]}
<table> { {#each users} } <tr data-id="{ {id} }"> <td>{ {login} }</td> <td data-id="{ {groupId} }">{ {lookup ../infos @index} }</td> </tr> { {/each} }</table>
user1 auser2 buser3 c
这里在users数组中按照索引值引用infos数组中对应的值,如果想引用groups中的groupId呢?很简单,用with。
<table> { {#each users} } <tr data-id="{ {id} }"> <td>{ {login} }</td> <td data-id="{ {groupId} }">{ {#with (lookup ../groups @index)} }{ {title} }{ {/with} }</td> </tr> { {/each} }</table>
内置的helper不够强大,所以通常需要写js代码自定义helper,先看一个简单的单行helper。
传值
数值、字符串、布尔值这种常规数据可以直接传入,同时也可以传递JSON对象(但只能传一个),以key=value这种形式写在后面,最后就可以通过参数的hash属性来访问了。
模板
{ {agree_button "My Text" class="my-class" visible=true counter=4} }
代码
hbs.registerHelper('agree_button', function() { console.log(arguments[0]);//==>"My Text" console.log(arguments[1].hash);//==>{class:"my-class",visible:true,conter:4}}
传变量
传变量时可以用this指针来指代它访问属性,通过逻辑判断后可以返回一段html代码,不过太建议这样做。考虑以后的维护性,这种html代码和js代码混合起来的维护性是比较差的,如果要抽象层组件还是使用分页比较好。
模板:
{ {agree_button person} }
注册helper:
hbs.registerHelper('agree_button', function(p) { console.log(p===this);//==> true var blog = hbs.handlebars.escapeExpression(this.person.blog), name = hbs.handlebars.escapeExpression(this.person.name); return new hbs.handlebars.SafeString( "<a href='"+blog+"'>"+ name + "</button>" );});
数据:
var context = { person:{name: "亚里士朱德", blog: "https://yalishizhude.github.io"} };};
html页面:
<a href="https://yalishizhude.github.io">亚里士朱德</a>
当内容只想做字符串解析的时候可以用 escapeExpression 和 SafetString 函数。
块级helper获取参数的方式跟之前差不多,只是最后多了一个参数,这个参数有两个函数 fn 和 revers 可以和 else 搭配使用。后面将会讲解。
模板:
{ {#list nav} } <a href="{ {url} }">{ {title} }</a>{ {/list} }
注册helper:
Handlebars.registerHelper('list', function(context, options) { var ret = "<ul>"; for(var i=0, j=context.length; i<j; i++) { ret = ret + "<li>" + options.fn(context[i]) + "</li>"; } return ret + "</ul>";});
数据:
{ nav: [ { url: "https://yalishihzude.github.io", title: "blog" }, { url: "https://www.github.com/yalishizhude", title: "github" }, ]}
html页面:
<ul> <li> <a href="https://yalishizhude.github.io">blog</a> </li> <li> <a href="https://www.github.com/yalishizhude">github</a> </li></ul>
each的index变量比较常用,但是它是从0开始的,往往不符合业务中的需求,这里写个helper来扩展一下。
注册helper:
hbs.registerHelper('eval', function(str, options){ var reg = /\{\{.*?\}\}/g; var result = false; var variables = str.match(reg); var context = this; //如果是each if(options.data){ context.first = context.first||options.data.first; context.last = context.last||options.data.last; context.index = context.index||options.data.index; context.key = context.key||options.data.key; } _.each(variables, function(v){ var key = v.replace(/{ {|} }/g,""); var value = typeof context[key]==="string"?('"'+context[key]+'"'):context[key]; str = str.replace(v, value); }); try{ result = eval(str); return new hbs.handlebars.SafeString(result); }catch(e){ return new hbs.handlebars.SafeString(''); console.log(str,'--Handlerbars Helper "eval" deal with wrong expression!'); } });
模板:
{ {#each list} }{ {eval '{ {index} }+1'} }{ {/each} }
上面说到if不支持复杂的表达式,如果是“&&”操作还可以用子表达式来实现,更加复杂的就不好办了,这里我写了一个helper来实现。
注册helper:
hbs.registerHelper('ex', function(str, options) { var reg = /\{\{.*?\}\}/g; var result = false; var variables = str.match(reg); var context = this; _.each(variables, function(v){ var key = v.replace(/{ {|} }/g,""); var value = typeof context[key]==="string"?('"'+context[key]+'"'):context[key]; str = str.replace(v, value); }); try{ result = eval(str); if (result) { return options.fn(this); } else { return options.inverse(this); } }catch(e){ console.log(str,'--Handlerbars Helper "ex" deal with wrong expression!'); return options.inverse(this); } });
模板:
{ {#ex "{ {state} }==='submiting'"} }<i class="icon cross-danger">1</i>{ {else} }<i class="icon cross-success">2</i>{ {/ex} }
先将整个逻辑表达式作为一个字符串传入,然后替换其中的变量值,最后用eval函数来解析表达式,同时增加异常处理。
比较推崇使用分页来实现组件化。分页跟helper一样需要先注册。在hbs模块中可以批量注册,比较简单。
hbs.registerPartials(__dirname + '/views/partials');
用“>”来引用模板,这种情况一般用来处理页头页尾这种简单的分页。后面可以传入参数。
{ {> myPartial param} }当使用块级表达式时,我们通常添加“#”,而分页是“>”,所以块级分页使用“#>”,这里表示如果layout分页不存在则显示块内的内容My Content。
{ {#> layout } } My Content{ {/layout} }
当然也可以用表达式来代替分页名称
{ {> (whichPartial) } }
当分页中一部分代码是固定的,另一部分是变化的时候,可以在分页中添加“@partial-block”,这时当引用这个分页时,在内部编写代码将会填充到这个位置。
partial.hbs:
亚里士朱德{ {> @partial-block } }
模板:
{ {#>partial} }https:yalishizhude.github.io{ {/partial} }
html页面:
亚里士朱德https:yalishizhude.github.io
当有多段代码需要填充到分页时,可以用如下方法。分页中内嵌分页变量,模板中通过内联分页的方式传入。
模板:
{ {#> partial} } { {#*inline "nav"} } 亚里士朱德 { {/inline} } { {#*inline "content"} } https://yalishizhude.github.io { {/inline} }{ {/partial} }
partial.hbs:
<div class="nav"> { {> nav} }</div><div class="content"> { {> content} }</div>
html页面:
<div class="nav"> 亚里士朱德</div><div class="content"> https://yalishizhude.github.io</div>
本文列举的只是handlebars中最重要和常用的功能,更多细碎的功能可以去查看
官方API 。
我想将导航条写成一个分页(partial),导航条左边的文字标题是可以通过参数传递的,但是右边的内容可能是文字、图片其它元素,需要具体业务自定义实现。我又不想把html代码写在js中,所以希望在模板中将这段未知的模板代码填充到分页中进行展现。我在官网文档中找到了 NaN来实现此功能,但是本机实验一直解析报错。
解决过程:
这个问题原因可能有两个,一是官方文档有错,二是本机环境的插件有问题(Express用hbs模块,该模块封装了handlebars引擎模块)。为了验证官方文档的正确性,我找到了一个在线handlebars解析器,输入文档中的代码时可以正确解析,那么只可能出现在hbs模块了。这时在github上找到hbs模块最新版本为4,查看本地版本为3,更新后果然可以正常解析了。
handlebars让我们看到一个好的插件应该有的特征:
作者:亚里士朱德
博客: http://yalishizhude.github.io