建立AMD、CMD、nodeJS通用的模板引擎,并封装发布到np

2016-10-12  本文已影响0人  李大嘴JimmyLee
首先我们先来写一个简单的模板引擎代码
var str = "My name is {{name}},I'm {{age}} years old";

var regex = /{{([a-zA-Z_$][0-9a-zA-Z\._$]*)}}/g;

 //match 匹配的字串
 //key 匹配正则括号中的值(如有多个括号就会有多个值)
 //offset 匹配字串的偏移量
 //string 整个字符串

  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"

优化简单的模板引擎代码

上面的代码有缺陷,如果在对象中有嵌套层的话,那么是无法被上面的正则匹配替换的。

将上述代码{{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"

现在我们来修改下代码:

//match 匹配的字串
//key 匹配正则括号中的值
//offset 匹配字串的偏移量
//string 整个字符串
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('.') 截取成数组形成["friend", "name"],并且通过判断长度length,循环调出最里面的值,直到循环到最里层,取到想要的值
相当于:

//第一次循环:
 obj = obj[key];//{name:"tom"}
//第二次循环:
 obj = obj[key];//tom

那么现在来写成函数
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);

准备封装

首先封装的代码不仅要起到隔离作用域的作用,并且要能够在CMD、AMD、nodejs中通用使用,也就是说将这段封装好的代码移到各自环境中,自己匹配适合的代码生成模块。

我们先来定义一个自执行函数

(function(name, definition, context){
  //TODO::
})(name, function(){}, this);

自执行函数将要接受 一个(定义的函数名,函数,作用域)

那么我们一步一步添加

(function(name, definition, context){
  if(typeof module != 'undefined' && module.exports){
    //在 node 环境中
    module.exports = definition();
  } else if (typeof context['define'] == 'function' && (context['define']['amd']) || typeof context['define'] == 'function' && (context['define']['cmd'])) {
    //在 AMD(requirejs) 或者 在 CMD(seajs) 环境中 
    define(definition);
  } else{
    //在客户端client中 
    context[name] = definition();
  }
})(name, function(){}, this);

在这段代码中,
第一个if判断语句
通过能力检测判断 module ,module是在node环境中才有的方法,并且module.exports存在,在将函数definition放进mudule.exports 环境中,成为node环境下的代码。
第二个判断语句
通过能力检测判断context['define']['amd']或context['define']['cmd']并且都判断context是一个函数,这样说明在CMD或者AMD环境下,他们的定义磨矿化函数的方式都是difine(),所以通用格式写成 difine(definition)。

最后一个是在不是 nodejs 和 CMD AMD 环境下 ,默认在客户端window环境下,所以context 等于 window 。在window全局作用域下添加变量名name,并放入definition函数


完整代码可以写成
(function(name, definition, context) {
  if (typeof module != 'undefined' && module.exports) {
    //在 node 环境中
    module.exports = definition();
  } else if (typeof context['define'] == 'function' && (context['define']['amd']) || typeof context['define'] == 'function' && (context['define']['cmd'])) {
    //在 AMD(requirejs) 或者 在 CMD(seajs) 环境中 
    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 发布上线
并通过 npm官网查找
下次自己使用通过 npm intall xxx 即可下载安装到 全局或者 当前文件夹的 node_modules中。

上一篇下一篇

猜你喜欢

热点阅读