JavaScript输入邮箱自动提示实例代码


Posted in Javascript onJanuary 13, 2014

本来想把之前对artTemplate源码解析的注释放上来分享下,不过隔了一年,找不到了,只好把当时分析模板引擎原理后,自己尝试

写下的模板引擎与大家分享下,留个纪念,记得当时还对比了好几个模板引擎来着。

这里所说的js的模板引擎,用的是原生的javascript语法,所以很类似php的原生模板引擎。

 

前端模板引擎的作用?

1. 可以让前端开发更简单,不需要为了生成一个dom结构而使用+运算符去拼接字符串,而只需要一个元素的(里面的html模板),或者一个变量(存储着模板),或者

一个模板文件

2. 易于维护,减少耦合,假使你的dom结构变化了,不需要更改逻辑代码,而只需要更改对应的模板(文件)

3. 可以缓存,如果你的模板是一个类似.tpl的文件,那么完全可以用浏览器去加载,并且还存下来。说到.tpl文件,可以做的不仅仅是缓存了,你还可以做到通过模块加载器

    将.tpl作为一个模块,那就可以按需加载文件,不是更省宽带,加快页面速度吗?

4. 等等等

 

前端模板引擎的原理?

原理很简单就是 对象(数据)+ 模板(含有变量) -> 字符串(html)

 

前端模板引擎的如何实现?

通过解析模板,根据词法,将模板转换成一个函数,然后通过调用该函数,并传递对象(数据),输出字符串(html)

(当然,具体的还要看代码的)

就像这样:

var tpl = 'i am <%= name%>, <%= age=> years old'; // <%=xxx>% 词法,标记为变量var obj = {
    name : 'lovesueee' ,
    age : 24
};
var fn = Engine.compile(tpl); // 编译成函数
var str = fn(obj);   // 渲染出字符串       

例子:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ice demo</title>
<script src="/javascripts/jquery/jquery-1.7.2.js"></script>
<script src="/javascripts/ice/ice.js"></script>
<body>
    <div id="content"></div>
</body>
<script type="text/html" id="tpl">
    <div>here is the render result:</div>
    <%  = this.title() ;%>
    <table border=1>
    <% for(var i=0,tl = this.trs.length,tr;i<tl;i++){  %>
        <%
            tr = this.trs[i];
            if (tr.sex === "女") {
        %>
        <tr>
        <td><%= tr.name;; %></td> <td><%= tr.age; %></td> <td><%= tr.sex || "男" %></td>
        </tr>
        <% } %>
    <% } %>
    </table>
    <img src="<%= this.href %>">
    <%= this.include('tpl2',this); %>
</script>
<script type="text/html" id="tpl2">
    <div>here is the render result:</div>
    <%  = this.print('Welcome to Ice Template') ;%>
    <table border=1>
    <% for(var i=0,tl = this.trs.length,tr;i<tl;i++){  %>
        <%
            tr = this.trs[i];
            if (tr.sex === "男") {
        %>
        <tr>
        <td><%= tr.name;; %></td> <td><%= tr.age; %></td> <td><%= tr.sex || "男" %></td>
        </tr>
        <% } %>
    <% } %>
    </table>
    <img src="<%= this.href %>">
</script>
<script>
    var trs = [
        {name:"隐形杀手",age:29,sex:"男"},
        {name:"索拉",age:22,sex:"男"},
        {name:"fesyo",age:23,sex:"女"},
        {name:"恋妖壶",age:18,sex:"男"},
        {name:"?崎",age:25,sex:"男"},
        {name:"你不懂的",age:30,sex:"女"}
    ]
    // var html = ice("tpl",{
    //     trs: trs,
    //     href: "http://images.3water.com/type4.jpg"
    // },{
    //     title: function(){
    //         return "<p>这是使用视图helper输出的代码片断</p>"
    //     }
    // });
    var elem = document.getElementById('tpl');
    var tpl = elem.innerHTML;
    var html = ice(tpl,{
        trs: trs,
        href: "http://images.3water.com/type4.jpg"
    },{
        title: function(){
            return "<p>这是使用视图helper输出的代码片断</p>"
        }
    });
    console.log(html);
    $("#content").html(html);
</script>
</html>

简单的实现:

