最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue中Mustache引擎插值語法使用詳解

 更新時間:2022年12月12日 09:08:27   作者:糖^O^  
在Vue中通過Mustache模板引擎將data中的文本數(shù)據(jù)插入到HTML中,下面這篇文章主要給大家介紹了關(guān)于Vue中Mustache模板引擎插值語法的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下

什么是模板引擎

模板引擎是將數(shù)據(jù)變?yōu)橐晥D最優(yōu)雅的解決方案

以前出現(xiàn)過的其它數(shù)據(jù)變視圖的方法

純 DOM 法

數(shù)組 join 法

在 js 里單雙引號內(nèi)的內(nèi)容是不能換行的,為了提高 dom 結(jié)構(gòu)可讀性,利用了數(shù)組的 join 方法(將數(shù)組變?yōu)樽址?,注?join 的參數(shù) ‘’ 不可以省略,否則得到的 str 字符串會是以逗號間隔的

es6 的模板字符串(``)

剛開始用模板引擎時可以引用 如下:

<script src="https://cdn.bootcdn.net/ajax/libs/mustache.js/4.2.0/mustache.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/mustache.js/4.2.0/mustache.js"></script>

底層核心機理

//最簡單的模板的實現(xiàn)機理,利用的是正則表達式中的replace()方法

// replace()的第二個參數(shù)可以是一個函數(shù),這個函數(shù)提供捕獲的東西的參數(shù),就是$1

//結(jié)合data的對象,即可進行智能的替換

//編譯普通對象成token
const templateStr = `<h3>我今天買了一部{{thing}}手機,花了我{{money}}元,心情好{{mood}}啊</h3>`;
[
    ["text",'<h3>我今天買了一部'],
    ["name",'thing'],
    ["text",'手機,花了我'],
    ["name",'money']
    ["text",'元,心情好'],
    ["name","mood"],
    ["text",'啊']
]

模塊化打包工具有webpack(webpack-dev-server) 、rollup、Parcel等

我們經(jīng)常使用webpack進行模塊化打包

實現(xiàn) Scanner 類

Scanner 類的實例就是一個掃描器,用來掃描構(gòu)造時作為參數(shù)提供的那個模板字符串

- 屬性

  • pos:指針,用于記錄當(dāng)前掃描到字符串的位置
  • tail:尾巴,值為當(dāng)前指針之后的字符串(包括指針當(dāng)前指向的那個字符)

- 方法

  • scan:無返回值,讓指針跳過傳入的結(jié)束標(biāo)識 stopTag
  • scanUntil:傳入一個指定內(nèi)容 stopTag 作為讓指針 pos 結(jié)束掃描的標(biāo)識,并返回掃描內(nèi)容
// Scanner.js
export default class Scanner {
  constructor(templateStr) {
    this.templateStr = templateStr
    // 指針
    this.pos = 0
    // 尾巴
    this.tail = templateStr
  }
  scan(stopTag) { 
    this.pos +=  stopTag.length // 指針跳過 stopTag,比如 stopTag 是 {{,則 pos 就會加2
    this.tail = this.templateStr.substring(this.pos) // substring 不傳第二個參數(shù)直接截取到末尾
  }
  scanUntil(stopTag) {
    const pos_backup = this.pos // 記錄本次掃描開始時的指針位置
    // 當(dāng)指針還沒掃到最后面,并且當(dāng)尾巴開頭不是 stopTag 時,繼續(xù)移動指針進行掃描
    while (!this.eos() && this.tail.indexOf(stopTag) !== 0){
      this.pos++ // 移動指針
      this.tail = this.templateStr.substring(this.pos) // 更新尾巴
    }
    return this.templateStr.substring(pos_backup, this.pos) // 返回掃描過的字符串,不包括 this.pos 處
  }
  // 指針是否已經(jīng)抵達字符串末端,返回布爾值 eos(end of string)
  eos() {
    return this.pos >= this.templateStr.length
  }
}

