原文地址:http://www.cnblogs.com/chyingp/archive/2013/06/30/front-end-tmplate-start.html

写在前面

随着前端领域的发展和社会化分工的需要,继前端攻城湿之后,又一重要岗位横空出世——重构攻城湿!所谓的重构攻城湿,他们的一大特点之一,就是精通CSS配置文件的编写。。。前端攻城湿跟重构攻城湿是一对好基友,你写逻辑来,我写样式。

好吧,本文并不是介绍重构攻城湿这个职业的,而是通过一个简单的场景来说说:

1. 在用前端模板之前,我们是肿么动态创建节点的

2. 为什么要使用前端模板

一个简单的场景

下面这张图片看着应该很眼熟吧?没错,是从mac QQ的好友列表里面截出来的。作为一名前端攻城湿,相信不少童鞋的第一反应是:需要用什么样的html结构来标识它?样式要怎么写?

好吧,就假设我们可以用下面的dom结构来标识这个“好友”,不考虑其合理性,同时,样式部分我们华丽丽地直接忽略

<div>
<img src="http://www.example.com/img/bg.png" />
<h3>小卡的测试号</h3>
<div>大家好,我是个性签名</div>
</div>

大家知道,我们的QQ好友列表是不固定的,于是必须得进行“动态创建”。我们通常会肿么做呢?

老湿说:createElement神马的是王道

老湿曾经谆谆教诲我们说,不要通过innerHTML来创建节点,因为那会让代码变得混乱不堪。好歹也拿过优秀少先队员的称号,当然得听老湿话了,于是我乖乖地写下如下代码:

var card = document.createElement('div');

var avatar = document.createElement('img');  // 头像
avatar.src = 'http://www.example.com/img/header.png';
card.appendChild(avatar); var nick = document.createElement('h3'); // 昵称
var nickTxt = document.createTextNode('小卡的测试号');
nick.appendChild(nickTxt);
card.appendChild(nick); var signature = document.createElement('div'); // 个性签名
var signatureTxt = document.createTextNode('大家好,我是个性签名');
signature.appendChild(signatureTxt);
card.appendChild(signature);

createElement的问题

筋疲力竭地敲完上面地代码,我露出了满足地微笑:老湿你坑我哪! 就这么几个破节点,让我敲这么多代码?

好吧,后来我才知道我错怪老湿了,他让我用createElement地方式来创建节点,但没说过让我人肉敲啊。人类进步的源动力之一就是懒,计算机存在的很大价值就是为了解放生产力,干嘛不换个思路,让代码来帮我们生成代码呢?代码生成代码?听着好玄乎,其实并不难,请看《【前端模板之路】二、人肉非智举,让代码帮我们写代码才是王道》

好吧,即使我们真的做到了“让代码为我们写代码”,看看上面人肉敲的那坨东西,有没有发现什么问题?

自言自语神马的最讨论了,最大的问题在于:dom结构很不直观,你压根不知道你创建出来的节点结构是神马样子的!!

换别人接手你的代码,第一件事就是得把上面的代码跑一遍,然后耐着性子打开控制台把dom结构翻一遍,才能知道你上面那坨代码究竟造了个什么鬼东西出来。好吧,那我改。。。

总结下:费体力,不直观

那些年,我们一起用过的innerHTML

毛少将说过:innerHTML是个好属性!看看换做innerHTML我们会肿么做?

var card = document.createElement('div');
card.innerHTML = '<img src="http://www.example.com/img/bg.png" />' +
'<h3>小卡的测试号</h3>' +
'<div>大家好,我是个性签名</div>';

哇!只需要几行代码就搞定了,麻麻再也不用担心我加班了!写代码,so easy!

一切似乎很美好,但是,慢着!假如我们现在要创建一批节点呢?上面把资料都写死了不通用啊!

很简单嘛,把动态变化的那几个字段提取出来不就得了,如下代码所示,瞬间高档大气上档次

function createCard(avatarURL, nick, signature){

    var card = document.createElement('div');
card.innerHTML = '<img src="'+ avatarURL +'" />' +
'<h3>'+ nick +'</h3>' +
'<div>'+ signature +'</div>';
return card;
}
createCard('http://www.example.com/img/bg.png', '小卡的测试号', '大家好,我是个性签名');

innerHTML的问题

很好,字符串相加,一堆引号,似乎看出点问题来了。上面的场景算是很简单的,动态变化的内容不过就头像、昵称、个性签名三个,但现实世界远比我们预料的要复杂得多。如果我们想把显示的好友资料再扩展以下,加上在线状态、是否会员、是否手机在线,那么,上面的代码可能变成这样(只是yy的)

