Scroll the page on drag with jQuery

2019-01-13 13:38发布

I have tried using kinetic.js and the code below, however when I try this in IE11 it keeps jumping to the top every time I scroll:

$("html").kinetic();

I want to make the page scrollable on tablets and IE10 and 11 so that users can just push the page up to scroll down as you would on mobile devices.

How can I do this in pure-JS or jQuery without it jumping to the top?

5条回答
狗以群分
2楼-- · 2019-01-13 13:54

You can do this quite simply by recording the position of the mouse when clicked, and the current position when being dragged. Try this:

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));
}

To prevent text selection while dragging, add the following 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


Update

Here's an version of the above as a jQuery plugin, extended to allow both vertical and horizontal scrolling via the settings. It also allows you to change the cursor that's used too.

(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>

查看更多
Root(大扎)
3楼-- · 2019-01-13 13:55

Base on Rory McCrossan's idea, implemented with 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';
    }

}
查看更多
Evening l夕情丶
4楼-- · 2019-01-13 14:04

I just like to add. Using Rory's code I made horizontal scrolling.

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;
    }
});
查看更多
The star\"
5楼-- · 2019-01-13 14:09

This code will work on horizontal and vertical mouse drag scroll. It's pretty simple.

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; }); 
查看更多
smile是对你的礼貌
6楼-- · 2019-01-13 14:10

Based on the first answer, this is the code for horizontal scroll on mouse drag:

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));
}
查看更多
登录 后发表回答