根據(jù)模板字符串生成 tokens

tokens是一個JS的嵌套數(shù)組,說白了,就是模板字符串的JS表示

有了 Scanner 類后,就可以著手去根據(jù)傳入的模板字符串生成一個 tokens 數(shù)組了。最終想要生成的 tokens 里的每一條 token 數(shù)組的第一項用 name(數(shù)據(jù)) 或 text(非數(shù)據(jù)文本) 或 #(循環(huán)開始) 或 /(循環(huán)結(jié)束) 作為標(biāo)識符

// parseTemplateToTokens.js
import Scanner from './Scanner.js'
import nestTokens from './nestTokens' // 后面會解釋
// 函數(shù) parseTemplateToTokens
export default templateStr => {
  const tokens = []
  const scanner = new Scanner(templateStr)
  let word
  while (!scanner.eos()) {
    word = scanner.scanUntil('{{')
    word && tokens.push(['text', word]) // 保證 word 有值再往 tokens 里添加
    scanner.scan('{{')
    word = scanner.scanUntil('}}')
    /** 
     *  判斷從 {{ 和 }} 之間收集到的 word 的開頭是不是特殊字符 # 或 /, 
     *  如果是則這個 token 的第一個元素相應(yīng)的為 # 或 /, 否則為 name
     */
    word && (word[0] === '#' ? tokens.push(['#', word.substr(1)]) : 
      word[0] === '/' ? tokens.push(['/', word]) : tokens.push(['name', word]))
    scanner.scan('}}')
  }
  return nestTokens(tokens) // 返回折疊后的 tokens, 詳見下文
}

在 index.js 引入 parseTemplateToTokens

// index.js
import parseTemplateToTokens from './parseTemplateToTokens.js'
window.My_TemplateEngine = {
  render(templateStr, data) {
    const tokens = parseTemplateToTokens(templateStr)
    console.log(tokens)
  }
}

這樣我們就可以把傳入的 templateStr 初步轉(zhuǎn)成 tokens 了,比如 templateStr 為

const templateStr = `
  <ul>
      {{#arr}}
        <li>
          <div>{{name}}的基本信息</div>
          <div>
            <p>{{name}}</p>
            <p>{{age}}</p>
            <div>
              <p>愛好:</p>
              <ol>
                {{#hobbies}}
                  <li>{{.}}</li>
                {{/hobbies}}
              </ol>
            </div>
          </div>
        </li>
      {{/arr}}
  </ul>
`

那么目前經(jīng)過 parseTemplateToTokens 處理將得到如下的 tokens

實現(xiàn) tokens 的嵌套

新建 nestTokens.js 文件,定義 nestTokens 函數(shù)來做 tokens 的嵌套功能,將傳入的 tokens 處理成包含嵌套的 nestTokens 數(shù)組返回。

然后在 parseTemplateToTokens.js 引入 nestTokens,在最后 return nestTokens(tokens)

在 nestTokens 中,我們遍歷傳入的 tokens 的每一個 token,遇到第一項是 # 和 /的分別做處理,其余的做一個默認(rèn)處理。

大致思路是當(dāng)遍歷到的 token 的第一項為 # 時,就把直至遇到配套的 / 之前,遍歷到的每一個 token 都放入一個容器(collector)中,把這個容器放入當(dāng)前 token 里作為第 3 項元素

但這里有個問題:在遇到匹配的 / 之前又遇到 # 了怎么辦?也就是如何解決循環(huán)里面嵌套循環(huán)的情況?

解決方法就是新建一個 棧數(shù)據(jù)類型 的數(shù)組(stack),遇到一個 #,就把當(dāng)前 token 放入這個棧中,讓 collector 指向這個 token 的第三個元素。

遇到下一個 # 就把新的 token 放入棧中,collector 指向新的 token 的第三個元素。

遇到 / 就把棧頂?shù)?token 移出棧,collector 指向移出完后的棧頂 token。

