自己写的一个dragsort拖动排序插件

2026-04-29 17:56:22 234
分类:js插件

拖动排序插件Nestable很好用,但是我要把table排序怎么不行呢,我也不想改变我页面的结构,所以自己写了一个拖动排序插件,主要针对table吧。

示例效果

dragsort.gif

代码

/*
* 作者:黄飞
* 时间:2018.3.24
* 说明:对表格的拖动排序操作,兼容移动端
* 使用方法:
*     var drag = new dragsort('#table tbody tr');
*     drag.init();// 注册事件
*     drag.off(); // 注销事件
* 注:写得比较简单,只能适应于对应的环境,如有bug或设计缺陷请联系我
*/
(function ($, window) {
    "use strict";
    var dragEvents = {};    //兼容手机端
    if ('ontouchstart' in document.documentElement) {
        dragEvents = {START: 'touchstart', MOVE: 'touchmove', END: 'touchend'}
    } else {
        dragEvents = {START: 'mousedown', MOVE: 'mousemove', END: 'mouseup'}
    }
    var Dragsort = function (element, options) {
        var defaults = {
            threshold: 5,   //拖动距离
        };
        this.dragging = false;  //拖动中
        this.allEle = element;
        this.$element;          //拖动元素
        this.originalClient = {X: 0, Y: 0};    //拖动起点x
        this.originalPosition;  //拖动元素原始位置
        this.$clone;        //克隆元素
        this.settins = $.extend({}, defaults, options);
    }
    Dragsort.prototype = {
        constructor: Dragsort,
        //注册事件
        init: function () {
            var self = this;
            $(self.allEle).each(function () {
                if (self.settins.dragSelector) {
                    //拖动元素
                    $(this).on(dragEvents.START, {
                        self: self,
                        dragElement: self.settins.dragSelector
                    }, self.dragStartHandler);
                }
                else {
                    $(this).on(dragEvents.START, {self: self, dragElement: this}, self.dragStartHandler);
                }
            });

        },
        //开始拖动
        dragStartHandler: function (event) {
            document.onselectstart = function () {
                return false;
            };
            var $element = $(event.data.dragElement);
            var self = event.data.self;
            self.$element = $element;
            self.originalClient.X = event.clientX || event.originalEvent.touches[0].clientX;
            self.originalClient.Y = event.clientY || event.originalEvent.touches[0].clientY;
            self.originalPosition = self.$element.position();

            $(document).on(dragEvents.MOVE, {self: self}, self.dragMoveHandler).on(dragEvents.END, {self: self}, self.dragEndHandler);
        },
        //拖动元素
        dragMoveHandler: function (event) {
            var self = event.data.self;

            var dragDistanceX = (event.clientX || event.originalEvent.touches[0].clientX) - self.originalClient.X,
                dragDistanceY = (event.clientY || event.originalEvent.touches[0].clientY) - self.originalClient.Y;

            if (self.dragging) {
                self.$clone.css({
                    left: self.originalPosition.left + dragDistanceX,
                    top: self.originalPosition.top + dragDistanceY
                });
                self.shiftHoveredElement(self.$clone, self.$element);
            }
            else if (Math.abs(dragDistanceX) > self.settins.threshold || Math.abs(dragDistanceY) > self.settins.threshold) {
                self.$clone = self.clone(self.$element);
                self.$element.parent().append(self.$clone);
                self.$element.css({visibility: 'hidden', cursor: 'move'});
                self.dragging = true;
            }
        },
        //拖动结束
        dragEndHandler: function (event) {
            var self = event.data.self;
            self.dragging = false;
            self.$clone.remove();
            self.$element.css({visibility: 'visible', cursor: 'default'});
            $(document).off(dragEvents.MOVE).off(dragEvents.END);
        },
        //克隆元素
        clone: function () {
            var $clone = this.$element.clone();
            $clone.css({
                // display: 'table',       //常用的table
                position: 'absolute',
                width: this.$element.width(),
                height: this.$element.height(),
                top: this.originalPosition.top,
                left: this.originalPosition.left,
                'z-index': 100000,
                border: '2px solid red'
            });

            this.$element.find('td').each(function (index, item) {
                $clone.find('td').eq(index).css({width: item.clientWidth + 'px'});
            });

            return $clone;
        },
        //拖动克隆元素时悬浮在某个元素上
        shiftHoveredElement: function ($clone, $dragElement) {
            var $movableElements = $(this.allEle);
            var hoveredElement = this.getHoveredElement($clone, $dragElement, $movableElements);

            var hoveredElementIndex = $movableElements.index(hoveredElement);
            var dragElementIndex = $movableElements.index($dragElement);

            if (hoveredElementIndex < dragElementIndex) {
                $(hoveredElement).before($dragElement);
            } else {
                $(hoveredElement).after($dragElement);
            }
        },
        //获取克隆元素悬浮在某个元素上的元素
        getHoveredElement: function ($clone, $dragElement, $movableElements) {
            for (var i = 0; i < $movableElements.length; i++) {
                var $currentElement = $movableElements.eq(i);
                if ($currentElement[0] == this.$element[0]) {
                    continue;
                }
                var eleTop = $currentElement.position().top,
                    eleLeft = $currentElement.position().left,
                    eleRight = eleLeft + $currentElement.width(),
                    eleBottom = eleTop + $currentElement.height();
                var overlappingY = $clone.position().top > eleTop && $clone.position().top < eleBottom;
                if (overlappingY) {
                    return $currentElement[0];
                }
            }
        },
        //注销事件
        off: function () {
            $(this.allEle).each(function () {
                $(this).off(dragEvents.START);
            });
        }
    }
    window.dragsort = Dragsort;
})(window.jQuery, window);