javascript模版引擎-tmpl 的精简及bug修正

展开/收缩

在基于MVC框架开发的web app中,js模板引擎显得特别重要,只需一个模板文本加一段json数据,mix一下,内容就出来了,以往都是用mustache.js, 这里记录一下项目同事介绍一个超精简的模板引擎-tmpl ,对对于mustache.js的单独的模板语法,这个引擎亲切许多,因为可以直接使用js原生的语法,像for switch if,之类。原作为jquery的作者John Resig 开发,详细博客地址, 另有国内某牛人性能改进版,详细见 博文 ,但使用之后,发现还是有点问题,先贴下完整代码:

/**
 * 微型模板引擎 tmpl 0.2
 * 0.2 更新:
 * 1. 修复转义字符与id判断的BUG
 * 2. 放弃低效的 with 语句从而最高提升3.5倍的执行效率
 * 3. 使用随机内部变量防止与模板变量产生冲突
 * @example
 * 方式一:在页面嵌入模板
 * <scriptt type="text/tmpl" id="tmpl-demo">
 * <ol title="<%=name%>">
 *  <% for (var i = 0, l = list.length; i < length; i ++) { %>
 *      <li><%=list[i]%></li>
 *  <% } %>
 * </ol>
 * </scriptt>
 * tmpl('tmpl-demo', {name: 'demo data', list: [202, 96, 133, 134]})
 *
 * 方式二:直接传入模板:
 * var demoTmpl =
 * '<ol title="<%=name%>">'
 * + '<% for (var i = 0, l = list.length; i < length; i ++) { %>'
 * +    '<li><%=list[i]%></li>'
 * + '<% } %>'
 * +'</ol>';
 * var render = tmpl(demoTmpl);
 * render({name: 'demo data', list: [202, 96, 133, 134]});
 *
 * 这两种方式区别在于第一个会自动缓存编译好的模板,
 * 而第二种缓存交给外部对象控制,如例二中的 render 变量。
 * @blog http://www.planeart.cn/?p=1594
 * @see		http://ejohn.org/blog/javascript-micro-templating/
 * @param	{String}	模板内容或者装有模板内容的元素ID
 * @param	{Object}	附加的数据
 * @return	{String}	解析好的模板
 */