這就利用了棧的先進后出的特點,保證了遍歷的每個 token 都能放在正確的地方,也就是 collector 都能指向正確的地址。

// nestTokens.js
export default (tokens) => {
  const nestTokens = []
  const stack = []
  let collector = nestTokens // 一開始讓收集器 collector 指向最終返回的數(shù)組 nestTokens
  tokens.forEach(token => {
    switch (token[0]) {
      case '#':
        stack.push(token)
        collector.push(token)
        collector = token[2] = [] // 連等賦值
        break
      case '/':
        stack.pop(token)
        collector = stack.length > 0 ? stack[stack.length-1][2] : nestTokens
        break;
      default:
        collector.push(token)
        break
    }
  })
  return nestTokens
}

One More Thing

上面的代碼中有用到 collector = token[2] = [],是為連等賦值,相當(dāng)于

token[2] = []
collector = token[2]

看著簡單,其實暗含著小坑,除非你真的了解它,否則盡量不要使用。比如我在別處看到這么一個例子,

let a = {n:1};
a.x = a = {n:2};
console.log(a.x); // 輸出? 

答案是 undefined,你做對了嗎?

tokens 結(jié)合數(shù)據(jù)解析為 dom 字符串

大致思路是遍歷 tokens 數(shù)組,根據(jù)每條 token 的第一項的值來做不同的處理,為 text 就直接把 token[1]

加入到最終輸出的 dom 字符串,為 name 則根據(jù) token[1] 去 data 里獲取數(shù)據(jù),結(jié)合進來。

當(dāng) data 里存在多層嵌套的數(shù)據(jù)結(jié)構(gòu),比如 data = { test: { a: { b: 10 } } },這時如果某個 token 為 [“name”, “test.a.b”],即代表數(shù)據(jù)的 token 的第 2 項元素是 test.a.b 這樣的有多個點符號的值,那么我么直接通過 data[test.a.b] 是無法拿到正確的值的,因為 js 不認(rèn)識這種寫法。

我們需要提前準(zhǔn)備一個 lookup 函數(shù),用以正確獲取數(shù)據(jù)。

定義 lookup 函數(shù)

// lookup.js
// 思路就是先獲取 test.a 的值, 比如說是 temp, 再獲取 temp.b 的值, 一步步獲取
export default (data, key) => {
  // 如果傳入的 key 里有點符號而且不是僅僅只是點符號
  if (key.indexOf('.') !== -1 && key !== '.' ) {
    const keys = key.split('.') // 將 key 用 . 分割成一個數(shù)組
    return keys.reduce((acc, cur) => {
      return acc[cur] // 一步步獲取
    }, data)
  }
  // 如果傳入的 key 沒有點符號,直接返回
  return data[key]
}

定義 renderTemplate 函數(shù)

接下來寫個 renderTemplate 函數(shù)將 tokens 和 data 作為參數(shù)傳入,解析為 dom 字符串了。

// renderTemplate.js
import lookup from './lookup.js'
import parseArray from './parseArray.js'
export default (tokens, data) => {
  let domString = ''
  tokens.forEach(token => {  
    switch (token[0]) {
      case 'text':
        domString += token[1]
        break
      case 'name':
        domString += lookup(data, token[1])
        break
      case '#':
        domString += parseArray(token[2], data[token[1]])
        break
      default:
        break
    }
  }) 
  return domString
}

需要注意的是遇到循環(huán)的情況,也就是當(dāng)某個 token 的第一項為 “#” 時,要再次遞歸調(diào)用 renderTemplate 函數(shù)。這里我們新定義了一個 parseArray 函數(shù)來處理。

// parseArray.js
import renderTemplate from './renderTemplate.js'
export default (tokens, data) => {
  let domString = ''
  data.forEach(itemData => {
    domString += renderTemplate(tokens, {
      ...itemData,
      '.': itemData // 針對簡單數(shù)組的情況,即模板字符串里的 {{.}} 
    })
  })
  return domString
}

