Pepper: Define your web components with simple codes.

yuanoook
yuanoook 发布于 2016-04-01 15:10:24 浏览:2152 类型:原创 - 随笔 分类:JavaScript - 待整理 二维码: 作者原创 版权保护
Pepper: Define your web components with simple codes.

通过自定义标签的形式自定义组件,Scope style + 数据渲染 + 方法

https://github.com/yuanoook/Pepper/
语法示例
Pepper.defineComponent('myTitle', {
    less: 'color:red',
    template: '<h1>${title}</h1>',
    data: {
        title: '我是标题,点我点我'
    },
    main: function(){
        var this_dom = $(this).filter(':not(style)');
        this_dom.on('click',function(){
            window.alert(this_dom.text());
        });
    }
});


示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Pepper</title>
    <script src="http://cdn.rawgit.com/yuanoook/Pepper/master/jquery.min.js"></script>
    <script>less={async:true};</script><script src="http://cdn.rawgit.com/yuanoook/Pepper/master/less.js"></script>
    <script src="http://cdn.rawgit.com/yuanoook/Pepper/master/pepper.js"></script>
    <script src="http://cdn.rawgit.com/yuanoook/Pepper/master/multiline.js"></script>
<script>
$(function(){
    var count = 0;
   Pepper.defineComponent('myTitle', {
        less: 'color:red',
        template: '<h1>${title}</h1>',
        data: {
            title: '我是标题,点我点我'
        },
        main: function(){
            var this_dom = $(this).filter(':not(style)');
            this_dom.on('click',function(){
                window.alert(this_dom.text());
            });
        }
    });

    Pepper.defineComponent('Pepper',{
        less: multiline(function(){/*
            padding:10px;margin:30px;box-shadow:0 0 10px rgba(0,0,0,.3);background:url(http://cdn.rawgit.com/yuanoook/Pepper/master/pepper.jpg) center no-repeat;background-size:100%;
            .close{float:right;}
            h1{color:#555;}
            p{font-weight:bold;}
        */}),
        template: multiline(function(){/*
            <div>
                <a class="close" href="javascript:;">Remove</a>
                <h3> ${title} </h3>
                <h4>This is Pepper ${count}</h4>
            </div>
        */}),
        data: {
            title: 'Any title you like',
            count: function(){
                return ++count;
            }
        },
        main: function(){
            var _this = this;
            var this_dom = $(this).filter(':not(style)');
            $(this_dom).on('click','.close',function(){
                $(_this).remove();
            });
        }
    });

    Pepper.defineComponent('DragElement',{
        less: multiline(function(){/*
            padding:10px;margin:30px;box-shadow:0 0 10px rgba(0,0,0,.3);position:relative;background:#fff url(http://cdn.rawgit.com/yuanoook/Pepper/master/chili-pepper.jpg) center no-repeat;background-size:100%;
            user-select: none;-webkit-user-select: none;width:250px;
            &.mousedown{cursor:move;}
            a{float:right;text-shadow:0 0 10px #fff;}
        */}),
        template: multiline(function(){/*
            <div>
                <h2>Drag me please!</h2>
                <a class="close" href="javascript:;">Remove</a>
                <p>
                    Top: <span>${top}px</span> Left: <span>${left}px</span>
                </p>
            </div>
        */}),
        data: {
            top: 0,
            left: 0
        },
        main: function(){
            var start_screenX,start_screenY,drag,start_top,start_left;
            var _this = this;
            var this_dom = $(this).filter(':not(style)');

            $(this_dom).on('pepperDrag',function(event){
                var updated_data = event.position;
                Pepper.update(this_dom, updated_data);
            });

            $(this_dom).on('click','.close',function(){
                $(_this).remove();
            });

            $(this_dom).on('mousedown',function(event){
                drag = true;
                start_screenX = event.screenX;
                start_screenY = event.screenY;
                start_top = (parseInt($(this_dom).css('top')) || 0);
                start_left = (parseInt($(this_dom).css('left')) || 0);
                $(this_dom).addClass('mousedown');
            });

            $(window).on('mouseup',function(){
                drag = false;
                $(this_dom).removeClass('mousedown');
            });

            $(window).on('mousemove',function(event){
                if(drag){
                    var diff_screenX = event.screenX - start_screenX;
                    var diff_screenY = event.screenY - start_screenY;
                    var new_position = {
                        top: start_top + diff_screenY,
                        left: start_left + diff_screenX
                    };

                    $(this_dom).css(new_position);

                    $(this_dom).trigger({
                        type: 'pepperDrag',
                        position: new_position
                    });
                }
            });
        }
    });
});
</script>
</head>
<body>