var tmpl = (function (cache, $) {
return function (str, data) {
	var fn = !/W/.test(str)
	? cache[str] = cache[str]
		|| tmpl(document.getElementById(str).innerHTML)

	: function (data) {
		var i, variable = [$], value = [[]];
		for (i in data) {
			variable.push(i);
			value.push(data[i]);
		};
		return (new Function(variable, fn.$))
		.apply(data, value).join("");
	};

	fn.$ = fn.$ || $ + ".push('"
	+ str.replace(/\/g, "\\")
		 .replace(/[rtn]/g, " ")
		 .split("<%").join("t")
		 .replace(/((^|%>)[^t]*)'/g, "$1r")
		 .replace(/t=(.*?)%>/g, "',$1,'")
		 .split("t").join("');")
		 .split("%>").join($ + ".push('")
		 .split("r").join("\'")
	+ "');return " + $;

	return data ? fn(data) : fn;
}})({}, '$' + (+ new Date));

此代码预设了两种模板使用环境,一种是用script标签,另一种直接传入string,是由代码的这个部分:

var fn = !/W/.test(str)

来判断是script标签还是直接string的,\W是代表非单词字符,这种判断预设了用户的script 的 id 一定为单词字符,如果是连字符”-”即会被当成string,出现错误,不是特别完美,
暂时也没找到什么好的判断方式,况且通常应用场都是用string, 索性直接去掉script的判断,只支持string的模板,如果硬要script,可以自行获取 script的innerHTML然后再以string的方式传给tmpl函数,另外模板里的语法是通过<%%>包裹的,容易与其他后端语言的模板冲突,故改成<##>.
以下是修正后的完整代码:

/**
 * 微型模板引擎 tmpl
 * 方式:直接传入模板:(可以随心所欲的使用js原生语法)
 * var demoTmpl =
 * '<ol title="<%=name%>">'
 * + '<% for (var i = 0, l = list.length; i < length; i ++) { %>'
 * +    '<li><%=list[i]%></li>'
 * + '<% } %>'
 * +'</ol>';
 * var render = tmpl(demoTmpl);
 * render({name: 'demo data', list: [202, 96, 133, 134]});
 *
 * 缓存交给外部对象控制,如例二中的 render 变量。
 * @blog http://www.planeart.cn/?p=1594
 * @see		http://ejohn.org/blog/javascript-micro-templating/
 * @param	{String}	模板内容或者装有模板内容的元素ID
 * @param	{Object}	附加的数据
 * @return	{String}	解析好的模板
 */
var tmpl = (function (cache, $) {
return function (str, data) {
	var fn = function (data) {
		var i, variable = [$], value = [[]];
		for (i in data) {
			variable.push(i);
			value.push(data[i]);
		};
		return (new Function(variable, fn.$))
		.apply(data, value).join("");
	};

	fn.$ = fn.$ || $ + ".push('"
	+ str.replace(/\/g, "\\")
		 .replace(/[rtn]/g, " ")
		 .split("<#").join("t")
		 .replace(/((^|#>)[^t]*)'/g, "$1r")
		 .replace(/t=(.*?)#>/g, "',$1,'")
		 .split("t").join("');")
		 .split("#>").join($ + ".push('")
		 .split("r").join("\'")
	+ "');return " + $;

	return data ? fn(data) : fn;
}})({}, '$' + (+ new Date));

正则表达式的技巧总结

展开/收缩

正则表达式在现在web的应用当中,如表单验证,url解析等,应用非常方便,比起普通的字符串解析性能上也高出不少。
这里就做一些关于正则表达式通用技巧的个人小总结,正则的入门可以参考以下网址内容
http://www.regexlab.com/zh/regref.htm
http://w3school.com.cn/js/jsref_obj_regexp.asp

1. 一些常用的元字符.
\w : 查找单词字符,包含字母数字及下划线,相当于[A-Za-z0-9_];
\d : 查找数字,相当于[0-9]
\s : 查找空白字符
\n : 查找换行符
. : 点号代表除换行符及行结束符外所有字符

2. 验证完整字符串,这在表单验证中常用到,例子如下:

var str = '18636200607';
var str2 = '10010';
var reg = /^\d{11}$/;
console.log(reg.test(str)); // return true;
console.log(reg.test(str2)); // return false;

这里的头尾的^$即是限定匹配的必须是整个字符串,而不是其中一部分,这对于表单验证里验证完整的合法输入很有用。
[继续阅读全文...]

javascript 多重继承小记

展开/收缩

第一种实现多重继承的方法是利用call/apply实现多重继承,核心就是用Function类的call/apply方法去绑定新的类,使新的类实例化后的对象继承了该属性及方法
代码如下:

/*-------利用call/apply实现多重继承--------*/
//基类1
function Base1(){
	this.name  = "base1";
	this.getName = function(){
		alert(this.name);
	}
};

//基类2
function Base2(){
	this.act = "eating";
	this._item = "banana";
	this.saying = function(){
		alert("I'm "+this.act+" the "+this._item+"!");
	};
};

//利用call/apply多重继承
function Extend(){
	//arguments为传进的参数伪数组
	for(var i=0; i<arguments.length; i++){
		arguments[i].call(this);
	}
}

//实例化一个对象,并继承自Base1,Base2
var myClass = new Extend(Base1,Base2);
myClass.getName();
myClass.saying();

[继续阅读全文...]

Google Chrome不支持本地添加cookie

展开/收缩

最近有个项目需要做Cookie的读取写入,在本地测试了几个浏览器,均无问题,唯独Google Chrome 是怎么也无法写入,最后GG一下找来原因,

原来: Google Chrome不支持本地添加cookie,网络浏览情况下是正常的。

记录一下。。

基于cookie的浏览记录功能

展开/收缩

script 部分================

/**********************
function : oCookieRecord
author : Der [http://hi.baidu.com/jasyyy]
lastodify : 2010-04-22
***********************/

//setCookie
function setCookie(name, value, days, path, domain, secure) {
	var sCookie = name + "=" + encodeURIComponent(value);
	if (days) {
		var _exp = new Date();
		_exp.setTime(_exp.getTime() + days * 24 * 60 * 60 * 1000);
		sCookie += "; expires=" + _exp.toGMTString();
	}
	if (path) {
		sCookie += "; path=" + path;
	} else {
		sCookie += "; path=/";
	}
	if (domain) {
		sCookie += "; domain=" + domain;
	}
	if (secure) {
		sCookie += "; secure=";
	}
	document.cookie = sCookie;
}

//getCookie
function getCookie(name) {
	var sRE = "(?:; )?" + name + "=([^;]*);?";
	var oRE = new RegExp(sRE);
	return (oRE.test(document.cookie)) ? decodeURIComponent(RegExp["$1"]) : null;
}

//delCookie
function delCookie(name, path) {
	setCookie(name, "", -1, path);
}

//CookieRecord
var oCookieRecord = new Object();
//setCookieRecord
oCookieRecord.set = function(oParam) {
	//配置参数
	var sTitleFilter = oParam.sTitleFilter,
	// title内容后缀筛选
	sRecordListId = oParam.sRecordListId,
	//浏览记录id
	sRecordListTagName = oParam.sRecordListTagName,
	//浏览记录标签名
	nRecordListLength = oParam.nRecordListLength,
	//浏览记录限制条数
	nExpires = oParam.nExpires,
	//cookie保留天数
	sCookiePath = oParam.sCookiePath,
	//限制cookie访问路径
	sDomain = oParam.sDomain,
	//限制cookie域
	bSecure = oParam.bSecure; //限制cookie是否为安全网站访问
	//参数默认值设置

	if (!sCookiePath) {
		sCookiePath = "/";
	}

	//setCookie record
	var path = window.location.pathname.split("/");
	var pathN = path[path.length - 1].split(".")[0];

	//筛选带逗号的同一篇文章
	if (pathN.indexOf(",") > -1) {
		pathN = pathN.slice(0, pathN.indexOf(","));
	}
	var articleTitle = document.title;

	//title后缀筛选
	if (sTitleFilter && sTitleFilter != "") {
		var tIndex = articleTitle.indexOf(sTitleFilter);
		if (tIndex > -1) {
			var tLen = sTitleFilter.length;
			var aLen = articleTitle.length;
			articleTitle = articleTitle.slice(0, tIndex) + articleTitle.slice(tIndex + tLen, aLen);
		}
	}
	var sValue = location.href + "^_^" + articleTitle;
	setCookie(pathN, sValue, nExpires, sCookiePath, sDomain, bSecure);

	//getRecordList
	var oCookieList = decodeURIComponent(document.cookie).split(";");
	var cookieList = [];
	var oFragment = document.createDocumentFragment();

	//筛选其他地方创建的cookie
	for (var i = 0,
	len = oCookieList.length; i < len; i++) {
		if (oCookieList[i].split("=")[1].indexOf("^_^") > -1) {
			cookieList.unshift(oCookieList.slice(i, i + 1).toString());
		}
	}

	//cookie数超出删除
	var len = cookieList.length;
	if (len > nRecordListLength) {
		for (var i = len - 1; i > nRecordListLength - 1; i--) {
			delCookie(cookieList[i].split("=")[0], sCookiePath);
			cookieList.pop();
		}
	}

	// 浏览记录填充
	for (var i = 0; i < cookieList.length; i++) {
		//creat tag
		var aCookie = cookieList[i].split("=")[1].split("^_^");
		var aCookieLen = aCookie.length;
		var aLink = aCookie[0];
		var aTitle = "";

		//筛选符号^_^
		if (aCookieLen > 2) {
			for (var j = 1; j < aCookieLen; j++) {
				if (j < aCookieLen - 1) {
					aTitle += aCookie[j] + "^_^";
				} else {
					aTitle += aCookie[j];
				}
			}
		} else {
			aTitle = aCookie[1];
		}

		//
		var aListTag = document.createElement(sRecordListTagName);
		var a = document.createElement("a");
		var aText = document.createTextNode(aTitle);

		//append tag
		a.setAttribute("href", aLink);
		a.setAttribute("target", "_blank");
		a.appendChild(aText);
		aListTag.appendChild(a);
		oFragment.appendChild(aListTag);
	}
	document.getElementById(sRecordListId).innerHTML = "";
	document.getElementById(sRecordListId).appendChild(oFragment);
}

//delCookieRecord
oCookieRecord.del = function(sRecordListId) {
	if (document.cookie != "") {
		//清空cookie
		var cookieList = decodeURIComponent(document.cookie).split(";");
		for (var i = 0,
		len = cookieList.length; i < len; i++) {
			if (cookieList[i].split("=")[1].indexOf("^_^") > -1) {
				delCookie(cookieList[i].split("=")[0]);
			}
		}
	}

	//清空记录
	document.getElementById(sRecordListId).innerHTML = "";
}

html 部分==============

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>">

<html xmlns="<a href="http://www.w3.org/1999/xhtml">

http://www.w3.org/1999/xhtml</a>">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>90后美女销魂自拍扮可爱 玉体横陈遭骂xxx名</title>
<script type="text/javascript" src="cookie.js"></script>
</head>
<body>
<h2>90后美女销魂自拍扮可<a href="mailto:qs#@#$@#$">qs#@#$@#$</a>爱 玉体横陈遭骂名</h2>
<div style=" margin-bottom:20px;"><a href="test1.html">test1.html</a> | <a href="test2.html">test2.html</a> | <a href="test3.html">test3.html</a> | <a href="test4.html">test4.html</a> <a href="test3,1.html">test3,1.html</a> | <a href="test3,2.html">test3,2.html</a> | </div>
<div class="record" >
	<h3>浏览记录</h3>
	<ul id="recordList">
	</ul>
	<script type="text/javascript">
//设置浏览记录[配置参数]
oCookieRecord.set({
	sTitleFilter:"- 米拉网 - 每天都有新看点WWW.33669.COM", // title内容后缀筛选
	sRecordListId:"recordList", //浏览记录id
	sRecordListTagName:"li", //浏览记录标签名
	nRecordListLength:3, //浏览记录限制条数
	nExpires:1 //cookie保留天数
});
</script>
	<p style="cursor:pointer" onclick='oCookieRecord.del("recordList")'>清除记录</p>
</div>
</body>
</html>

===================

可多建几个html文件测试cookie记录功能

iframe自适应高度

展开/收缩

在iframe调用的子页里添加JS:

function init(){

parent.document.getElementById(“id”).height = document.body.scrollHeight;

}

document.body.addEvent(“onload”,init);

js获取页面宽和高

展开/收缩

网页可见区域宽:document.body.clientWidth;
网页可见区域高:document.body.clientHeight;
网页可见区域高:document.body.offsetWidth   (包括边线的宽);
网页可见区域高:document.body.offsetHeight (包括边线的宽);
网页正文全文宽:document.body.scrollWidth;
网页正文全文高:document.body.scrollHeight;
网页被卷去的高:document.body.scrollTop;
网页被卷去的左:document.body.scrollLeft;
网页正文部分上:window.screenTop;
网页正文部分左:window.screenLeft;
屏幕分辨率的高:window.screen.height;
屏幕分辨率的宽:window.screen.width;
屏幕可用工作区高度:window.screen.availHeight;
屏幕可用工作区宽度:window.screen.availWidth;

———————————————————–

修正:
(须在页头有DTD声明)
document.body.clientWidth ==> BODY对象宽度
document.body.clientHeight ==> BODY对象高度
document.documentElement.clientWidth ==> 可见区域宽度(HTML元素)
document.documentElement.clientHeight ==> 可见区域高度(HTML元素)

>>
后台管理 工具库 RSS 微博 简历