发新贴  快速回复

如何实现自定义js模板引擎支持原生语法

  蜘蛛侦探研究中
2017-11-24 22:46

看到网上的js模板引擎很羡慕啊

怎么实现  类似vuejs      <li  v-for='(i,index) in datalist'  > <a href='i.href' > {{i.item}}</a> </li> 这样的模板引擎呢?

老师能讲讲原理不,源码确实看不懂,基础太差了。

最好能不能做一个视频教程说说,我想很多人对这个很感兴趣的。

谢谢老师了

2017年2月8日

js模板引擎和那些vue、angular自带的不太一样。你上面是类似vue那种的。常规的js模板引擎和后台模板解析是类似的,有开头和结束语句。vue那种直接写在标签上就可以了,angular也是如此。他们这种更好。方便。


但是上次我问谁能读懂angular源码,或者有没有视频,都没有人回答,说明不会。


所以,老师要是不懂angular、vue源码。也是很难做到跟他们一样的,只能说大概,但是我觉得不完美。


如果说你要上面那种效果,就是只能循环,不需要跟vue一样强大,那其实不难。自己随便用个正则匹配都可以的。还有那些双向数据绑定、依赖注入,这些其实简单,我们自己用原生js写是可以写出来的,但是要把这些全部联系起来写一个angular、vue这样的框架,那就有难度了,我实力达不到。


下面是我自己写的,简单模拟v-for。肯定没有angular、vue这些强大。你可以参考参考。


我现在也希望有视频是讲解angular源码的。


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模拟v-for</title>
<style>
*{margin:0;padding:0;}
ul,ol{list-style:none;}
</style>
</head>
<body>
<ul style="border:1px solid #ccc;padding:10px;margin:10px;">
<li>这是一个ul列表</li>
<li v-for="(i,value) in json1">这是索引{{i}},这是值{{value}}。</li>
</ul>
<ol style="border:1px solid green;padding:10px;margin:10px;">
<li>这是一个ol列表</li>
<li v-for="(i,value) in json2">这是索引<span>{{i}}</span>,这是值{{value}}。</li>
</ol>
<div style="border:1px solid green;padding:10px;margin:10px;">
<h2>这是标题和内容的列表</h2>
<div v-for="(i,item) in arr">
<h3>{{item.title}}</h3>
<p>{{item.content}}</p>
</div>
</div>
</body>
<script>
//一个大的json,用来挂载数据,就跟angular的$scope一样,要的数据就添加进去
var bigData={};
//下面是往bigData挂载的数据,就是输出到页面的数据
bigData.json1={a:1,b:2,c:3,d:'4'};
bigData.json2={name:'郝先生',age:20,school:'清华北大旁边的三流大学'};
bigData.arr=[
{title:'春天的小草',content:'春天又到了,我看到了充满生机的绿色,人们都是那么的忙,这春色在他们眼里毫无意义'},
{title:'自我介绍',content:'大家好,我是一个普普通通、诚实坦白的人,热爱编程、电子竞技、斯诺克'},
{title:'头上的绿',content:'绿有很多种,而现在人们常常说的是原谅色'}
];
//以下是循环自动生成节点代码
var elems=document.querySelectorAll('[v-for]');
for(var i=0;i<elems.length;i++){
ngRepeat(elems[i],bigData);
}
function ngRepeat(elem,data){
var tem=elem;
var elemParent=tem.parentNode;
var str=tem.innerHTML;
var s1,s2,s3;
elemParent.removeChild(tem);
tem.outerHTML.replace(/v-for="\((\w+),(\w+)\)\s+in\s+(\w+)"/ig,function($0,$1,$2,$3){
s1=$1;
s2=$2;
s3=$3;
});
for(var k in data[s3]){
var clone=tem.cloneNode(true);
clone.innerHTML=str.replace(/{{([\w\.]+)}}/g,function($0,$1){
if($1==s1)return k;
if(new RegExp(s2,'ig').test($1)){
if(typeof data[s3][k]!=='object'){
return data[s3][k];
}else{
var v=$1.replace(/\w+\./g,'');
return data[s3][k][v];
}
}
});
elemParent.appendChild(clone);
}
}
</script>
</html>

 

2017-11-25 15:30  回复本帖
 
蜘蛛侦探研究中

2017年2月8日 2017-11-25 15:30发表的内容:

js模板引擎和那些vue、angular自带的不太一样。你上面是类似vue那种的。常规的js模板引擎和后台模板解析是类似的,有开头和结束语句。vue那种直接写在标签上就可以了,angular也是如此。他们这种更好。方便。


但是上次我问谁能读懂angular源码,或者有没有视频,都没有人回答,说明不会。