<myTitle></myTitle>
<Pepper></Pepper>
<Pepper></Pepper>
<DragElement></DragElement>
<Pepper></Pepper>

</body>
</html>


核心代码
$(function(){
    window.Pepper = {
        defineComponent: defineComponent,
        update: update
    }

    function defineComponent(component_name,options){
        var opt = {};$.each(options,function(key,value){opt[key] = value;});
        opt.data = opt.data || {};

        var components = [];

        opt.component_name = component_name;
        $(component_name).each(function(){
            var tempDom = this;

            opt.component_id = randomId('pe-');

            fakeAsync_GetStyle(opt,function(css){
                var style = css ? $('<style>').html(css) : '';
                var dom = getTemplate(opt);
                $(dom).data('pepper_opt',opt);

                var component = $(style).add(dom);
                component = wrapComponent(component,opt);
                opt.main && opt.main.call(component);

                component.each(function(){
                    components.push(this);
                });

                $(tempDom).replaceWith(component);
            });
        });

        return $(components);
    }

    //like asynchronous, but really synchronous
    function fakeAsync_GetStyle(opt,callback){
        var lessStr = '#${component_id}{' + opt.less + '}';
        lessStr = strCompile(lessStr,opt);
        less.render(lessStr,function(err,res){
            err ? callback('') : callback(res.css);
        });
    }

    function getTemplate(opt){
        var template = strCompile(opt.template,opt);

        template = render(template,opt.data);

        var dom = $(template).attr('id',opt.component_id);
        return dom;
    }

    function update(this_dom, updated_data){
        var opt = $(this_dom).data('pepper_opt');

        var new_date = opt.data || {};
        $.each(updated_data,function(key,value){new_date[key]=value;});

        var old_html = $(this_dom).html();
        var new_html = render( opt.template||old_html , new_date );
        old_html !== new_html && $(this_dom).html(new_html);
    }

    function render(template, data){
        //replace ${key} with the subdata of data[key]
        template = template.replace(/\$\{([^\}]*)?\}/g,function(str,data_key,start){
            return getData(data, data_key.trim());
        });
        return template;
    }

    function getData(data, data_key){
        var res = data[data_key];
        switch( $.type(res) ){
            case 'function':
                res = res();
                break;
            case 'undefined':
            case 'NaN':
            case 'null':
                res = '';
                break;
        }
        return res;
    }

    function wrapComponent(component,opt){
        var prefix = strCompile('<!-- * Pe: ${component_name}  start -->',opt);
        var suffix = strCompile('<!--   Pe: ${component_name}  end * -->',opt);

        return $(prefix).add( component ).add(suffix);
    }

    function strCompile(str,opt){
        return (str||'').replace(/\$\{component_id\}/g,opt.component_id)
                  .replace(/\$\{component_name\}/g,opt.component_name);
    }

    function randomId(prefix){
        return (prefix||'')+( new Date().valueOf().toString(36)+Math.random().toString(36) ).split('0.').join('_').substr(0,12);
    }
});
z
给个赞 2 人点赞
收藏 0 人收藏
评论 已有 2 条评论;以下用户言论只代表其个人观点,不代表 前端网(QDFuns) 的观点或立场。
登录 以后才能发表评论
最热评论
xiayu121212
xiayu1212122016-04-01 18:24:541F
emoticon
举报 支持 (1) 回复 (0)
最新评论
老姚
老姚2016-04-01 19:43:322F
emoticon你这个库,主要是解决如何创建一个组件是吧。有点mvc的味道。数据、视图和交互分开了。如果组件之间要打交道怎么呢?观察者模式欠缺呀,emoticon可以进一步完善了。
举报 支持 (0) 回复 (0)
xiayu121212
xiayu1212122016-04-01 18:24:541F
emoticon
举报 支持 (1) 回复 (0)
yuanoook yuanoook 作者

享受平凡 | 追求卓越

作者最新