zoukankan      html  css  js  c++  java
  • 怎么写好组件

    我们为什么要写组件呢?这里不细分组件、插件、控件,追究其原因无非让代码,能够复用,追求更快的开发效率。其实还有个重要的原因,项目大了之后,难以维护。这个时候就会把项目中重复的部分抽取出来,形成一个组件。但是组件也会有些’缺点’,这个最后讲。

    组件需求

    要实现如图的一个条件选择器

    有的时候,项目时间紧张,就会直接切图,通过jquery的dom选择器实现这个’简单的功能’。

    需求分析

    为了更好的维护,以及更好的复用此组件,就要做些抽象。

    • 数据层:用来决定按钮个数以及按钮是否选择

    • 表现层:按钮使用现有的ui组件

    • 逻辑层:按钮事件等逻辑处理

    数据层

    data: null,

    choseT: 0,

    choseF: 0,

    getDataStatistics: function() {

        var list = this.data;

        var choseT = 0;

        var choseF = 0;

        var len = list.length;

        for (var i = 0; i < list.length; i++) {

            if(list[i].checked == 'checked') {

                choseT++;

            }else {

                choseF++;

            }

        }

        return {

            choseT: choseT,

            choseF: choseF,

            len: len

        };

    },

    dataChangeAll: function(checked) {

        var list = this.data;

        var len = list.length;

        checked = checked || '';

        if(checked == 'checked') {

            this.choseT = len;

            this.choseF = 0;

        }else {

            this.choseT = 0;

            this.choseF = len;

        }

        for (var i = 0; i < len; i++) {

            list[i].checked = checked;

        }

    },

    dataChangeSingle: function(index, checked) {

        var list = this.data;

        var choseT = this.choseT;

        var choseF = this.choseF;

        if(checked == 'checked') {

            choseT++;

            choseF--;

        }else {

            choseT--;

            choseF++;

        }

        this.choseT = choseT;

        this.choseF = choseF;

        list[index].checked = checked;

    }

    数据层主要对原始数据做些CURD的一些操作,具体的操作看具体的业务需求,但是要具有这个意识。

    表现层

    说白了表现层也就是template层或者view层,就是用户所看到的,一般会用一个比较成熟的ui库,比如bootstrap。

    getHtml: function(list, statistic) {

        var html =

            ['<div class="sales-dialog">',

               '<div>',

                   '<div class="tag-box-chose J_view_checkNav">',

                       this.getChoseNav(statistic),

                   '</div>',

                   '<div class="mt_10 J_view_checkItems">',

                        this.getChoseItem(list),

                   '</div>',

               '</div>',

            '</div>'].join('');

        return html;

    },

    getChoseNav: function(statistic) {

        var checkAll = '';

        var checkNone = '';

        var len = statistic.len;

        if(statistic.choseT == len) {

            checkAll = 'checked';

        }

        if(statistic.choseF == len) {

            checkNone = 'checked';

        }

        return [

            '<label class="tag '+checkAll+'">',

                '<input type="radio" name="radio-grade input-fat" class="J_view_checkAll" '+checkAll+' />',

                '<span class="tag-tit">全选</span>',

            '</label>',

            '<label class="tag '+checkNone+'">',

                '<input type="radio" name="radio-grade" class="J_view_checkNone" '+checkNone+'/>',

                '<span class="tag-tit">全不选</span>',

            '</label>'

        ].join('');

    },

    getChoseItem: function(list) {

        var inputs = '';

        var doInputFunc = function(i, detail) {

            return [

                '<div style="display:inline-block;150px;">',

                    '<label data-toggle="checkbox" class="checkbox-pretty inline '+detail.checked+'">',

                        '<input type="checkbox" value="'+i+'" class="J_view_checkItem " '+detail.checked+'><span>'+detail.name+'</span>',

                    '</label>',

                '</div>',

            ].join('');

        };

        for (var i = 0; i < list.length; i++) {

            inputs += doInputFunc(i, list[i]);

        }

        return inputs;

    },

    domAction: function($el, type, data) {

        var html = '';

        type = type || 'all';

        if(type == 'item') {

            html = this.getChoseItem(data);

            $el.find('.J_view_checkItems').html(html);

        }else if(type == 'all') {

            html = this.getChoseNav(data);

            $el.find('.J_view_checkNav').html(html);

        }

    }

    众所周知,template就是根据数据渲染成html,在spa项目尤其重要。

    逻辑层

    这层主要做 调用template方法将数据渲染到页面上;将页面上的一些事件结果,映射到数据层。其实现在流行的MVVM模式,就是在逻辑层这里做了更多的事情,只是开发者们不用去关心细节处理,更专注业务的开发。

    eventBind: function($el) {

        var _this = this;

        var $target = '';

        

        // 全选

        $el.on('change', '.J_view_checkAll', function() {

            if(!$(this).parent().hasClass('checked')) {

                _this.module.dataChangeAll('checked');

                _this.view.domAction($el, 'all', _this.module.getDataStatistics());

                _this.view.domAction($el, 'item', _this.module.data);

            }

        });

        

        // 全不选

        $el.on('change', '.J_view_checkNone', function() {

            if(!$(this).parent().hasClass('checked')) {

                _this.module.dataChangeAll('');

                _this.view.domAction($el, 'all', _this.module.getDataStatistics());

                _this.view.domAction($el, 'item', _this.module.data);

            }

        });

        

        // 单个

        $el.on('click', '.J_view_checkItem', function() {

            $target = $(this);

            var index = $target.val();

            var checked = '';

            if($target.prop('checked')) {

                checked = 'checked';

            }

            _this.module.dataChangeSingle(index, checked);

            _this.view.domAction($el, 'all', _this.module.getDataStatistics());

        });

    },

    eventUnbind: function($el) {

        $el.off('change');

        $el.off('click');

    },

    完整案例

    总结

    这样子写能更好的抽象出公共部分,在其它模块就只要传入数据就可以了,不用重复拷贝代码了。

    一开始说到组件会有‘缺点’?尤其是业务组件?

    分析

    项目版本迭代是一个很正常的事情,第一版的时候,比如这个数据选择项这个组件,在每个模块都有这样的需求。但是在下一个版本的时候,产品经理在其中一个模块更改了业务需求,这就导致这个模块的数据选择项,跟其它模块的数据选择项不一样了,但是又有80%甚至90%的相似度,这个时候就非常困扰,到底是重新写个,还是再对原来的组件,增加个兼容配置项?

    重新写会有很多重复的代码。新增配置项,又必须保证之前所有的模块都要正确,得必须都验证过去。有人就会觉得直接去验证好了啊,但是项目大了之后,一个一个去验证不是解决问题的办法。

    最终解决

    在写组件的时候,业务逻辑部分,现预留配置项,以便后面业务发生改变,通过配置项来重置。尤其是觉得产品经理会更改频繁的部分。

    实在是觉得更改逻辑较大,那就重新写个吧,因为一个一个去验证之前的模块的成本还是很大的。

  • 相关阅读:
    开源.NET FTP组件edtFTPnet 用法
    C#开发的较好的FTP类
    C# 配置文件读取与修改
    对于List的All,Any,Where,FirstOrDefault,Average,Sum,Distinct,Union,AddRange,RemoveRange,InsertRange,GetRange操作
    一次性打印多个C1FlexGrid
    Word自动生成目录页码靠右对齐
    Windows Workflow学习文档
    Windows Workflow开发演练
    Boo who
    Missing letters
  • 原文地址:https://www.cnblogs.com/zhangxiaolei521/p/5723771.html
Copyright © 2011-2022 走看看