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 相关文章推荐
强悍无比的WEB开发好助手FireBug(Firefox Plugin)
Jan 16 Javascript
jQuery 验证插件 Web前端设计模式(asp.net)
Oct 17 Javascript
JavaScript中json对象和string对象之间相互转化
Dec 26 Javascript
原生javascript实现无间缝滚动示例
Jan 28 Javascript
js实现点击左右按钮轮播图片效果实例
Jan 29 Javascript
javascript中html字符串转化为jquery dom对象的方法
Aug 27 Javascript
json格式数据的添加,删除及排序方法
Jan 21 Javascript
Vue中定义全局变量与常量的各种方式详解
Aug 23 Javascript
vue2.0 可折叠列表 v-for循环展示的实例
Sep 07 Javascript
vue 界面刷新数据被清除 localStorage的使用详解
Sep 16 Javascript
vue中将html字符串转换成html后遇到的问题小结
Dec 10 Javascript
vue中defineProperty和Proxy的区别详解
Nov 30 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使用ob_start生成html页面的方法
2014/11/07 PHP
配置eAccelerator和XCache扩展来加速PHP程序的执行
2015/12/22 PHP
PHP手机号中间四位用星号*代替显示的实例
2017/06/02 PHP
JavaScript写的一个自定义弹出式对话框代码
2010/01/17 Javascript
用JavaScript实现类似于ListBox功能示例代码
2014/03/09 Javascript
javascript的事件触发器介绍的实现
2014/06/05 Javascript
深入学习jQuery Validate表单验证
2016/01/18 Javascript
jQuery学习笔记之回调函数
2016/08/15 Javascript
JavaScript 拖拽实例代码
2016/09/21 Javascript
JS实现数组去重复值的方法示例
2017/02/18 Javascript
原生JavaScript实现精美的淘宝轮播图效果示例【附demo源码下载】
2017/05/27 Javascript
yarn的使用与升级Node.js的方法详解
2017/06/04 Javascript
Angular.js中window.onload(),$(document).ready()的写法浅析
2017/09/28 Javascript
利用vue + element实现表格分页和前端搜索的方法
2017/12/25 Javascript
jQuery实现的点击标题文字切换字体效果示例【测试可用】
2018/04/26 jQuery
React+Webpack快速上手指南(小结)
2018/08/15 Javascript
jQuery访问json文件中数据的方法示例
2019/01/28 jQuery
使用JS实现动态时钟
2020/03/12 Javascript
Vue使用富文本编辑器Vue-Quill-Editor(含图片自定义上传服务、清除复制粘贴样式等)
2020/05/15 Javascript
vue-admin-template配置快捷导航的代码(标签导航栏)
2020/09/04 Javascript
vue 实现基础组件的自动化全局注册
2020/12/25 Vue.js
使用Python生成XML的方法实例
2017/03/21 Python
python中urllib.unquote乱码的原因与解决方法
2017/04/24 Python
Python实现爬虫抓取与读写、追加到excel文件操作示例
2018/06/27 Python
Django 表单模型选择框如何使用分组
2019/05/16 Python
购买大码女装:Lane Bryant
2016/09/07 全球购物
美国职棒大联盟官方网上商店:MLBShop.com
2017/11/12 全球购物
Myprotein法国官网:欧洲第一运动营养品牌
2019/03/26 全球购物
JSP&Servlet技术面试题
2015/05/21 面试题
化工专业大学生职业生涯规划书
2014/01/14 职场文书
《蓝色的树叶》教学反思
2014/02/24 职场文书
面试自我介绍演讲稿
2014/04/29 职场文书
和睦家庭事迹
2014/05/14 职场文书
最美家庭活动方案
2014/08/31 职场文书
Mysql 用户权限管理实现
2021/05/25 MySQL
JMeter对MySQL数据库进行压力测试的实现步骤
2022/01/22 MySQL