template模板函數


template模板

一個簡單的字符串模板

	var template = (function() { 
		var cache = {};
		return function(obj, str) {
			if (!typeof str === "string") {
				return;
			}
			var compile = cache[str]
			if (!cache[str]) {
				var template = str.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
					var k = arguments[1]
					var tm =  "';" + k  + " tmp+='"
					console.log("tm", tm)
					return tm;
				})
				.replace(/\$\{\s*([^\}]+)\s*\}/g, function() {
					var k = arguments[1]
					var tm = "' +" + k+ "+'";
					return tm;
				})
				template = "var tmp = \"\"; with(obj){tmp ='" + template + "';}return tmp;"
				console.log("template", template)
				compile = new Function("obj", template)
			}
			return compile(obj)
		}
	})()

使用

	var str = "" +
	"<div> "+
	"<ul> "+
	"<%= for(var i=0;i < obj.length; i++) { %> "+
	"<li>${obj[i].name}</li> "+
	"<%= } %> "+
	"</ul> "+
	"</div> "

	var obj = [
		{name: "李飛1"},
		{name: "李飛2"},
		{name: "李飛3"},
	];
	
	var html = template(obj, str);
	//生成字符串:"<div> <ul>  <li>李飛1</li>  <li>李飛2</li>  <li>李飛3</li>  </ul> </div> "

介紹

  1. template函數有兩個參數,第一個是數據,第二個是字符串模板.

  2. 字符串模板的格式要求

    1. 要執行的js代碼需要寫在: <%= 這里 %> . 比如: <%= var a = ""; %>
    2. 從對象里拿的數據寫在: ${ 這里 } . 比如: ${obj.name}
  3. 如果obj是對象的話,可以直接從對象里拿數據.比如:

    	var obj = {name: "李飛"};
    	var str = "hello, ${name}";
    	var html = template(obj, str);	
    	//html 為 "hello,"李飛
    
  4. 如果obj是數組的話,不能直接拿,需要把數組便利才能使用.

原理分析

簡單來說就是,把js代碼寫在固定的格式中,用String.replace()方法,獲取到js代碼的字符串.
然后拼成一個函數格式的字符串.再用new Function()用這個函數字符串生成一個函數,去處理
模板里的字符串並返回

知識點

  1. String.replace(參數1, 參數2)

    1. 參數1,可以是字符串也可以是正則表達式,如果是正則表示式.並且有全局匹配g的話,會替換所有的匹配項.如果此時參數2是函數,那么有多少個匹配項,函數就會執行杜少次
    2. 參數2,可以是字符串,也可以是回調函數.函數的返回值會替代匹配的字符串.而回調函數的參數是一般有四個.可以用arguments來拿;
      1. 第一個參數是正則匹配到的字符串
      2. 第二個參數是與正則表達式中子表達式相匹配的字符串.也就是正則中的括號()匹配到的字符串.也即是template函數中我們需要拼接的js字符串.
      3. 如果子表達式有2個,則這里是第二個.多個以此類推.如果子表達式沒有了.這里是整個被匹配到的字符串所在的length.
      4. 完整的原始字符串;
    3. replace函數不改變源字符串.返回值是替換之后的結果
  2. new Function(參數1, 參數2, functionBody)

    1. Function函數的最后一個參數functionBody就是函數字符串.這里的字符串會被變成js代碼成為函數體
    2. functionBody前面的參數都是最終函數的參數.
  3. with語句

    	var obj = {name: "lifei", age: 18};
    	with(obj) {
    		var a = name; // "lifei"
    		var age = age; // 18
    	}
    

    在with語句中可以用變量直接獲取obj對象上的屬性.就好像把window換成了obj一樣.可以直接訪問他的屬性.用在template函數中可以讓拼接的字符串更加的清晰.但是with語句執行緩慢.慎用.

  4. 用來匹配js代碼的正則表達式: /<%=\s([^%>]+)\s%>/g

    1. g: 全局匹配
    2. <%= : 用"<%="開頭
    3. \s* : 不定數量的空格
    4. [^%>] : 除了"%>"以外的其他字符
    5. () : 子表達式

詳解

因為有Function函數的存在.我們可以拼接一個函數字符串來生成函數.對源字符串進行處理.所以我們的主要問題就是用String.replace()拿到模板里的js代碼.再和源字符串一起拼接成一個函數字符串.再用new Function()生成函數,處理字符串.生成最后的結果.

比如:
```
	var str = "<span>name</span>"
	var obj = {name: "李飛"}
```
這兩個參數我們最后要生成的函數字符串是: 
```
	"var tmp = \"\"; with(obj){tmp ='<span>name</span>';}return tmp;"
```

```
var template = (function() { 
	var cache = {};
	return function(obj, str) {

		//判斷str
		if (!typeof str === "string") {
			return;
		}

		//懶加載
		var compile = cache[str]
		if (!cache[str]) {
			var template = str.replace(/<%=\s*([^%>]+)\s*%>/g, function() {
				
				//arguments拿到正則中([^%>]+)匹配到的,js代碼;
				var k = arguments[1]

				//拼接,這里最麻煩
				var tm =  "';" + k  + " tmp+='"
				return tm;
			})

			//因為js的執行代碼和從對象中取數據的代碼格式不一樣.所以要匹配兩次.
			.replace(/\$\{\s*([^\}]+)\s*\}/g, function() {
				var k = arguments[1]
				var tm = "' +" + k+ "+'";
				return tm;
			})

			//拼接函數代碼
			template = "var tmp = \"\"; with(obj){tmp ='" + template + "';}return tmp;"
			console.log("template")
			//生成函數.
			compile = new Function("obj", template)
		}

		//返回值
		return compile(obj)
	}
})()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM