生活与工作

先说一下当前的情况:

  来到新公司也已经一个多月,今天是十月三十号,所以,算起来是整整50天(如果是百天,那么小孩子要办百天酒,情侣的这天可能也会过的开心很多)。虽然来了五十天,但是实际上感觉工作了25天左右,因为是第一个项目做完之后,因为人手比较紧张吧,没有后台来,还有需求这块也没有一个需求书,所以我是持续被闲置的状态,所以就每天看看书,小黄书(你不知道的JS)或者是读一读其他大神的博客,要么就是看看代码划划水啥的。这不前两天磊哥让我帮他做一个页面,可能是看不下去了吧哈哈哈。

生活与工作

是一个比较简单的页面 ,那么这个页面的功能和交互:

左侧复选框和右侧列表框联动,右侧列表框有拖拽功能。
基本来说就是这两个。使用Jquery和easyUI。

可能有疑问啊:没啥难的记录他干嘛?

1.是我第一次进行这种封装,对我来说确实是个挑战。

2.不实战就真的不能真正理解看的书中是什么意思。

先把代码贴出来

var Tools = {};

Tools.fieldCheck = (function () {
    // 初始化复选框数据
    var Fn = function (obj) {
        this.checkArray = [];//被选选项
        this.total = 0;// 选项总数,用于确认是否已全选
        this.initObj = obj.data;//初始化数组
        this.commitFn = obj.commit;//提交的回调函数
        this.cancelFn = obj.cancel;//取消的回调函数
        this.init();
    };
    Fn.prototype = {
        constructor: Fn,
        init: function () {
            var str = this.getDomStr(this.initObj);
            $('#checks').html(str);
            this.initRender(this.initObj);
            this.eventBind();
        },

        /**
            * @param {Array} array 数据数组用以初始化,控制禁用和勾选回显
            * @returns {null} 无返回值
            */
        initRender: function (array) {
            var _this = this;
            $.each(array, function (index, element) {
                var child = element.child;
                child.forEach(function (ele) {
                    //总数计算 用来控制
                    _this.total++;
                    if (ele.checked) {
                        $('#' + ele.id).attr('checked', 'checked');
                        var checked = ele.label + '-' + ele.fieldName + '-' + ele.id + '-' + ele.disabled;
                        _this.reRender(true, checked);
                    }
                    if (ele.disabled) {
                        $('#' + ele.id).attr('disabled', 'disabled');
                    }
                });
            });
        },

        /**
         * 功能 初始化DOM
         * @param {Array} array  复选框数据数组
         * @returns {String} str 组成复选框的HTML
         */
        getDomStr: function (array) {
            var str = '<div>';
            for (var i = 0; i < array.length; i++) {
                var p = array[i];
                str += '<div><div  class="title ">' + p.label + '</div>';
                str += '<div class="items" >';
                var child = p.child;
                for (var j = 0; j < child.length; j++) {
                    str += '<div class="item"><input type="checkBox"  data-toggle="topjui-checkbox" ';
                    //data-Info 自定义属性存储复选框信息 label、fieldName、disabled、id
                    str += 'data-info="' + child[j].label + '-' + child[j].fieldName + '-' + child[j].id + '-' + child[j].disabled + '"  id=' + child[j].id + '>';
                    str += '<label for="' + child[j].id + '">' + child[j].label + '</label></input></div>';
                }
                str += '</div></div>';
            }
            return str;
        },

        /**
                   * 事件绑定
                   * @param {function} commitFn 提交按钮回调
                   * @param {function} cancelFn 取消按钮回调
                   * @returns {null}   无返回值
                   */
        eventBind: function () {
            var _this = this;
            $('#checks').click(function (event) {
                event = event || window.event;
                if (event.target.tagName === 'INPUT') {
                    var datastr = $(event.target).attr('data-info');
                    var dataArray = datastr.split('-');
                    var dataInfo = dataArray[0] + '-' + dataArray[1] + '-' + dataArray[2] + '-' + dataArray[3];
                    //存在
                    var index = _this.checkArray.indexOf(dataInfo);
                    if (index > -1) {
                        _this.reRender(false, dataInfo);
                    } else {
                        _this.reRender(true, dataInfo);
                    }
                }
            });
            $('#checkAll').click(function (event) {
                // 判断按钮状态
                event = event || window.event;
                //被选中
                $('#checkList').html('');
                _this.checkArray = [];
                if ($('#checkAll:checked').length > 0) {
                    $.each(_this.initObj, function (index, element) {
                        var child = element.child;
                        $.each(child, function (i, ele) {
                            var checked = ele.label + '-' + ele.fieldName + '-' + ele.id + '-' + ele.disabled;
                            _this.reRender(true, checked);
                        });
                    });
                    $('#checks input:checkbox').prop('checked', true);
                } else {
                    $(':checked').prop('checked', false);
                }

            });
            //确定按钮
            $('commit').click(function (event) {
                event = event || window.event;
                _this.commitFn(event, this.handleChecked());
            });
            $('#cancel').click(function (event) {
                event = event || window.event;
                _this.cancelFn(event);
            });

            $('#checkList').click(function (event) {
                event = event || window.event;
                if (event.target.tagName === 'A') {
                    _this.reRender(false, $(event.target).attr('data-info'));
                }
            });
        },

        /**
           * @param {boolean} flag  true 为新增 false为删除
           * @param {str} info 数据字符串
           * @returns {null} 无返回值
           */
        reRender: function (flag, info) {
            var _this = this;
            var infoArray = info.split('-');
            //新增
            if (flag) {
                this.checkArray.push(info);
                var str = '<div type="text"  class="label"  id="' + infoArray[1] + '">';
                str += '<div id="' + infoArray[1] + '_drag"   >' + infoArray[0];
                if (infoArray[3] !== 'true') {
                    str += '<a href="javascript:;"  data-info="' + info + '" class="textbox-icon icon-clear clear " />';
                }
                str += '</div></div>';
                $('#checkList').append(str);
                if ($('#checkList').children().length === this.total) {
                    $('#checkAll').prop('checked', true);
                } else {
                    $('#checkAll').prop('checked', false);
                }
                // 如果全部选中则勾选全选按钮
                $('#' + infoArray[1]).draggable({
                    handle: '#' + infoArray[1] + '_drag',
                    axis: 'v',
                    proxy: function (source) {
                        var p = $('<div style="border:2px solid #ccc;width:80px"></div>');
                        p.html($(source).html()).appendTo('body');
                        return p;
                    },
                    onBeforeDrag: function (e) {
                        //点击A标签停止拖动
                        if (e.target.tagName == 'A') {
                            return false;
                        }
                        $('.label').droppable({
                            accept: '#' + infoArray[1],
                            onDrop: function (e, source) {
                                $(e.target).removeClass('ondrop');
                                // $(source).removeClass("ondrop");
                                //获取到当前降落的元素
                                // e为被降落的元素;
                                // source为降落元素
                                var id = e.target.id;
                                //清除由于拖拽产生的绝对定位样式
                                $(source).css('position', 'static');
                                $(source).css('top', 0);
                                $(source).css('left', 0);
                                $('#' + id).before(source);
                                _this.resort(source.id, id);
                            },
                            onDragEnter: function (e, source) {
                                $(e.target).addClass('ondrop');
                            },
                            onDragLeave: function (e, source) {
                                $(e.target).removeClass('ondrop');
                            },
                        });
                    },
                    onStopDrag: function (e) {
                        $('#' + infoArray[1]).css('position', 'static');
                        $('#' + infoArray[1]).css('top', 0);
                        $('#' + infoArray[1]).css('left', 0);
                    },
                });
            } else {
                this.checkArray.splice(this.checkArray.indexOf(info), 1);
                $('#' + infoArray[1]).remove();
                $('#' + infoArray[2]).prop('checked', false);
                $('#checkAll').prop('checked', false);
            }
        },


        /**
            * 功能 重排数组顺序使与HTML顺序保持一致
            * @param {any} prev 拖动元素
            * @param {any} next 被插入元素
            * @returns {null} 无返回值
            */
        resort: function (prev, next) {
            var prevIndex = -1;
            var nextIndex = -1;
            $.each(this.checkArray, function (index, ele) {
                var infoArray = ele.split('-');
                if (infoArray[1] === next) {
                    nextIndex = index;
                }
                if (infoArray[1] === prev) {
                    prevIndex = index;
                }
            });
            this.checkArray.splice(nextIndex, 0, this.checkArray[prevIndex]);
            var k = prevIndex > nextIndex ? 1 : 0;
            this.checkArray.splice(prevIndex + k, 1);
        },
        getChecked: function () {
            return this.handleChecked();
        },

        /**
         * 功能:将已选中的字符串对象转为对象
         * @returns {null} 已选对象数组
         */
        handleChecked: function () {
            var array = [];
            $.each(this.checkArray, function (index, ele) {
                var objArray = ele.split('-');
                array.push({ label: objArray[0], fieldName: objArray[1], id: objArray[2] });
            });
            return array;
        },
    };
    return Fn;
}());