function createCard(avatarURL, nick, signature, onlineState, isVIP, isMobileOnline){

    var onlineTxt = '';
switch(onlineState){
case 0:
onlineTxt = '在线';
break;
case 1:
onlineTxt = '离线';
break;
case 0:
onlineTxt = '忙碌';
break;
default:
case 0:
onlineTxt = '在线';
break;
}
var card = document.createElement('div'); // 有性能洁癖的兄弟看到下面的代码表拿砖头砸我 card.innerHTML = '<img src="'+ avatarURL +'" />' + // 头像
'<h3>'+ nick +'</h3>' + // 昵称
'<div>'+ onlineTxt +'</div>' + // 在线状态
'<div>'+ (isVIP ? '会员' : '非会员') +'</div>'; // 是否会员 if(isMobileOnline){
card.innerHTML += '<div>'+ (isMobileOnline ? '手机在线' : '') +'</div>'; // 是否手机在线
} card.innerHTML += '<div>'+ signature +'</div>'; // 个性签名
return card;
}

显然,代码开始变得有点混乱了,再加上id、class以及其他属性,相信我,绝对会很壮观。。。

缺点总结:可维护性较差(解决方案在后文会说到)

重构的童鞋说:我不想看你的代码!

上面简单对比了createElement、innerHTML创建节点的两种方式,细心的童鞋不难看出笔者的倾向性——innerHTML。

随着前端领域的发展和社会化分工的需要,继前端攻城湿之后,又一重要岗位横空出世——重构攻城湿!所谓的重构攻城湿,他们的一大特点之一,就是精通CSS配置文件的编写。。。

前端攻城湿跟重构攻城湿是一对好基友,你写逻辑来,我写样式。

>>重构的兄弟说:把你的HTML交出来!

于是,我把之前的那段代码给他,就是这货

    var card = document.createElement('div');
card.innerHTML = '<img src="'+ avatarURL +'" />' +
'<h3>'+ nick +'</h3>' +
'<div>'+ signature +'</div>';
return card;

>>重构的兄弟:。。。谁要看你的代码,我要看HTML结构!!

>>我:。。。要命有一条~~要不你把createCard 调用一下?

>>重构的兄弟怒了:想试试千年杀?!!

>>我:??!!擦,别~~你骚等~~~

于是,我简单倒腾了一下,给了它下面这东西,还是最开头的那段HTML,只不过把所有动态变化的内容,用$XX的形式代替了

<div id="my_tmpl">
<div>
<img src="${avatar}" />
<h3>${nick}</h3>
<div>${signature}</div>
</div>
</div>

重构的童鞋拿到他要的东西,心满意足的就回去写他的CSS去了,那我们呢?也很简单,原来拼字符串,现在正则换变量,如下

var data = {
avatar: 'http://www.example.com/img/bg.png',
nick: '小卡的测试号',
signature: '大家好,我是个性签名'
};
var html = document.getElementById('my_tmpl').innerHTML;
html = html.replace(/\$\{(.+?)\}/g, function(all, $1){ // 将${XX}替换成data[XX]
return data[$1];
});

这里我们已经隐约看到了前端模板的身影了,结构、样式与逻辑分离的第一步已经实现了,重构的童鞋根据约定好的HTML模板写CSS样式,前端的童鞋负责往模板里填内容、更新内容,绑定事件,处理用户交互等,这样做的好处很明显:

1. 结构、表现、逻辑分离,便于重构、前端童鞋的分工配合

2. 更好的可维护性,再也不用被一堆createElement,或破碎的字符串之间绕晕了

原来就是这货:前端模板引擎的本质

看着前面的${avatar}、${nick}等,很多童鞋应该有似曾相似之感。没错,这里用的替换标识,跟jQuery Tmpl的变量替换标识是一样的,可参考https://github.com/BorisMoore/jquery-tmpl

前端模板引擎的本质,就是变量替换而已。

看到这里,你是不是觉得:原来这货就是前端模板引擎啊,不过如此嘛!如果你有这种感觉,那么:

1. 你以为前端模板引擎有多玄乎啊,本来绕来绕去,最终就是变量替换那么回事

2. Too young,to simple,sometimes, too naive. 前端模板引擎做的事情,除了变量替换之外,还要处理逻辑判断、循环、模板嵌套、预渲染预处理等一堆东东,光有变量替换,实在不好意思说是前端模板引擎。。

好了,之前还有个问题等着解决,ctrl+f找到下面这段代码

    if(isMobileOnline){
card.innerHTML += '<div>'+ (isMobileOnline ? '手机在线' : '') +'</div>'; // 是否手机在线
}

这其实就是逻辑判断要做的事情,假设用的是jQuery Tmpl,下面这样写就可以了

<div>
{{if isMobileOnLine}}手机在线{{/if}}
</div>

jQuery Tmpl的用法,这里不打算展开,可参考:http://www.cnblogs.com/think8848/archive/2011/07/17/2108570.html

jQuery Tmpl的源码剖析,请见后续文章~~

写在后面

本文通过一个场景的场景,引出我们为什么要使用前端模板,至于前端模板的设计这里暂时不提及,留待后续文章展开。

想到哪写到哪,逻辑略凌乱,包涵~码字不易,请随手点推荐~~

