時間:2023-06-07 08:21:01 | 來源:網(wǎng)站運營
時間:2023-06-07 08:21:01 來源:網(wǎng)站運營
模板引擎的整理歸納:var songs =[ {name:'剛剛好', singer:'薛之謙', url:'http://music.163.com/xxx'}, {name:'最佳歌手', singer:'許嵩', url:'http://music.163.com/xxx'}, {name:'初學(xué)者', singer:'薛之謙', url:'http://music.163.com/xxx'}, {name:'紳士', singer:'薛之謙', url:'http://music.163.com/xxx'}, {name:'我們', singer:'陳偉霆', url:'http://music.163.com/xxx'}, {name:'畫風(fēng)', singer:'后弦', url:'http://music.163.com/xxx'}, {name:'We Are One', singer:'郁可唯', url:'http://music.163.com/xxx'} ] //拼接字符串,有一定惡意腳本注入風(fēng)險 遍歷 var html = ''; html +='<div class="song-list">' html +=' <h1>熱歌榜</h1>' html +=' <ol>' for(var i=0;i<songs.length;i++){ html += '<li>'+songs[i].name+' - '+songs[i].singer+'</li>' } html +=' </ol>' html +='</div>' document.body.innerHTML =html;
// 構(gòu)造DOM對象 遍歷 缺點復(fù)雜; var elDiv = document.createElement('div') elDiv.className = 'song-list'; var elH1 =document.createElement('h1') elH1.appendChild(document.createTextNode('熱歌榜')) var elList = document.createElement('ol') for(var i = 0; i<songs.length;i++){ var li = document.createElement('li') li.textContent = songs[i].name +' - ' + songs[i].singer elList.appendChild(li) } elDiv.appendChild(elH1); elDiv.appendChild(elList); document.body.appendChild(elDiv);
可以看到上述兩種方式雖然可以達成需求,但是尤其繁瑣且缺乏規(guī)范,很容易出錯。var template = '<p>Hello,my name is <%name%>. I am <%age%> years old.</p>'; var data ={ name:'zyn', age:31 } var TemplateEngine = function (tpl,data){ var regex = /<%([^%>]+)?%>/g; while(match = regex.exec(tpl)){ tpl = tpl.replace(match[0],data[match[1]]) } return tpl } var string = TemplateEngine(template,data) console.log(string);
這里其實就是把模板中需要替換的字符串做了個標(biāo)記,這里是以<%...%>作為標(biāo)記,然后替換時基于正則捕捉該標(biāo)記并進行數(shù)據(jù)源的替換(通過同一個key進行)模板文件: var template = '<p>Hello,my name is <%name%>. I am <%age%> years old.</p>';數(shù)據(jù): var data ={ name:'zyn', age:31 }模板引擎: var TemplateEngine = function (tpl,data){ var regex = /<%([^%>]+)?%>/g; while(match = regex.exec(tpl)){ tpl = tpl.replace(match[0],data[match[1]]) } return tpl }HTML文件: var string=TemplateEngine(template,data) document.body.innerHTML= string
var data ={ name:'zyn', profile:{age:31} }
在模板中使用<%profile.age%>的話,代碼會被替換成data[‘profile.age’],結(jié)果是undefined,因為括號型沒辦法認(rèn)識.符號,當(dāng)然我們可以改進Template函數(shù)來分解復(fù)雜對象轉(zhuǎn)換為[][]的形式。但是這里我們換一個方式。var template = '<p>Hello, my name is <%this.name%>. I/'m <%this.profile.age%> years old.</p>'
這里為了之后的示范,我們補充一下關(guān)于new Function的知識,這個函數(shù)的構(gòu)造函數(shù)可以根據(jù)傳入?yún)?shù)來動態(tài)生成一個函數(shù),包括函數(shù)入?yún)?,函?shù)體等:var fn = new Function("num", "console.log(num + 1);");fn(2); //3
等同于:var fn = function(num) { console.log(num + 1);}fn(2); // 3
這里我們思路基本明確了,就是希望構(gòu)建一個函數(shù)體字符串,然后利用JS代碼執(zhí)行過程幫我們把數(shù)據(jù)綁定到模板上面。var Arr=[];Arr.push("<p>Hello,my name is");Arr.push(this.name);Arr.push("i am");Arr.push(this.proflie.age)Arr.push("years old</p>")return Arr.join('')
接下來需要做的還是去尋找模板中的標(biāo)記位,即<%...%>片段,然后遍歷所有的匹配項將其push到字符串?dāng)?shù)組中去,最后借助new Function完成。var TemplateEngine = function(tpl, data) { // 正則全局匹配 // code用于保存函數(shù)體字符串 // cursor是游標(biāo),用于記錄tpl處理的位置 var re = /<%([^%>]+)?%>/g, code = 'var Arr=[];/n', cursor = 0; // 函數(shù)add負責(zé)將解析的代碼行添加到code函數(shù)體中 // 后面的replace是將code包含的雙引號進行轉(zhuǎn)義 var add = function(line) { code += 'Arr.push("' + line.replace(/"/g, '//"') + '");/n'; } // 循環(huán)處理模板,每當(dāng)存在匹配項就進入循環(huán)體 while(match = re.exec(tpl)) { add(tpl.slice(cursor, match.index)); add(match[1]); cursor = match.index + match[0].length; } add(tpl.substr(cursor, tpl.length - cursor)); code += 'return Arr.join("");'; // <-- return the result console.log(code); return tpl;}var template = '<p>Hello, my name is <%this.name%>. I/'m <%this.profile.age%> years old.</p>';var data = { name: "zyn", profile: { age: 29 }}console.log(TemplateEngine(template, data));
循環(huán)過程:第一次循環(huán):match=[ 0:<%this.name%>", 1:"this.name", index:21, input:"<p>Hello, my name is<%this.name%>.I'm<%this.profile.age%>years old.</p>", length:2 ]tpl.slice(cursor, match.index) = "<p>Hello, my name is "執(zhí)行函數(shù)add("<p>Hello, my name is ")code="var Arr=[];Arr.push("<p>Hello, my name is ");"在執(zhí)行add(match[1]);match[1]="this.name"code ="var Arr=[];Arr.push("<p>Hello, my name is ");Arr.push("this.name");" cursor = match.index + match[0].length;cursor = 21+13=34;//就是<%this.name%>最后一位的位置;第二次循環(huán)跟第一次一樣繼續(xù)把模板文件添加到code上;兩次循環(huán)完成后code = "var Arr[];Arr.push("<p>Hello, my name is ");Arr.push("this.name");Arr.push(". I'm ");Arr.push("this.profile.age")"cursor =60 ;然后執(zhí)行: add(tpl.substr(cursor, tpl.length - cursor));cursor =60 ; tpl.length=75 tpl.substr(cursor, tpl.length - cursor)截取最后一段模板文件 years old.</p>code += 'return Arr.join("");'code = "var Arr[];Arr.push("<p>Hello, my name is ");Arr.push("this.name");Arr.push(". I'm ");Arr.push("this.profile.age")Arr.push("years old </p>")return Arr.join("")"如果還不明白可以復(fù)制代碼在代碼上打幾個斷點看下執(zhí)行的過程,很快就能明白;
最后我們會在控制臺里面看見如下的內(nèi)容:var Arr[];Arr.push("<p>Hello, my name is ");Arr.push("this.name");Arr.push(". I'm ");Arr.push("this.profile.age")Arr.push("years old </p>")return Arr.join("")<p>Hello, my name is <%this.name%>. I'm <%this.profile.age%> years old.</p>
這里還存在一些問題:var TemplateEngine = function(html, options) { var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var Arr=[];/n', cursor = 0; var add = function(line, js) { js? (code += line.match(reExp) ? line + '/n' : 'r.push(' + line + ');/n') : (code += line != '' ? 'r.push("' + line.replace(/"/g, '//"') + '");/n' : ''); return add; } while(match = re.exec(html)) { add(html.slice(cursor, match.index))(match[1], true); cursor = match.index + match[0].length; } add(html.substr(cursor, html.length - cursor)); code += 'return r.join("");'; return new Function(code.replace(/[/r/t/n]/g, ''));}
這里感興趣的可以基于上面的示例自己嘗試去實現(xiàn)一下上一小節(jié)的例子~關(guān)鍵詞:歸納,整理,引擎,模板
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。