所以,老师要是不懂angular、vue源码。也是很难做到跟他们一样的,只能说大概,但是我觉得不完美。


如果说你要上面那种效果,就是只能循环,不需要跟vue一样强大,那其实不难。自己随便用个正则匹配都可以的。还有那些双向数据绑定、依赖注入,这些其实简单,我们自己用原生js写是可以写出来的,但是要把这些全部联系起来写一个angular、vue这样的框架,那就有难度了,我实力达不到。


下面是我自己写的,简单模拟v-for。肯定没有angular、vue这些强大。你可以参考参考。


我现在也希望有视频是讲解angular源码的。


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模拟v-for</title>
<style>
*{margin:0;padding:0;}
ul,ol{list-style:none;}
</style>
</head>
<body>
<ul style="border:1px solid #ccc;padding:10px;margin:10px;">
<li>这是一个ul列表</li>
<li v-for="(i,value) in json1">这是索引{{i}},这是值{{value}}。</li>
</ul>
<ol style="border:1px solid green;padding:10px;margin:10px;">
<li>这是一个ol列表</li>
<li v-for="(i,value) in json2">这是索引<span>{{i}}</span>,这是值{{value}}。</li>
</ol>
<div style="border:1px solid green;padding:10px;margin:10px;">
<h2>这是标题和内容的列表</h2>
<div v-for="(i,item) in arr">
<h3>{{item.title}}</h3>
<p>{{item.content}}</p>
</div>
</div>
</body>
<script>
//一个大的json,用来挂载数据,就跟angular的$scope一样,要的数据就添加进去
var bigData={};
//下面是往bigData挂载的数据,就是输出到页面的数据
bigData.json1={a:1,b:2,c:3,d:'4'};
bigData.json2={name:'郝先生',age:20,school:'清华北大旁边的三流大学'};
bigData.arr=[
{title:'春天的小草',content:'春天又到了,我看到了充满生机的绿色,人们都是那么的忙,这春色在他们眼里毫无意义'},
{title:'自我介绍',content:'大家好,我是一个普普通通、诚实坦白的人,热爱编程、电子竞技、斯诺克'},
{title:'头上的绿',content:'绿有很多种,而现在人们常常说的是原谅色'}
];
//以下是循环自动生成节点代码
var elems=document.querySelectorAll('[v-for]');
for(var i=0;i<elems.length;i++){
ngRepeat(elems[i],bigData);
}
function ngRepeat(elem,data){
var tem=elem;
var elemParent=tem.parentNode;
var str=tem.innerHTML;
var s1,s2,s3;
elemParent.removeChild(tem);
tem.outerHTML.replace(/v-for="\((\w+),(\w+)\)\s+in\s+(\w+)"/ig,function($0,$1,$2,$3){
s1=$1;
s2=$2;
s3=$3;
});
for(var k in data[s3]){
var clone=tem.cloneNode(true);
clone.innerHTML=str.replace(/{{([\w\.]+)}}/g,function($0,$1){
if($1==s1)return k;
if(new RegExp(s2,'ig').test($1)){
if(typeof data[s3][k]!=='object'){
return data[s3][k];
}else{
var v=$1.replace(/\w+\./g,'');
return data[s3][k][v];
}
}
});
elemParent.appendChild(clone);
}
}
</script>
</html>

 

谢谢,万分感谢
2017-11-25 21:55  回复本帖
 
蜘蛛侦探研究中

2017年2月8日 2017-11-25 15:30发表的内容:

js模板引擎和那些vue、angular自带的不太一样。你上面是类似vue那种的。常规的js模板引擎和后台模板解析是类似的,有开头和结束语句。vue那种直接写在标签上就可以了,angular也是如此。他们这种更好。方便。


但是上次我问谁能读懂angular源码,或者有没有视频,都没有人回答,说明不会。


所以,老师要是不懂angular、vue源码。也是很难做到跟他们一样的,只能说大概,但是我觉得不完美。


如果说你要上面那种效果,就是只能循环,不需要跟vue一样强大,那其实不难。自己随便用个正则匹配都可以的。还有那些双向数据绑定、依赖注入,这些其实简单,我们自己用原生js写是可以写出来的,但是要把这些全部联系起来写一个angular、vue这样的框架,那就有难度了,我实力达不到。


下面是我自己写的,简单模拟v-for。肯定没有angular、vue这些强大。你可以参考参考。