并没有贴出HTML:)

下面写下我的收获吧:

1.现在面向对象思想开发,感觉也就是原子性的体现,同时也是可能也是高内聚,低耦合的一种体现。

一个组件公开和私有的是要分清楚的,比如我有些方法实际上并不是接口的,但是我还是把他放在了原型链对象上,这是不应该的,因为这是一个立即执行函数,所以函数内也是可以声名一些函数的,即

(function(){

/*可以写一些公共函数供构造函数中的函数公用,能找到是因为作用域链的原因。这样这些函数就成了封闭性的函数,而不是接口了,不过不好的应该是函数会一直在内存中存在,因为原型对象的调用会持有他//的引用,所以这些公共函数无法退出内存。,但是我这个做的并不好,因为我全都放在了原型链上,让一个对象很笨重,另外就是给使用者一种可以调用的感觉,其实是这些函数是不能调用的,擅自调用甚至会有一些问题,以后这个问题就要避免,可以问一问磊哥,感觉这样是不对的。*/

}());

2.是实现思路上的一个问题:

先说一下整体思路:传入一个data ,data中的对象会有四个属性:label fieldName id checked disabled child 六个属性  checked和disabled用来控制复选框状态 ,child是子数组,属性和父级一样,然后一个数组checkedList用来记录被勾选的选项,渲染左侧复选框时,我会把元素信息存在标签上的一个自定义属性中,这么做的原因是:因为点击了复选框,那么就需要在右侧列表添加一个或者删除一个列表元素,但是我不想再点击复选框时,再去data中遍历查询一些信息,因为data是有层级关系,遍历起来很麻烦,我实在不想再前端进行很多的循环,所以我就将所需的信息存了起来,然后再新增或者删除时,就直接拿到信息,然后查询元素信息,就可以直接进行操作了。但是有一个弊端,checkedList中的元素是一个平面一个字符串(有人就问,为啥要用字符串呢?你直接把对象序列化存进去,然后反序列化放数组里多好,反序列化会增加一个问题,就是在数组中找到一个对象,是不行的,因为数组的indexOf使用的是‘===’,而当我去验证我的checkedList中是否有这个对象时,那就还要写forEach,并且去比较属性的值,我觉得更加复杂。)会让数据看起来有些奇怪。然后就是在取数据是也会让他看起来怪怪的,就是要反序列化,我是使用分隔符 '-'进行分割的,所以就代码就看起来很麻烦。写这一段时总想还不如循环,现在想想循环可能更加的简洁,只是启动很多次循环会让我有点烦。我还是更喜欢索引,够直接。我采用这个方案的初衷就是为了提高性能。可能我觉得代码上使他看起来更麻烦。代码逻辑也复杂了不少。究竟孰优孰劣,我想这也不是一个问题,因为这个功能太小了,以至于没人会在意他,但是我还是希望能真正注意执行的效率。尽管我的处理实际上可能是更糟糕的,如果哪位大神觉得确实是这样,或者是有更好的方案,一定要给我留言,谢谢!

3.我想到另外一种实现,就在遍历时就直接创建出所有的元素 形成一个map 左侧复选框和右侧列表元素的map ,使用使用id作为属性值,对象作为属性值,另外一个map使用另外一个属性名作为属性值,这样再查询dom时更加的方便,这样就可以实现dom复用,然后要在右侧列表中添加一个属性控制是否显示,其实是是否被勾选的标记这样就从重新构建元素变成了存取元素。不知道jquery被easyUI修改后还能不能存储?还有很多疑问...

4.不知道我的上述思考会不会显得不太聪明的样子哈哈哈,请见谅。

那我就继续看书去了,拜拜!

 

上一篇:自定义单选、复选框


下一篇:用JavaScript实现全选-反选