通过原生html+css就可以写出基本的组件,比如select,很简单就可以写一个符合标准的组件

        <select name="name" class="form-control">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
            <option value="4">4</option>
        </select>

我做了很长时间java程序猿,配合jsp中的jstl,很简单的创建原生的html,再加上原生的事件,一个页面直接手工

但如果抛开后端生成html的能力,由js生成html,情况产生了微妙的变化

        <select id="name" class="form-control">
        </select>
        <script type="text/javascript">
            var data=[{
                text:1,
                value:1
            },{
                text:2,
                value:2
            },{
                text:3,
                value:3
            },{
                text:4,
                value:4
            }];
            for(var i=0;i<data.length;i++){
                $("#name").append(" <option value='"+data[i].value+"'>"+data[i].text+"</option>")
            }
        </script>

js只赋予html交互的能力,并没有对html进行增强,他对html标签的增强仅限于此,出于复用的方式,我们需要对js组件化(如果设计到select,table,html这些标签,我更愿意叫脚本化标签)

出于复用的目的,写一个简单的jquery插件

        <select id="name" class="form-control">
        </select>
        <script type="text/javascript">
            
        $("#name").combobox({
            data:data
        })
        
    //丢到    <script src="">中
    (function($){
        function creatr(jq,data){
            for(var i=0;i<data.length;i++){
               jq.append(" <option value='"+data[i].value+"'>"+data[i].text+"</option>")
            }
        }
        //只处理单个jq,多个jq需要包裹一层jq.each
        $.fn.combobox=function(options){
            creatr(options.data)
        }
    })($)
        
        </script>

这样用起来就简单多了,他现在还很脆弱,任何一个小需求都能整死他,至少他缺少事件的能力,从对象角度看标签完全具有属性,方法和事件,我们的小组件也缺乏这三样基本能力

属性能力

传递过去的参数及其展示的参数的保存位置,有很多地方可以去保存,最简单的就是直接赋值给组件,没有被复用的属性将会极大的消耗性能,至少目前都会选择使用数据存储的方式对组件的属性进行保存,而非直接赋值(对属性的处理,算是js比较特殊的地方),jquery的数据存储方式也是比较流行的方式(这有两种实现,这些实现也都是为了解决组件属性存放问题的解决方案)

        //这是一种最为粗暴的方式,原因参考数据存储
        $.fn.combobox=function(options){
            this.options=options;
        }
        
        //jquery的解决方案,需要的时候    $(this).data("options")
        $.fn.combobox=function(options){
            $(this).data("options",options);
        }

方法能力

必须至于原形之中,用于方法的共享,如果使用原形,就得注意内部使用new创建,$().combobox()后,可以直接使用方法

    (function($){

         function Combobox(options){
             //除了简单必要的属性至于this中,大多数属性还丢到其相关标签的$().data中
             this.options=options;
             this.create(options.data)
         }
        
        Combobox.prototype.getValue=function(){
                return     this.options;
        }
        
        Combobox.prototype.create(data){
            for(var i=0;i<data.length;i++){
               jq.append(" <option value='"+data[i].value+"'>"+data[i].text+"</option>")
            }
        }
        $.fn.combobox=function(options){
            //流行的无new创建组件
            return new Combobox(options);
        }
          $.fn.combobox.Constructor = Combobox
        
    })($)

当然也可以将方法直接负载构造方法上,而后提供一个统一的入口(一般就是构造方法),进行方法的调用,这种方式没有new,看似也没有原形,使用了js中一切都是对象,一切都可以赋值的特性,除了重写$.fn.combobox比较麻烦外(你会把method给干掉),完全无死角

    (function($){
        function create(jq,data){
            for(var i=0;i<data.length;i++){
               jq.append(" <option value='"+data[i].value+"'>"+data[i].text+"</option>")
            }
        }

    
        $.fn.combobox=function(options){
            if(typeof options === "string"){
                $(this).data("options",options);
                return     create(this.options)
            }
            var method=$.fn.combobox.method[options]
            method||method()
        }
        
        $.fn.combobox.method={
            getOptions:function(jq){
                return     $(this).data("options");
            }
        }
    })($)

事件能力

事件能力必须依赖于构建对象时的绑定,他是一个方法,只是绑到了原生方法中,会由系统调用,并传递参数,仅此而已(可以的话我想说,这就是实现了一个系统级的接口,你可以调用,但你无法保证参数的质量)

    (function($){
        function create(jq,data){
            for(var i=0;i<data.length;i++){
               jq.append(" <option value='"+data[i].value+"'>"+data[i].text+"</option>")
            }
        }
        
        function bind(jq,options){
            if(options.onSelect){
                options.onBeforeSelect(jq);
                jq.on("select",options.onSelect);
                options.onAfterSelect(jq);
            }
            
        }
    
        $.fn.combobox=function(options){
            if(typeof options === "string"){
                $(this).data("options",options);
                     create(this.options)
                     bind(this,options)
                     return
            }
            var method=$.fn.combobox.method[options]
            method||method()
        }
        
        $.fn.combobox.method={
            getOptions:function(jq){
                return     $(this).data("options");
            }
        }
    })($)

好了,将它们实现,我们第一个jquery组件也就诞生了,回头在看一下实现,这个组件只是对select这个html标签,脚本化,我们可以使用js动态且方便的生成原生的html标签,优势在于原生,缺点在于没有增强,需要checkbox的需求就能搞死你(我一直认为checkbox+select完全无意义,浪费cpu),再来一个select+tree,估计得疯掉一票...这个时候就不得不对这个组件进行增强,比如这里,我们在其内部可能会使用div甚至ul进行实现,而非传统的select(这正好也解释了为什么是combobox而非select)

使用增强的方式可以实现更多的酷炫功能,遗憾的是每个组件实现的思路完全不一致,这会限制组件的结构,这种结构也会反过来影响css,原生的标签很容易替换css,而增强过的标签很难更换一个皮肤,除非你很熟悉这种组件结构

可以的话,我只想将标准的标签进行脚本化(放在html上纯原生,即只做标签的交互),以方便我应付不同的UI,否则,即使组件化的封装减化了功能实现,超蛋疼的皮肤修改也会让人菊紧一整天

posted on 2015-07-05 00:15  Glimis  阅读(376)  评论(0编辑  收藏  举报