jQueryUI 拖动时自动滚动

Posted

技术标签:

【中文标题】jQueryUI 拖动时自动滚动【英文标题】:jQueryUI Auto Scroll on Drag 【发布时间】:2016-01-23 11:15:39 【问题描述】:

http://jsfiddle.net/ujty083a/4/

  $(document).ready(function()
        $(".left ul li").draggable(
            refreshPosition: true,
            revert: true
        );

        $(".right li").droppable(
            drop:   function(e, ui)
                alert(ui.draggable.text()+" "+$(this).text());
            
        );

    );

我有三个列表,一个可以拖动,另外两个可以拖放。正确的列表可能有也可能没有滚动条,但总会有 2 个或更多。

我发现的第一个问题是,当顶部列表有滚动条并且您尝试将项目放到第二个列表中时,会触发两个事件。一个用于隐藏列表,一个用于可见列表。

第二个问题是当其中一个列表有滚动条时,当用户将项目拖入其中时它不会自动滚动。

【问题讨论】:

【参考方案1】:

我认为您需要修改 droppable 并以这种方式大幅修改一些行为:

您需要添加一个选项来定义 droppable 是否应该是 可滚动与否。 那么您需要某种验证来确定哪个droppable 是否可见。 你需要调整一些已经存在的滚动行为 jquery ui 小部件。

这并不完美,但应该能给你一些想法:

 $.widget('ui.droppable', $.ui.droppable, 

        _over: function (e, ui) 
            var draggable = $.ui.ddmanager.current;
            if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

            // this to make sure the droppable is visible
            this.scrollVisible = this._isScrollIntoView();

            if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element)) && (!this.options.scrollable || this.scrollVisible)) 

                if (this.options.hoverClass) 
                    this.element.addClass(this.options.hoverClass);
                
                // to activate scrollable you need to change scrollParent of the draggable
                // and adjust some calculations
                if (this.options.scrollable) 
                    draggable.overflowOffset = $(this.element).scrollParent().offset();
                    draggable.scrollParent = $(this.element).scrollParent();
                    draggable.offsetParent = $(this.element).scrollParent();
                    draggable.offset.parent.top = $(this.element).scrollParent().scrollTop();
                
                this._trigger('over', event, this.ui(draggable));
            


        ,
        _out: function (event) 

            this._super();
            var draggable = $.ui.ddmanager.current;

            // remove scrollable 
            if (this.options.scrollable) 
                draggable.scrollParent = $(document);
                draggable.offsetParent = $(document);
                draggable.overflowOffset = $(document).offset();
                draggable.offset.parent.top = $(document).scrollTop();
            
        ,
        _drop: function (event, custom) 

            var draggable = custom || $.ui.ddmanager.current;
            if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element

            var childrenIntersection = false;
            this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function () 
                var inst = $.data(this, 'droppable');
                if (
                inst.options.greedy && !inst.options.disabled && inst.options.scope == draggable.options.scope && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && $.ui.intersect(draggable, $.extend(inst, 
                    offset: inst.element.offset()
                ), inst.options.tolerance)) 
                    childrenIntersection = true;
                    return false;
                
            );
            if (childrenIntersection) return false;

            // same as for over, you need to validate visibility of the element
            this.scrollVisible = this._isScrollIntoView();

            if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element)) && (!this.options.scrollable || this.scrollVisible)) 
                if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
                if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
                this._trigger('drop', event, this.ui(draggable));
                return this.element;
            

            return false;

        ,
        // a function to check visibility. Taken here:
        //http://***.com/questions/487073/check-if-element-is-visible-after-scrolling
        _isScrollIntoView() 

            var $elem = $(this.element);
            var $parent = $(this.element).scrollParent();

            var docViewTop = $parent.parent().scrollTop();
            var docViewBottom = docViewTop + $parent.parent().height();

            var elemTop = $elem.offset().top;
            var elemBottom = elemTop + $elem.height();

            return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
        
    );



    $(document).ready(function () 
        $(".left ul li").draggable(
            refreshPosition: true,
            revert: true,

        );

        $(".right .top li").droppable(
            scrollable: true,

            drop: function (e, ui) 
                alert(ui.draggable.text() + " " + $(this).text());
            
        );
        $(".right .bottom li").droppable(
            scrollable: false,

            drop: function (e, ui) 
                alert(ui.draggable.text() + " " + $(this).text());
            
        );

    );

http://jsfiddle.net/ejv32oen/4/

【讨论】:

它肯定会让我接近。感谢您的帮助。

以上是关于jQueryUI 拖动时自动滚动的主要内容,如果未能解决你的问题,请参考以下文章

如何让我的 JQueryUI 可拖动元素浮动到另一个溢出的元素中?

WPF列表框在拖动时自动滚动

拖动项目时在列表视图上创建自动滚动

JQueryUI 对话框:“自动”宽度不考虑垂直滚动条

web自动化中页面多个滚动条时的拖动操作?

向下拖动网页滚动条的时候,怎么老是自动向上滚动