handlebars

handlebars

​ 開發一個頁面組件,原本想着本身純手工擼,通過大大的指導發現有個叫handleBars的模版工具,能夠減小不少開發工做量,因而試了一下,這東西有點老,也有坑,但整體用下來比本身純手寫樣式仍是香不少。php

​ Handlebars是一種簡單的模版語言,使用模版和輸入對象來生成HTML或者其餘文本格式,是個帶有嵌入式的handlebars表達式,就相似{{表達式}},在執行模版時,這些表達式就會被輸入對象中的值所替換html

1.安裝

​ 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

2.語法詳解

(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定義了幾個內置的助手代碼,方便使用,接下來簡單介紹一下

  • if

    根據條件渲染代碼塊,若是參數返回false,undefined,null,"",0或者[]時,該代碼塊將不會被渲染

    {{#if 0 === 1}}<div>我永遠不會被渲染</div>{{/if}}

  • unless

    和#if相反,當表達式返回false時渲染代碼塊{{#unless 0 === 1}}<div>我會被渲染</div>{{/unless}}

  • each

    遍歷列表,能夠使用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後面的參數就能夠作爲#with內容中的this,這個對於多重嵌套的模板十分好用,嵌套層次很深的時候,就再也不須要a.b.c.d這種形式進行數據引用

    `{{#with city as | city |}}
    {{#with city.location as | loc |}}

    {{city.name}}: {{loc.north}} {{loc.east}}

    {{/with}}
    {{/with}}`

    其中as用於給對應的參數取別名,取別名以後就能夠使用別名進行引用了

    each也能夠使用{{else}}

  • 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'。

  • log

    容許在執行模板時記錄上下文的狀態

    (4)補充語法

    {{{裏面的內容原樣輸出}}}

3.模板語言的原理(自身理解)

模板語言分爲預設處理模塊和模板編輯模塊兩個部分,預設處理模塊是預設一些模板的處理邏輯,當系統遇到這些邏輯時,就會進行相應的處理,好比在處理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
相關文章
相關標籤/搜索