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%的相似度,这个时候就非常困扰,到底是重新写个,还是再对原来的组件,增加个兼容配置项?

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

    最终解决

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

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

  • 相关阅读:
    不可或缺 Windows Native (15)
    不可或缺 Windows Native (14)
    不可或缺 Windows Native (13)
    不可或缺 Windows Native (12)
    不可或缺 Windows Native (11)
    不可或缺 Windows Native (10)
    不可或缺 Windows Native (9)
    不可或缺 Windows Native (8)
    不可或缺 Windows Native (7)
    不可或缺 Windows Native (6)
  • 原文地址:https://www.cnblogs.com/zhangxiaolei521/p/5723771.html
Copyright © 2011-2022 走看看