到此這篇關(guān)于Vue中Mustache引擎插值語法使用詳解的文章就介紹到這了,更多相關(guān)Vue Mustache內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue組件的渲染流程詳細(xì)講解

    Vue組件的渲染流程詳細(xì)講解

    在Vue核心中除了響應(yīng)式原理外,視圖渲染也是重中之重,下面這篇文章主要給大家介紹了關(guān)于Vue組件的渲染流程,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • 解決vue-cli項目打包出現(xiàn)空白頁和路徑錯誤的問題

    解決vue-cli項目打包出現(xiàn)空白頁和路徑錯誤的問題

    今天小編就為大家分享一篇解決vue-cli項目打包出現(xiàn)空白頁和路徑錯誤的問題。具有很好的參考價值。希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue和webpack安裝命令詳解

    vue和webpack安裝命令詳解

    這篇文章主要介紹了vue和webpack安裝命令,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • vue antd的from表單中驗證rules中type的坑記錄

    vue antd的from表單中驗證rules中type的坑記錄

    這篇文章主要介紹了vue antd的from表單中驗證rules中type的坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • vue中動態(tài)設(shè)置meta標(biāo)簽和title標(biāo)簽的方法

    vue中動態(tài)設(shè)置meta標(biāo)簽和title標(biāo)簽的方法

    這篇文章主要介紹了vue中動態(tài)設(shè)置meta標(biāo)簽和title標(biāo)簽的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • vue Element UI 解決表格數(shù)據(jù)不更新問題及解決方案

    vue Element UI 解決表格數(shù)據(jù)不更新問題及解決方案

    在使用Vue和ElementUI開發(fā)后臺管理系統(tǒng)時,可能會遇到表格數(shù)據(jù)不更新的問題,這通常是因為Vue的響應(yīng)式系統(tǒng)未檢測到數(shù)據(jù)變化或數(shù)據(jù)更新后未正確觸發(fā)視圖的重新渲染,本文給大家介紹vue Element UI 解決表格數(shù)據(jù)不更新問題,感興趣的朋友一起看看吧
    2024-10-10
  • vue大型項目之分模塊運行/打包的實現(xiàn)

    vue大型項目之分模塊運行/打包的實現(xiàn)

    這篇文章主要介紹了vue大型項目之分模塊運行/打包的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 基于vue實現(xiàn)分頁效果

    基于vue實現(xiàn)分頁效果

    這篇文章主要介紹了基于vue實現(xiàn)分頁效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 詳解Vuejs2.0之異步跨域請求

    詳解Vuejs2.0之異步跨域請求

    這篇文章主要介紹了詳解Vuejs2.0之異步跨域請求,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Vue項目每次發(fā)版后要清理瀏覽器緩存問題解決辦法

    Vue項目每次發(fā)版后要清理瀏覽器緩存問題解決辦法

    最近項目更新頻繁,每次一更新客戶都說還跟之前的一樣,一查原因是因為客戶沒有清空瀏覽器的緩存,所以為了方便客戶看到最新版本,開始調(diào)研再發(fā)布新版本后自動清理緩存,這篇文章主要給大家介紹了關(guān)于Vue項目每次發(fā)版后要清理瀏覽器緩存問題的解決辦法,需要的朋友可以參考下
    2024-02-02

最新評論

习水县| 宣恩县| 平塘县| 鄱阳县| 洛浦县| 伊通| 临漳县| 包头市| 阿城市| 宜宾市| 万全县| 永寿县| 白玉县| 延寿县| 嘉峪关市| 资阳市| 巴青县| 鄂伦春自治旗| 潮安县| 方正县| 桑日县| 庆元县| 噶尔县| 克东县| 雷州市| 饶阳县| 绍兴市| 将乐县| 武冈市| 桑日县| 小金县| 望谟县| 瑞丽市| 汉阴县| 阳信县| 海丰县| 家居| 临夏市| 高尔夫| 会理县| 陆丰市|