首先我們先來寫一個(gè)簡單的模板引擎代碼
var str = "My name is {{name}},I'm {{age}} years old";
var regex = /{{([a-zA-Z_$][0-9a-zA-Z\._$]*)}}/g;
//match 匹配的字串
//key 匹配正則括號(hào)中的值(如有多個(gè)括號(hào)就會(huì)有多個(gè)值)
//offset 匹配字串的偏移量
//string 整個(gè)字符串
var data = {
name: 'jimmy',
age: 25,
sex: '男',
friend: {
name: 'tom'
}
};
var tpl = str.replace(regex, function(match, key, offset, string){
return data[key] || match;
});
console.log(tpl);//"My name is jimmy,I'm 25 years old"
優(yōu)化簡單的模板引擎代碼
上面的代碼有缺陷愧捕,如果在對象中有嵌套層的話,那么是無法被上面的正則匹配替換的申钩。
將上述代碼{{name}}修改成{{friend.name}}則不替換:
var str = "My {{friend.name}} is jimmy,I'm {{age}} years old";
console.log(tpl);//"My {{friend.name}} is jimmy,I‘m 25 years old"
現(xiàn)在我們來修改下代碼:
//match 匹配的字串
//key 匹配正則括號(hào)中的值
//offset 匹配字串的偏移量
//string 整個(gè)字符串
var a = str.replace(regex, function(match, key, offset, string){
var keys = key.split('.'),
obj = data;
while(keys.length > 0) {
key = keys.shift();
obj = obj[key];
}
return obj || match;
});
console.log(a);//"My name is tom,I'm 25 years old"次绘;
我們將{{friend.name}} 中的friend.name 通過 split('.') 截取成數(shù)組形成["friend", "name"],并且通過判斷長度length撒遣,循環(huán)調(diào)出最里面的值邮偎,直到循環(huán)到最里層,取到想要的值
相當(dāng)于:
//第一次循環(huán):
obj = obj[key];//{name:"tom"}
//第二次循環(huán):
obj = obj[key];//tom
那么現(xiàn)在來寫成函數(shù)
function easyTpl(data, str) {
var regex = /{{([a-zA-Z_$][0-9a-zA-Z\._$]*)}}/g;
var result = str.replace(regex, function(match, key, offset, string) {
var keys = key.split('.'),
obj = data;
while (keys.length > 0) {
key = keys.shift();
obj = obj[key];
}
return obj || match;
});
return result;
}
var tpl = easyTpl(data, str);
console.log(tpl);
準(zhǔn)備封裝
首先封裝的代碼不僅要起到隔離作用域的作用义黎,并且要能夠在CMD禾进、AMD、nodejs中通用使用廉涕,也就是說將這段封裝好的代碼移到各自環(huán)境中泻云,自己匹配適合的代碼生成模塊。
我們先來定義一個(gè)自執(zhí)行函數(shù)
(function(name, definition, context){
//TODO::
})(name, function(){}, this);
自執(zhí)行函數(shù)將要接受 一個(gè)(定義的函數(shù)名狐蜕,函數(shù)宠纯,作用域)
那么我們一步一步添加
(function(name, definition, context){
if(typeof module != 'undefined' && module.exports){
//在 node 環(huán)境中
module.exports = definition();
} else if (typeof context['define'] == 'function' && (context['define']['amd']) || typeof context['define'] == 'function' && (context['define']['cmd'])) {
//在 AMD(requirejs) 或者 在 CMD(seajs) 環(huán)境中
define(definition);
} else{
//在客戶端client中
context[name] = definition();
}
})(name, function(){}, this);
在這段代碼中,
第一個(gè)if判斷語句
通過能力檢測判斷 module 层释,module是在node環(huán)境中才有的方法婆瓜,并且module.exports存在,在將函數(shù)definition放進(jìn)mudule.exports 環(huán)境中,成為node環(huán)境下的代碼湃累。
第二個(gè)判斷語句
通過能力檢測判斷context['define']['amd']或context['define']['cmd']并且都判斷context是一個(gè)函數(shù)勃救,這樣說明在CMD或者AMD環(huán)境下,他們的定義磨礦化函數(shù)的方式都是difine(),所以通用格式寫成 difine(definition)治力。
最后一個(gè)是在不是 nodejs 和 CMD AMD 環(huán)境下 蒙秒,默認(rèn)在客戶端window環(huán)境下,所以context 等于 window 宵统。在window全局作用域下添加變量名name晕讲,并放入definition函數(shù)
完整代碼可以寫成
(function(name, definition, context) {
if (typeof module != 'undefined' && module.exports) {
//在 node 環(huán)境中
module.exports = definition();
} else if (typeof context['define'] == 'function' && (context['define']['amd']) || typeof context['define'] == 'function' && (context['define']['cmd'])) {
//在 AMD(requirejs) 或者 在 CMD(seajs) 環(huán)境中
define(definition);
} else {
//在客戶端中 client
context[name] = definition();
}
})('easyTpl', function() {
return function(data, str) {
var regex = /{{([a-zA-Z_$][0-9a-zA-Z\._$]*)}}/g;
return str.replace(regex, function(match, key, offset, string) {
var keys = key.split('.'),
obj = data;
while (keys.length > 0) {
obj = obj[keys.shift()];
}
return obj || match;
});
}
}, this);
最后 命令行操作
通過 npm init 生成packge.json
npm login
npm publish 發(fā)布上線
并通過 npm官網(wǎng)查找
下次自己使用通過 npm intall xxx 即可下載安裝到 全局或者 當(dāng)前文件夾的 node_modules中。