我现在也希望有视频是讲解angular源码的。


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模拟v-for</title>
<style>
*{margin:0;padding:0;}
ul,ol{list-style:none;}
</style>
</head>
<body>
<ul style="border:1px solid #ccc;padding:10px;margin:10px;">
<li>这是一个ul列表</li>
<li v-for="(i,value) in json1">这是索引{{i}},这是值{{value}}。</li>
</ul>
<ol style="border:1px solid green;padding:10px;margin:10px;">
<li>这是一个ol列表</li>
<li v-for="(i,value) in json2">这是索引<span>{{i}}</span>,这是值{{value}}。</li>
</ol>
<div style="border:1px solid green;padding:10px;margin:10px;">
<h2>这是标题和内容的列表</h2>
<div v-for="(i,item) in arr">
<h3>{{item.title}}</h3>
<p>{{item.content}}</p>
</div>
</div>
</body>
<script>
//一个大的json,用来挂载数据,就跟angular的$scope一样,要的数据就添加进去
var bigData={};
//下面是往bigData挂载的数据,就是输出到页面的数据
bigData.json1={a:1,b:2,c:3,d:'4'};
bigData.json2={name:'郝先生',age:20,school:'清华北大旁边的三流大学'};
bigData.arr=[
{title:'春天的小草',content:'春天又到了,我看到了充满生机的绿色,人们都是那么的忙,这春色在他们眼里毫无意义'},
{title:'自我介绍',content:'大家好,我是一个普普通通、诚实坦白的人,热爱编程、电子竞技、斯诺克'},
{title:'头上的绿',content:'绿有很多种,而现在人们常常说的是原谅色'}
];
//以下是循环自动生成节点代码
var elems=document.querySelectorAll('[v-for]');
for(var i=0;i<elems.length;i++){
ngRepeat(elems[i],bigData);
}
function ngRepeat(elem,data){
var tem=elem;
var elemParent=tem.parentNode;
var str=tem.innerHTML;
var s1,s2,s3;
elemParent.removeChild(tem);
tem.outerHTML.replace(/v-for="\((\w+),(\w+)\)\s+in\s+(\w+)"/ig,function($0,$1,$2,$3){
s1=$1;
s2=$2;
s3=$3;
});
for(var k in data[s3]){
var clone=tem.cloneNode(true);
clone.innerHTML=str.replace(/{{([\w\.]+)}}/g,function($0,$1){
if($1==s1)return k;
if(new RegExp(s2,'ig').test($1)){
if(typeof data[s3][k]!=='object'){
return data[s3][k];
}else{
var v=$1.replace(/\w+\./g,'');
return data[s3][k][v];
}
}
});
elemParent.appendChild(clone);
}
}
</script>
</html>

 

朋友你好,请问一下,如果再深入一点,实现if else 这种功能,应该怎么写呢?
2017-11-28 13:19  回复本帖
2017年2月8日

蜘蛛侦探研究中 2017-11-28 13:19发表的内容:

朋友你好,请问一下,如果再深入一点,实现if else 这种功能,应该怎么写呢?
if else用来做什么的,放在哪里,标签上还是怎么的
2017-11-28 21:10  回复本帖
 
蜘蛛侦探研究中

2017年2月8日 2017-11-28 21:10发表的内容:

if else用来做什么的,放在哪里,标签上还是怎么的
就是实现模板引擎的基本流程控制功能
比如 <li v-if="name=='miaov'" >这是一个li标签</li> 如果v-if里面的条件是true,就渲染这个li标签,否则不渲染, 当然 如果是 <if name=='miaov'> <li>这是一个li标签</li> </if> 这种形式,也是可以的。
2017-11-28 23:41  回复本帖
2017年2月8日

你写个 v-if 和 v-for 一起使用的demo我看看,就是你想渲染什么样格式的html结构。


例如:


<ul>


<li v-for="(i,v) in json">{{i}}</li>


</ul>


得到:


<ul>


<li v-for="(i,v) in json">0</li>


<li v-for="(i,v) in json">1</li>


<li v-for="(i,v) in json">2</li>


<li v-for="(i,v) in json">3</li>


</ul>


 


类似这样,你写个v-if 和 v-for 一起使用,然后你想要的效果。

2017-11-29 11:18  回复本帖
 
蜘蛛侦探研究中

2017年2月8日 2017-11-29 11:18发表的内容:

你写个 v-if 和 v-for 一起使用的demo我看看,就是你想渲染什么样格式的html结构。


例如:


<ul>


<li v-for="(i,v) in json">{{i}}</li>


</ul>


得到:


<ul>


<li v-for="(i,v) in json">0</li>


<li v-for="(i,v) in json">1</li>


<li v-for="(i,v) in json">2</li>


<li v-for="(i,v) in json">3</li>


</ul>


 


类似这样,你写个v-if 和 v-for 一起使用,然后你想要的效果。

<ul>

<li v-for="(i,v) in json">

<a>{{i}} {{v.name}} </a>