(转)【前端模板之路】一、重构的兄弟说:我才不想看你的代码!把HTML给我交出来!的更多相关文章

  1. 【前端模板之路】一、重构的兄弟说:我才不想看你的代码!把HTML给我交出来!

    写在前面 随着前端领域的发展和社会化分工的需要,继前端攻城湿之后,又一重要岗位横空出世——重构攻城湿!所谓的重构攻城湿,他们的一大特点之一,就是精通CSS配置文件的编写...前端攻城湿跟重构攻城湿是一 ...

  2. Fis3的前端工程化之路[三大特性篇之内容嵌入]

    Fis3版本:v3.4.22 Fis3的三大特性 资源定位:获取任何开发中所使用资源的线上路径 内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中 依赖声明:在一个文本文 ...

  3. SS - DIY一个前端模板引擎.(一)

    前端MVVM 模式有点很多,完全摆脱了意大利面条式的代码. 个人认为,所有MVVM 的框架基础就是一个高性能的JS模板引擎,它极大简化了 DOM 操作, 使页面渲染和业务逻辑彻底分离. 为了理解模板引 ...

  4. 前端模板Juicer

    Juicer 是一个高效.轻量的前端 (Javascript) 模板引擎,使用 Juicer 可以是你的代码实现数据和视图模型的分离(MVC). 除此之外,它还可以在 Node.js 环境中运行. 用 ...

  5. DIY一个前端模板引擎.(一)

    前端MVVM 模式有点很多,完全摆脱了意大利面条式的代码.个人认为,所有MVVM 的框架基础就是一个高性能的JS模板引擎,它极大简化了 DOM 操作, 使页面渲染和业务逻辑彻底分离.为了理解模板引擎原 ...

  6. 前端模板artTemplate,handlerbars的使用心得

    写前端页面肯定离不开模板渲染,就近期项目中用的两个前端模板做一些使用总结,顺便复习一下,也方便后面温故. 1,artTemplate 优点: 1,一般web端用得较多,执行速度通常是 Mustache ...

  7. Mustache.js前端模板引擎源码解读

    mustache是一个很轻的前端模板引擎,因为之前接手的项目用了这个模板引擎,自己就也继续用了一会觉得还不错,最近项目相对没那么忙,于是就抽了点时间看了一下这个的源码.源码很少,也就只有六百多行,所以 ...

  8. JST(JavaScript Trimpath)前端模板引擎简介

    JST(JavaScript Trimpath)前端模板引擎简介及应用 今天在做某系统日志列表的时候用到了这个玩意儿.刚开始只是根据别人的例子照葫芦画瓢完成了日志列表及对应详情,晚上有空了才仔细去网上 ...

  9. 我的web前端修炼之路从此开始

    看过一篇文章,上面说过要想学习一门新技术,从什么时候开始都是不晚的.但对于一名大四的学生,只会一点简单的网页架构,只懂得HTML,CSS,JavaScript简单的一点皮毛,却怎么也说不过去.但也是这 ...

随机推荐

  1. 开发沉思录 - 记大数据平台的一次 BUG井喷

    研究REST提交重启:终于提交成功了,首先一个错误:地址IP地址的http://hdp0:8080/api/v1/clusters/HDP/requests ,被我错误写成了request,当误了大量 ...

  2. React组件性能优化总结

    性能优化的思路 影响网页性能最大的因素是浏览器的重排(repaint)和重绘(reflow). React的Virtual DOM就是尽可能地减少浏览器的重排和重绘. 从React渲染过程来看,如何防 ...

  3. JS 获取鼠标坐标

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 杂项-EMS:目录

    ylbtech-杂项-EMS:目录 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返回顶部   ...

  5. 进程句柄和进程ID的区别和关系

    进程和进程句柄和进程id含义 进程是一个正在运行的程序,进程里可以包括多个模块(DLL,OCX,等)进程句柄是程序访问时用到的东西,当前进程句柄等于主模块的句柄,当你使用OpenProcess时的进程 ...

  6. 并发模型(二)——Master-Worker模式

    Master-Worker模式是常用的并行模式之一,它的核心思想是,系统有两个进程协作工作:Master进程,负责接收和分配任务:Worker进程,负责处理子任务.当Worker进程将子任务处理完成后 ...

  7. Java微信公众平台开发(九)--关键字回复以及客服接口实现(该公众号暂时无法提供服务解决方案)

    转自:http://www.cuiyongzhi.com/post/47.html 我们在微信公众号的后台可以发现微信给我们制定了两种模式,一种是开发者模式(也就是我们一直在做的开发),还有一种模式是 ...

  8. tomcat配置多个host

    当一个tomcat需要配多个应用时,并且内网和外网的访问IP还不一样,就需要使用到tomcat配置多个虚拟主机. <Host name="localhost"  appBas ...

  9. Mongoose 参考手册(转载)

    Mongoose 是什么? 一般我们不直接用MongoDB的函数来操作MongoDB数据库 Mongose就是一套操作MongoDB数据库的接口. Schema 一种以文件形式存储的数据库模型骨架,无 ...

  10. 一个完整的用java客户端使用httpClient请求网页并返回的方法

    import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import ja ...