(function (win) {
    // 模板引擎路由函数
    var ice = function (id, content) {
        return ice[
            typeof content === 'object' ? 'render' : 'compile'
        ].apply(ice, arguments);
    };

    ice.version = '1.0.0';
    // 模板配置
    var iConfig = {
        openTag  : '<%',
        closeTag : '%>'
    };

    var isNewEngine = !!String.prototype.trim;
    // 模板缓存
    var iCache = ice.cache = {};
    // 辅助函数
    var iHelper = {
        include : function (id, data) {
            return iRender(id, data);
        },
        print : function (str) {
            return str;
        }
    };
    // 原型继承
    var iExtend = Object.create || function (object) {
        function Fn () {};
        Fn.prototype = object;
        return new Fn;
    };
    // 模板编译
    var iCompile = ice.compile = function (id, tpl, options) {
        var cache = null;
        id && (cache = iCache[id]);
        if (cache) {
            return cache;
        }
        // [id | tpl]
        if (typeof tpl !== 'string') {
            var elem = document.getElementById(id);
            options = tpl;
            if (elem) {
                // [id, options]
                options = tpl;
                tpl = elem.value || elem.innerHTML;
            } else {
                //[tpl, options]
                tpl = id;
                id = null;
            }
        }
        options = options || {};
        var render  = iParse(tpl, options);
        id && (iCache[id] = render);
        return render;
    };

    // 模板渲染
    var iRender = ice.render = function (id, data, options) {
        return iCompile(id, options)(data);
    };

    var iForEach = Array.prototype.forEach ?
        function(arr, fn) {
            arr.forEach(fn)
        } :
        function(arr, fn) {
            for (var i = 0; i < arr.length; i++) {
                fn(arr[i], i, arr)
            }
        };

    // 模板解析
    var iParse = function (tpl, options) {
        var html = [];
        var js = [];
        var openTag = options.openTag || iConfig['openTag'];
        var closeTag = options.closeTag || iConfig['closeTag'];
        // 根据浏览器采取不同的拼接字符串策略
        var replaces = isNewEngine
            ?["var out='',line=1;", "out+=", ";", "out+=html[", "];", "this.result=out;"]
            : ["var out=[],line=1;",  "out.push(", ");", "out.push(html[", "]);", "this.result=out.join('');"];
        // 函数体
        var body = replaces[0];
        iForEach(tpl.split(openTag), function(val, i) {
            if (!val) {
                return;
            }
            var parts = val.split(closeTag);
            var head = parts[0];
            var foot = parts[1];
            var len = parts.length;
            // html
            if (len === 1) {
                body += replaces[3] + html.length + replaces[4];
                html.push(head);
            } else {
                if (head ) {
                    // code
                    // 去除空格
                    head = head
                        .replace(/^\s+|\s+$/g, '')
                        .replace(/[\n\r]+\s*/, '')

                    // 输出语句
                    if (head.indexOf('=') === 0) {
                        head = head.substring(1).replace(/^[\s]+|[\s;]+$/g, '');
                        body += replaces[1] + head + replaces[2];
                    } else {
                        body += head;
                    }
                    body += 'line+=1;';
                    js.push(head);
                }
                // html
                if (foot) {
                    _foot = foot.replace(/^[\n\r]+\s*/g, '');
                    if (!_foot) {
                        return;
                    }
                    body += replaces[3] + html.length + replaces[4];
                    html.push(foot);
                }
            }
        });
        body = "var Render=function(data){ice.mix(this, data);try{"
            + body
            + replaces[5]
            + "}catch(e){ice.log('rend error : ', line, 'line');ice.log('invalid statement : ', js[line-1]);throw e;}};"
            + "var proto=Render.prototype=iExtend(iHelper);"
            + "ice.mix(proto, options);"
            + "return function(data){return new Render(data).result;};";
        var render = new Function('html', 'js', 'iExtend', 'iHelper', 'options', body);
        return render(html, js, iExtend, iHelper, options);
    };
    ice.log = function () {
        if (typeof console === 'undefined') {
            return;
        }
        var args = Array.prototype.slice.call(arguments);
        console.log.apply && console.log.apply(console, args);
    };
    // 合并对象
    ice.mix = function (target, source) {
        for (var key in source) {
            if (source.hasOwnProperty(key)) {
                target[key] = source[key];
            }
        }
    };
    // 注册函数
    ice.on = function (name, fn) {
        iHelper[name] = fn;
    };
    // 清除缓存
    ice.clearCache = function () {
        iCache = {};
    };
    // 更改配置
    ice.set = function (name, value) {
        iConfig[name] = value;
    };
    // 暴露接口
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = template;
    } else {
        win.ice = ice;
    }
})(window);
Javascript 相关文章推荐
javascript break指定标签打破多层循环示例
Jan 20 Javascript
javascript计时器编写过程与实现方法
Feb 29 Javascript
关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法
May 17 Javascript
jQuery 选择器(61种)整理总结
Sep 26 Javascript
jQuery插件FusionCharts绘制的2D双面积图效果示例【附demo源码】
Apr 11 jQuery
get  post jsonp三种数据交互形式实例详解
Aug 25 Javascript
angular2 ng2 @input和@output理解及示例
Oct 10 Javascript
jQuery实现table表格信息的展开和缩小功能示例
Jul 21 jQuery
使用JS获取页面上的所有标签
Oct 18 Javascript
微信小程序webview 脚手架使用详解
Jul 22 Javascript
Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作
Aug 31 Javascript
vue+django实现下载文件的示例
Mar 24 Vue.js
js判断是否为ie的方法小结
Jan 13 #Javascript
jquery教程限制文本框只能输入数字和小数点示例分享
Jan 13 #Javascript
javascript教程之不完整的继承(js原型链)
Jan 13 #Javascript
javascript函数作用域学习示例(js作用域)
Jan 13 #Javascript
多选列表框动态添加,移动,删除,全选等操作的简单实例
Jan 13 #Javascript
鼠标经过tr时,改变tr当前背景颜色
Jan 13 #Javascript
js导航栏单击事件背景变换示例代码
Jan 13 #Javascript
You might like
php 8小时时间差的解决方法小结
2009/12/22 PHP
php操作SVN版本服务器类代码
2011/11/27 PHP
ThinkPHP中Session用法详解
2014/11/29 PHP
解决ThinkPHP关闭调试模式时报错的问题汇总
2015/04/22 PHP
是 WordPress 让 PHP 更流行了 而不是框架
2016/02/03 PHP
php实现通过soap调用.Net的WebService asmx文件
2017/02/27 PHP
php定期拉取数据对比方法实例
2019/09/22 PHP
硬盘浏览程序,保存成网页格式便可使用
2006/12/03 Javascript
JQuery的ajax基础上的超强GridView展示
2009/09/18 Javascript
Jquery之Ajax运用 学习运用篇
2011/09/26 Javascript
JavaScript字符串对象toUpperCase方法入门实例(用于把字母转换为大写)
2014/10/17 Javascript
12306验证码破解思路分享
2015/03/25 Javascript
详解Angular开发中的登陆与身份验证
2016/07/27 Javascript
AngularJS 指令的交互详解及实例代码
2016/09/14 Javascript
利用Node.JS实现邮件发送功能
2016/10/21 Javascript
微信小程序 less文件编译成wxss文件实现办法
2016/12/05 Javascript
nodejs操作mysql实现增删改查的实例
2017/05/28 NodeJs
Node.js中的cluster模块深入解读
2018/06/11 Javascript
validform表单验证的实现方法
2019/03/08 Javascript
element 中 el-menu 组件的无限极循环思路代码详解
2020/04/26 Javascript
详细解读Python中的__init__()方法
2015/05/02 Python
Python常用知识点汇总
2016/05/08 Python
快速了解Python相对导入
2018/01/12 Python
OpenCV图像颜色反转算法详解
2019/05/13 Python
python自动生成model文件过程详解
2019/11/02 Python
解决python调用自己文件函数/执行函数找不到包问题
2020/06/01 Python
pycharm中如何自定义设置通过“ctrl+滚轮”进行放大和缩小实现方法
2020/09/16 Python
社团活动策划书范文
2014/01/09 职场文书
婚前协议书怎么写
2014/04/15 职场文书
校企合作协议书
2014/04/16 职场文书
化工专业自荐书
2014/06/16 职场文书
我的中国梦演讲稿800字
2014/08/19 职场文书
爱与责任师德演讲稿
2014/08/26 职场文书
党员个人对照检查材料范文
2014/09/24 职场文书
一般纳税人申请报告
2015/05/18 职场文书
关于保护环境的建议书
2019/06/24 职场文书