性别 :<span v-if="v.sex==1" >男</span> <!--当v.sex的值等于1时 这个span标签才显示出来 -->
<span v-if="v.sex==0" >女</span> <!--当v.sex的值等于0时 这个span标签才显示出来 -->

</li>



</ul>



json数据格式为

json:[

{name:'leo',sex:1},

{name:'mei',sex:0},

{name:'kiki',sex:0}

]


得到:



<ul>

<li> <a>0 lei </a>性别:<span>男</span> </li>

<li> <a>1 mei </a>性别:<span>女</span> </li>

<li> <a>2 kiki </a>性别 <span>女</span> </li>

</ul>
2017-11-29 14:12  回复本帖
2017年2月8日

蜘蛛侦探研究中 2017-11-29 14:12发表的内容:

<ul>

<li v-for="(i,v) in json">

<a>{{i}} {{v.name}} </a>

性别 :<span v-if="v.sex==1" >男</span> <!--当v.sex的值等于1时 这个span标签才显示出来 -->
<span v-if="v.sex==0" >女</span> <!--当v.sex的值等于0时 这个span标签才显示出来 -->

</li>



</ul>



json数据格式为

json:[

{name:'leo',sex:1},

{name:'mei',sex:0},

{name:'kiki',sex:0}

]


得到:



<ul>

<li> <a>0 lei </a>性别:<span>男</span> </li>

<li> <a>1 mei </a>性别:<span>女</span> </li>

<li> <a>2 kiki </a>性别 <span>女</span> </li>

</ul>

把之前版本的ngRepeat函数修改成下面这样就可以了。

function ngRepeat(elem,data){
	var tem=elem;
	var elemParent=tem.parentNode;
	var str=tem.innerHTML;
	var s1,s2,s3;
	elemParent.removeChild(tem);
	tem.outerHTML.replace(/v-for="\((\w+),(\w+)\)\s+in\s+(\w+)"/ig,function($0,$1,$2,$3){
		s1=$1;
		s2=$2;
		s3=$3;
	});
	for(var k in data[s3]){
		var clone=tem.cloneNode(true);
		var ifHtml=[];
		clone.innerHTML=str.replace(/{{([\w\.]+)}}|(v-if="\s*(.*)==(\w)\s*")/g,function($0,$1,$2,$3,$4){
			if($1==s1)return k;
			if(new RegExp(s2,'ig').test($1)){
				if(typeof data[s3][k]!=='object'){
					return data[s3][k];
				}else{
					var v=$1.replace(/\w+\./g,'');
					return data[s3][k][v];
				}				
			}
			if($2){				
				var v=$3.replace(/\w+\./g,'');
				if($4!=data[s3][k][v]){
					ifHtml.push(clone.querySelector('['+$2+']').outerHTML)
					return $2;
				}		
			}
		});
		for(var h=0;h<ifHtml.length;h++){
			clone.innerHTML=clone.innerHTML.replace(ifHtml[h],'');
		}
		elemParent.appendChild(clone);
	}
}

 

2017-12-01 10:07  回复本帖
 
蜘蛛侦探研究中

2017年2月8日 2017-12-01 10:07发表的内容:

把之前版本的ngRepeat函数修改成下面这样就可以了。

function ngRepeat(elem,data){
	var tem=elem;
	var elemParent=tem.parentNode;
	var str=tem.innerHTML;
	var s1,s2,s3;
	elemParent.removeChild(tem);
	tem.outerHTML.replace(/v-for="\((\w+),(\w+)\)\s+in\s+(\w+)"/ig,function($0,$1,$2,$3){
		s1=$1;
		s2=$2;
		s3=$3;
	});
	for(var k in data[s3]){
		var clone=tem.cloneNode(true);
		var ifHtml=[];
		clone.innerHTML=str.replace(/{{([\w\.]+)}}|(v-if="\s*(.*)==(\w)\s*")/g,function($0,$1,$2,$3,$4){
			if($1==s1)return k;
			if(new RegExp(s2,'ig').test($1)){
				if(typeof data[s3][k]!=='object'){
					return data[s3][k];
				}else{
					var v=$1.replace(/\w+\./g,'');
					return data[s3][k][v];
				}				
			}
			if($2){				
				var v=$3.replace(/\w+\./g,'');
				if($4!=data[s3][k][v]){
					ifHtml.push(clone.querySelector('['+$2+']').outerHTML)
					return $2;
				}		
			}
		});
		for(var h=0;h<ifHtml.length;h++){
			clone.innerHTML=clone.innerHTML.replace(ifHtml[h],'');
		}
		elemParent.appendChild(clone);
	}
}

 

谢谢朋友,帮了我大忙了,不嫌弃可以加我QQ314779559,平时多多交流
2017-12-01 16:27  回复本帖
登录 后才可以发表回复