【问题标题】:Scroll the page on drag with jQuery使用 jQuery 在拖动时滚动页面
【发布时间】:2020-11-07 14:20:47
【问题描述】:

我尝试过使用 kinetic.js 和下面的代码,但是当我在 IE11 中尝试此操作时,每次滚动时它都会跳到顶部:

$("html").kinetic();

我想让页面在平板电脑和 IE10 和 11 上可滚动,这样用户只需向上推动页面即可向下滚动,就像在移动设备上一样。

如何在纯 JS 或 jQuery 中做到这一点而不跳到顶部?

【问题讨论】:

    标签: javascript jquery html css kineticjs


    【解决方案1】:

    您可以通过记录单击时鼠标的位置以及拖动时的当前位置来非常简单地做到这一点。试试这个:

    var clicked = false, clickY;
    $(document).on({
        'mousemove': function(e) {
            clicked && updateScrollPos(e);
        },
        'mousedown': function(e) {
            clicked = true;
            clickY = e.pageY;
        },
        'mouseup': function() {
            clicked = false;
            $('html').css('cursor', 'auto');
        }
    });
    
    var updateScrollPos = function(e) {
        $('html').css('cursor', 'row-resize');
        $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));
    }
    

    要防止在拖动时选择文本,请添加以下 CSS:

    body {
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }
    

    Example fiddle


    更新

    这是上面的一个 jQuery 插件版本,扩展为允许通过设置进行垂直和水平滚动。它还允许您更改也使用的cursor

    (function($) {
      $.dragScroll = function(options) {
        var settings = $.extend({
          scrollVertical: true,
          scrollHorizontal: true,
          cursor: null
        }, options);
    
        var clicked = false,
          clickY, clickX;
    
        var getCursor = function() {
          if (settings.cursor) return settings.cursor;
          if (settings.scrollVertical && settings.scrollHorizontal) return 'move';
          if (settings.scrollVertical) return 'row-resize';
          if (settings.scrollHorizontal) return 'col-resize';
        }
    
        var updateScrollPos = function(e, el) {
          $('html').css('cursor', getCursor());
          var $el = $(el);
          settings.scrollVertical && $el.scrollTop($el.scrollTop() + (clickY - e.pageY));
          settings.scrollHorizontal && $el.scrollLeft($el.scrollLeft() + (clickX - e.pageX));
        }
    
        $(document).on({
          'mousemove': function(e) {
            clicked && updateScrollPos(e, this);
          },
          'mousedown': function(e) {
            clicked = true;
            clickY = e.pageY;
            clickX = e.pageX;
          },
          'mouseup': function() {
            clicked = false;
            $('html').css('cursor', 'auto');
          }
        });
      }
    }(jQuery))
    
    $.dragScroll();
    /* Note: CSS is not relevant to the solution. 
       This is only needed for this demonstration */
    
    body,
    html {
      padding: 0;
      margin: 0;
    }
    
    div {
      height: 1000px;
      width: 2000px;
      border-bottom: 3px dashed #EEE;
      /* gradient is only to make the scroll movement more obvious */
      background: rgba(201, 2, 2, 1);
      background: -moz-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
      background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(201, 2, 2, 1)), color-stop(16%, rgba(204, 0, 204, 1)), color-stop(31%, rgba(94, 0, 201, 1)), color-stop(43%, rgba(0, 153, 199, 1)), color-stop(56%, rgba(0, 199, 119, 1)), color-stop(69%, rgba(136, 199, 0, 1)), color-stop(83%, rgba(199, 133, 0, 1)), color-stop(100%, rgba(107, 0, 0, 1)));
      background: -webkit-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
      background: -o-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
      background: -ms-linear-gradient(-125deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
      background: linear-gradient(-110deg, rgba(201, 2, 2, 1) 0%, rgba(204, 0, 204, 1) 16%, rgba(94, 0, 201, 1) 31%, rgba(0, 153, 199, 1) 43%, rgba(0, 199, 119, 1) 56%, rgba(136, 199, 0, 1) 69%, rgba(199, 133, 0, 1) 83%, rgba(107, 0, 0, 1) 100%);
      filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#c90202', endColorstr='#6b0000', GradientType=1);
      color: #EEE;
      padding: 20px;
      font-size: 2em;
    }
    
    body {
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -khtml-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div>First...</div>
    
    <div>Second...</div>

    【讨论】:

    • 滚动时如何防止选择页面上的项目?
    • 我认为应该是-moz-none;
    • -moz-none 是非标准的,所以我省略了它。
    • @ben 不要那样做 - 将大量 css 属性附加到 DOM 中的每个元素将是难以置信的慢。改用这个:jsfiddle.net/RoryMcCrossan/883RP/1
    • 我建议添加 e.preventDefault();下面的 'mousedown': function(e) { 避免鼠标移出窗口时自动滚动(另见:stackoverflow.com/questions/12938516/…
    【解决方案2】:

    我只是想补充。使用 Rory 的代码,我进行了水平滚动。

    var clicked = false, base = 0;
    
    $('#someDiv').on({
        mousemove: function(e) {
            clicked && function(xAxis) {
                var _this = $(this);
                if(base > xAxis) {
                    base = xAxis;
                    _this.css('margin-left', '-=1px');
                }
                if(base < xAxis) {
                    base = xAxis;
                    _this.css('margin-left', '+=1px');
                }
            }.call($(this), e.pageX);
        },
        mousedown: function(e) {
            clicked = true;
            base = e.pageX;
        },
        mouseup: function(e) {
            clicked = false;
            base = 0;
        }
    });
    

    【讨论】:

      【解决方案3】:

      此代码适用于水平和垂直鼠标拖动滚动。这很简单。

      var curYPos = 0,
          curXPos = 0,
          curDown = false;
      
      window.addEventListener('mousemove', function(e){ 
        if(curDown === true){
          window.scrollTo(document.body.scrollLeft + (curXPos - e.pageX), document.body.scrollTop + (curYPos - e.pageY));
        }
      });
      
      window.addEventListener('mousedown', function(e){ curDown = true; curYPos = e.pageY; curXPos = e.pageX; });
      window.addEventListener('mouseup', function(e){ curDown = false; }); 
      

      【讨论】:

        【解决方案4】:

        基于 Rory McCrossan 的想法,使用 AngularJS2 实现。

        import {Directive, ElementRef, OnDestroy, Input} from "@angular/core";
        
        declare var jQuery: any;
        
        @Directive({
            selector: '[appDragScroll]'
        })
        export class DragScrollDirective implements OnDestroy {
        
            @Input() scrollVertical: boolean = true;
            @Input() scrollHorizontal: boolean = true;
        
            private dragging = false;
            private originalMousePositionX: number;
            private originalMousePositionY: number;
            private originalScrollLeft: number;
            private originalScrollTop: number;
        
            constructor(private nodeRef: ElementRef) {
                let self = this;
        
                jQuery(document).on({
                    "mousemove": function (e) {
                        self.dragging && self.updateScrollPos(e);
                    },
                    "mousedown": function (e) {
                        self.originalMousePositionX = e.pageX;
                        self.originalMousePositionY = e.pageY;
                        self.originalScrollLeft = jQuery(self.nodeRef.nativeElement).scrollLeft();
                        self.originalScrollTop = jQuery(self.nodeRef.nativeElement).scrollTop();
                        self.dragging = true;
                    },
                    "mouseup": function (e) {
                        jQuery('html').css('cursor', 'auto');
                        self.dragging = false;
                    }
                });
        
            }
        
            ngOnDestroy(): void {
                jQuery(document).off("mousemove");
                jQuery(document).off("mousedown");
                jQuery(document).off("mouseup");
            }
        
            private updateScrollPos(e) {
                jQuery('html').css('cursor', this.getCursor());
        
                let $el = jQuery(this.nodeRef.nativeElement);
                if (this.scrollHorizontal) {
                    $el.scrollLeft(this.originalScrollLeft + (this.originalMousePositionX - e.pageX));
                }
                if (this.scrollVertical) {
                    $el.scrollTop(this.originalScrollTop + (this.originalMousePositionY - e.pageY));
                }
            }
        
            private getCursor() {
                if (this.scrollVertical && this.scrollHorizontal) return 'move';
                if (this.scrollVertical) return 'row-resize';
                if (this.scrollHorizontal) return 'col-resize';
            }
        
        }
        

        【讨论】:

          【解决方案5】:

          基于第一个答案,这是鼠标拖动时水平滚动的代码:

          var clicked = false, clickX;
          $(document).on({
              'mousemove': function(e) {
                  clicked && updateScrollPos(e);
              },
              'mousedown': function(e) {
                  e.preventDefault();        
                  clicked = true;
                  clickX = e.pageX;
              },
              'mouseup': function() {
                  clicked = false;
                  $('html').css('cursor', 'auto');
              }
          });
          
          var updateScrollPos = function(e) {
              $('html').css('cursor', 'grabbing');
              $(window).scrollLeft($(window).scrollLeft() + (clickX - e.pageX));
          }
          

          【讨论】:

            【解决方案6】:

            我对 Rory 的代码进行了相当多的修改,并让每个元素的侧向滚动工作正常。对于在 web 应用程序的单个视图中具有多个可滚动磁贴的项目,我需要它。将.drag 类添加到任何元素,可能会做一些样式,应该很好。

            // jQuery sidescroll code. Can easily be modified for vertical scrolling as well.
            // This code was hacked together so clean it up if you use it in prod.
            // Written by Josh Moore
            // Thanks to Rory McCrossan for a good starting point
            
            // How far away the mouse should move on a drag before interrupting click
            // events (your own code must also interrupt regular click events with a
            // method that calls getAllowClick())
            const THRESHOLD = 32;
            var clicked = false;
            var allowClick = true;
            
            // mouseX: most recent mouse position. updates when mouse moves.
            //     el: jQuery element that will be scrolled.
            //    thX: "threshold X", where the mouse was at the beginning of the drag
            var mouseX, startY, el, thX;
            
            // Add the .drag class to any element that should be scrollable.
            // You may need to also add these CSS rules:
            //   overflow: hidden; /* can be replaced with overflow-x or overflow-y */
            //   whitespace: none;
            function drag() {
                $('.drag').on({
                    'mousemove': e => {
                        if (el != null && clicked) {
                            el.scrollLeft(el.scrollLeft() + (mouseX - e.pageX));
                            mouseX = e.pageX;
                            allowClick = Math.abs(thX - mouseX) > THRESHOLD ? false : true;
                        }
                    },
                    'mousedown': e => {
                        clicked = true;
                        // This lets the user click child elements of the scrollable.
                        // Without it, you must click the .drag element directly to be able to scroll.
                        el = $(e.target).closest('.drag');
                        mouseX = e.pageX;
                        thX = e.pageX;
                    },
                    'mouseup': e => {
                        clicked = false;
                        el = null;
                        allowClick = true;
                    }
                });
            }
            
            function getAllowClick() {
                return allowClick;
            }
            

            同样,我没有使用垂直滚动,但添加它会非常简单(用 Y 替换 X,scrollTop() 而不是 scrollLeft() 等)。希望这对将来的人有所帮助!

            【讨论】:

              【解决方案7】:

              这个框架是用 vanilla javascript 编写的,对我来说效果最好。

              它还支持div内的滚动。

              注意:如果您创建动态内容,请在渲染后调用dragscroll.reset();

              dragscroll

              Usage

              demo

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-02-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多