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 相关文章推荐
JQuery最佳实践之精妙的自定义事件
Aug 11 Javascript
用jquery与css打造个性化的单选框和复选框
Oct 20 Javascript
jQuery拖拽插件gridster使用指南
Apr 21 Javascript
JS实现的打字机效果完整实例
Jun 20 Javascript
关于JavaScript限制字数的输入框的那些事
Aug 14 Javascript
使用jsonp实现跨域获取数据实例讲解
Dec 25 Javascript
Vue.js鼠标悬浮更换图片功能
May 17 Javascript
详解vue.js+UEditor集成 [前后端分离项目]
Jul 07 Javascript
微信小程序数据存储与取值详解
Jan 30 Javascript
Vue利用localStorage本地缓存使页面刷新验证码不清零功能的实现
Sep 04 Javascript
vue 解决mintui弹窗弹起来,底部页面滚动bug问题
Nov 12 Javascript
使用PDF.js渲染canvas实现预览pdf的效果示例
Apr 17 Javascript
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 empty()与isset()区别的详细介绍
2013/06/17 PHP
php实现指定字符串中查找子字符串的方法
2015/03/17 PHP
php抽象类用法实例分析
2015/07/07 PHP
php微信开发之关注事件
2018/06/14 PHP
javascript入门·图片对象(无刷新变换图片)\滚动图像
2007/10/01 Javascript
bgsound 背景音乐 的一些常用方法及特殊用法小结
2010/05/11 Javascript
JS返回上一页实例代码通过图片和按钮分别实现
2013/08/16 Javascript
JS 新增Cookie 取cookie值 删除cookie 举例详解
2014/10/10 Javascript
常常会用到的截取字符串substr()、substring()、slice()方法详解
2015/12/16 Javascript
jQuery数据检索中根据关键字快速定位GridView指定行的实现方法
2016/06/08 Javascript
BootStrap下拉框在firefox浏览器界面不友好的解决方案
2016/08/18 Javascript
微信小程序  自定义创建详细介绍
2016/10/27 Javascript
浅谈jquery中next与siblings的区别
2016/10/27 Javascript
基于jQuery实现滚动切换效果
2016/12/02 Javascript
react-native-tab-navigator组件的基本使用示例代码
2017/09/07 Javascript
jQuery选择器之子元素选择器详解
2017/09/18 jQuery
微信小程序App生命周期详解
2018/01/31 Javascript
JS控制GIF图片的停止与显示
2019/10/24 Javascript
js判断密码强度的方法
2020/03/18 Javascript
Vue简单实现原理详解
2020/05/07 Javascript
ssh批量登录并执行命令的python实现代码
2012/05/25 Python
使用python删除nginx缓存文件示例(python文件操作)
2014/03/26 Python
Python 列表(List) 的三种遍历方法实例 详解
2017/04/15 Python
python遍历序列enumerate函数浅析
2017/10/17 Python
利用TensorFlow训练简单的二分类神经网络模型的方法
2018/03/05 Python
Python实现的简单排列组合算法示例
2018/07/04 Python
pytorch实现seq2seq时对loss进行mask的方式
2020/02/18 Python
解决TensorFlow调用Keras库函数存在的问题
2020/07/06 Python
财务出纳员岗位职责
2013/11/26 职场文书
室内拓展活动方案
2014/02/13 职场文书
志愿者宣传口号
2014/06/17 职场文书
四风问题对照检查整改措施思想报告
2014/10/05 职场文书
酒店收银员岗位职责
2015/04/07 职场文书
2015年酒店客房部工作总结
2015/04/25 职场文书
JavaScript流程控制(分支)
2021/12/06 Javascript
CentOS7 minimal 最小化安装网络设置过程
2022/12/24 Servers